SpringBoot中@ControllerAdvice的三种使用场景

news2024/11/23 15:10:47

一、全局异常处理

代码示例如下:

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 业务层异常枚举
 */
public enum ServiceExceptionEnum {
    SUCCESS(0, "成功"),
    ERROR(1, "失败"),
    SYS_ERROR(1000, "服务端发生异常"),
    MISSING_REQUEST_PARAM_ERROR(1001, "参数缺失"),
    INVALID_REQUEST_PARAM_ERROR(1002, "请求参数不合法");

    private final String message;

    private final int code;

    ServiceExceptionEnum(int code, String message) {
        this.code = code;
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public int getCode() {
        return code;
    }
}
import com.example.quartzdemo.enums.ServiceExceptionEnum;

import java.io.Serializable;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 统一返回结果实体类
 */
public class CommonResult<T> implements Serializable {


    /**
     * 错误码
     */
    private Integer code;
    /**
     * 错误提示
     */
    private String message;
    /**
     * 返回数据
     */
    private T data;

    /**
     * 成功
     *
     * @param data
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> success(T data) {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.setCode(ServiceExceptionEnum.SUCCESS.getCode());
        commonResult.setMessage(ServiceExceptionEnum.SUCCESS.getMessage());
        commonResult.setData(data);
        return commonResult;
    }

    /**
     * 失败
     *
     * @param message
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> error(String message) {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.setCode(ServiceExceptionEnum.ERROR.getCode());
        commonResult.setMessage(message);
        return commonResult;
    }

    /**
     * 失败
     *
     * @param message
     * @param <T>
     * @return
     */
    public static <T> CommonResult<T> error(int code, String message) {
        CommonResult<T> commonResult = new CommonResult<>();
        commonResult.setCode(code);
        commonResult.setMessage(message);
        return commonResult;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "CommonResult{" +
                "code=" + code +
                ", message='" + message + '\'' +
                ", data=" + data +
                '}';
    }
}

全局异常处理类:

import com.example.quartzdemo.common.CommonResult;
import com.example.quartzdemo.enums.ServiceExceptionEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

/**
 * @author qinxun
 * @date 2023-06-14
 * @Descripion: 全局异常处理
 */
@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    /**
     * 处理 MissingServletRequestParameterException 异常
     * <p>
     * SpringMVC 参数不正确
     */
    @ResponseBody
    @ExceptionHandler(value = MissingServletRequestParameterException.class)
    public CommonResult<String> missingServletRequestParameterExceptionHandler(HttpServletRequest req, MissingServletRequestParameterException ex) {
        log.error("[missingServletRequestParameterExceptionHandler]", ex);
        // 包装 CommonResult 结果
        return CommonResult.error(ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.MISSING_REQUEST_PARAM_ERROR.getMessage());
    }

    @ResponseBody
    @ExceptionHandler(value = ConstraintViolationException.class)
    public CommonResult<String> constraintViolationExceptionHandler(HttpServletRequest req, ConstraintViolationException ex) {
        log.error("[constraintViolationExceptionHandler]", ex);
        // 拼接错误
        StringBuilder detailMessage = new StringBuilder();
        for (ConstraintViolation<?> constraintViolation : ex.getConstraintViolations()) {
            // 使用 ; 分隔多个错误
            if (detailMessage.length() > 0) {
                detailMessage.append(";");
            }
            // 拼接内容到其中
            detailMessage.append(constraintViolation.getMessage());
        }
        // 包装 CommonResult 结果
        return CommonResult.error(
                ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
    }

    /**
     * 处理参数校验异常
     *
     * @param req
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = BindException.class)
    public CommonResult<String> bindExceptionHandler(HttpServletRequest req, BindException ex) {
        log.info("========进入了 bindException======");
        log.error("[bindExceptionHandler]", ex);
        // 拼接错误
        StringBuilder detailMessage = new StringBuilder();
        for (ObjectError objectError : ex.getAllErrors()) {
            // 使用 ; 分隔多个错误
            if (detailMessage.length() > 0) {
                detailMessage.append(";");
            }
            // 拼接内容到其中
            detailMessage.append(objectError.getDefaultMessage());
        }
        // 包装 CommonResult 结果
        return CommonResult.error(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
    }

    /**
     * 处理参数校验异常
     *
     * @param req
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public CommonResult<String> MethodArgumentNotValidExceptionHandler(HttpServletRequest req, MethodArgumentNotValidException ex) {
        log.info("-----------------进入了 MethodArgumentNotValidException-----------------");
        log.error("[MethodArgumentNotValidException]", ex);
        // 拼接错误
        StringBuilder detailMessage = new StringBuilder();
        for (ObjectError objectError : ex.getBindingResult().getAllErrors()) {
            // 使用 ; 分隔多个错误
            if (detailMessage.length() > 0) {
                detailMessage.append(";");
            }
            // 拼接内容到其中
            detailMessage.append(objectError.getDefaultMessage());
        }
        // 包装 CommonResult 结果
        return CommonResult.error(ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getCode(),
                ServiceExceptionEnum.INVALID_REQUEST_PARAM_ERROR.getMessage() + ":" + detailMessage.toString());
    }


    /**
     * 处理其它 Exception 异常
     *
     * @param req
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public CommonResult<String> exceptionHandler(HttpServletRequest req, Exception e) {
        // 记录异常日志
        log.error("[exceptionHandler]", e);
        // 返回 ERROR CommonResult
        return CommonResult.error(ServiceExceptionEnum.SYS_ERROR.getCode(),
                ServiceExceptionEnum.SYS_ERROR.getMessage());
    }
}

二、全局数据绑定

全局数据绑定可以用来做一些初始化数据的操作,我们可以将一些公共的数据定义到添加了@ControllerAdvice注解的类中,这样我们就可以在每一个Controller中可以访问这些数据。

1.定义全局数据绑定类

import java.util.HashMap;
import java.util.Map;

/**
 * @author qinxun
 * @date 2023-06-15
 * @Descripion: 全局数据绑定
 */
@ControllerAdvice
public class GlobalDataBindHandler {

    @ModelAttribute(name = "gd")
    public Map<String, Object> globalData() {
        Map<String, Object> map = new HashMap<>();
        map.put("website", "https://www.xx.com/");
        map.put("email", "xxxx@qq.com");
        return map;
    }
}

使用@ModelAttribute注解标记该方法返回的是一个全局数据。

2.我们在Controller类中使用这个全局数据

import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Map;

/**
 * @author qinxun
 * @date 2023-06-15
 * @Descripion: 全局数据绑定测试
 */
@RestController
public class HelloController {

    @GetMapping("/hello")
    public String toHello(Model model) {
        Map<String, Object> map = model.asMap();
        // 输出 {map={website=https://www.xx.com/, email=xxxx@qq.com}}
        System.out.println(map);
        return "hello";
    }
}

三、全局数据预处理

1.我们准备两个实体类

/**
 * @author qinxun
 * @date 2023-06-15
 * @Descripion: Author实体
 */
public class Author {

    private String name;

    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "Author{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
/**
 * @author qinxun
 * @date 2023-06-15
 * @Descripion: Book实体
 */
public class Book {

    private String name;

    private Integer price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getPrice() {
        return price;
    }

    public void setPrice(Integer price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

我们定义一个访问接口

import com.example.quartzdemo.bean.Author;
import com.example.quartzdemo.bean.Book;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author qinxun
 * @date 2023-06-15
 * @Descripion: 测试
 */
@RestController
public class TestController {


    /**
     * 测试
     *
     * @param book   Book对象
     * @param author Author对象
     */
    @PostMapping("/book")
    public void addBook(Book book, Author author) {
        System.out.println(book);
        System.out.println(author);
    }
}

这个时候,我们的添加操作就会有问题,因为这两个实体类中都有一个name的属性,前端传递数据的时候,无法区分是哪个实体的name属性,这种情况我们可以通过@ControllerAdvice的全局数据预处理来解决这个问题。

我们在postman上进行测试

 控制台打印返回

Book{name='书名,作者', price=20}
Author{name='书名,作者', age=20}

发现数据混乱了,这不是我们需要的结果。

如何解决?

1.给接口中的变量取别名

import com.example.quartzdemo.bean.Author;
import com.example.quartzdemo.bean.Book;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author qinxun
 * @date 2023-06-02
 * @Descripion: 测试
 */
@RestController
public class TestController {


    /**
     * 测试
     *
     * @param book   Book对象
     * @param author Author对象
     */
    @PostMapping("/book")
    public void addBook(@ModelAttribute("b") Book book, @ModelAttribute("a") Author author) {
        System.out.println(book);
        System.out.println(author);
    }
}

2.全局数据处理类

import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.HashMap;
import java.util.Map;

/**
 * @author qinxun
 * @date 2023-06-15
 * @Descripion: 全局数据处理
 */
@ControllerAdvice
public class GlobalDataBindHandler {

    // 全局数据绑定
    @ModelAttribute
    public Map<String, Object> globalData() {
        Map<String, Object> map = new HashMap<>();
        map.put("website", "https://www.xx.com/");
        map.put("email", "xxxx@qq.com");
        return map;
    }

    // 对命名为b的全局数据预处理
    @InitBinder("b")
    public void b(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("b.");
    }

    // 对命名为a的全局数据预处理
    @InitBinder("a")
    public void a(WebDataBinder binder) {
        binder.setFieldDefaultPrefix("a.");
    }
}

@InitBinder("b")表示该方法用来处理和Book相关的参数,给参数添加一个b前缀,要求参数必须有b前缀。

3.postman测试

 控制台打印返回

Book{name='书名', price=20}
Author{name='作者', age=20}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/648861.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用同步信号量和互斥信号量解决生产者和消费者问题

生产者和消费者问题 生产者和消费者问题是一个经典的进程同步问题。在这个问题中&#xff0c;生产者不断地向缓冲区中写入数据&#xff0c;而消费者则从缓冲区中读取数据。生产者进程和消费者进程对缓冲区的操作是互斥的&#xff0c;即任意时刻只能有一个进程对这个缓冲区进行…

RTU电流采集上传

RTU电流采集上传 案例说明器件 物联网平台开发代码修改三元组 测试 案例说明 本案例使用HD1&#xff08;RTU&#xff09;检测外部电流&#xff0c;并将电流上传阿里云端。 压力传感器输出电流信号&#xff0c;读取压力传感器数值时需要检测电流大小。haasHD1(RTU)有两路ADC—…

深度学习应用篇-元学习[16]:基于模型的元学习-Learning to Learn优化策略、Meta-Learner LSTM

【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化算法、卷积模型、序列模型、预训练模型、对抗神经网络等 专栏详细介绍&#xff1a;【深度学习入门到进阶】必看系列&#xff0c;含激活函数、优化策略、损失函数、模型调优、归一化…

[C语言实现]数据结构堆之《害怕二叉树所以天赋全点到堆上了》

&#x1f970;作者: FlashRider &#x1f30f;专栏: 数据结构 &#x1f356;知识概要&#xff1a;详解堆的概念、小根堆与大根堆的区别、以及代码实现。 目录 什么是堆&#xff1f; 如何实现堆&#xff1f; 代码实现堆(小根堆) 定义堆以及堆的初始化和销毁。 堆的插入 堆…

LeetCode·每日一题·1177. 构建回文串检测·前缀和

作者&#xff1a;小迅 链接&#xff1a;https://leetcode.cn/problems/can-make-palindrome-from-substring/solutions/2309940/qian-zhui-he-zhu-shi-chao-ji-xiang-xi-by-n3ps/ 来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 著作权归作者所有。商业转载请联系作者获…

最新水文水动力模型在城市内涝、城市排水、海绵城市规划设计中深度应用

随着计算机的广泛应用和各类模型软件的发展&#xff0c;将排水系统模型作为城市洪灾评价与防治的技术手段已经成为防洪防灾的重要技术途径。本次培训将聚焦于综合利用GIS及CAD等工具高效地进行大规模城市排水系统水力模型的建立&#xff0c;利用SWMM实现排水系统水力模拟。讲解…

【RH850/U2A】:GreenHills编译配置

GreenHills编译配置 GreenHills语法.gpj文件.opt文件示例GreenHills编译器在编译我们的文件时涉及它需要哪些文件及相关配置呢?带着疑问我们开始来梳理。 我们还是以具体示例来展开(硬件平台:RH850 U2A8) GreenHills语法 一般我们是需要查看它的帮助文档的,文档在哪里呢?…

CSP第二轮/NOIP 比赛注意事项

一、在哪里写代码 主办方会提前在桌面已在 E 盘根目录下建立以考生准考证编号命名的文件夹,考生应检查该文件夹名称是否正确(包括编号及大小写字母),如有错误须立即上报监考人员,由监考人员进行更改。确认无误后,考生须为每道试题再单独建立一个子文件夹,子文件夹名与对应…

某互联网银行绿色金融背后的“安全秘诀”

​随着银保监会出台《银行业保险业绿色金融指引》、人民银行牵头制定《G20转型金融框架》的发布&#xff0c;金融行业正在持续加大对绿色金融支持力度。某互联网银行为了响应号召&#xff0c;采用数字化无纸化办公&#xff0c;线上零接触服务减少大量碳排放&#xff0c;成为国内…

oracle rac架构解读

一、oracle 数据库架构 单节点数据库&#xff0c;如果实例宕机了&#xff0c;如果一个业务链接在实例上面&#xff0c;那么这个业务就中断了。这个时候系统就不具有可用性了&#xff0c;那么这个时候单节点的可用性是很差的。 对于RAC来说&#xff0c;和单实例一样&#xff0c;…

新榜 | 小红书美妆用户趋势洞察报告

目前&#xff0c;小红书上聚集了大量年轻、高知的女性美妆用户&#xff0c;她们倾向于在小红书平台分享美妆护肤产品和使用经验&#xff0c;用户间的互动、分享氛围浓厚&#xff1b;而这些评论互动也传递了用户的真实诉求&#xff0c;理解用户的关注点对于企业和品牌来说将具有…

Vue中如何进行数据导入与Excel导入

Vue中如何进行数据导入与Excel导入 Vue是一款非常流行的JavaScript框架&#xff0c;它提供了一套用于构建用户界面的工具和库。在Vue中&#xff0c;我们可以使用多种方式来导入数据&#xff0c;包括从服务器获取数据、从本地存储获取数据、从文件中读取数据等等。其中&#xf…

如何提高职场沟通能力

如何提高职场沟通能力 在现代职场中&#xff0c;良好的沟通能力不仅有助于我们更好地完成工作任务&#xff0c;还能提高团队协作效率&#xff0c;降低矛盾和误解。本文将为你提供一些建议和技巧&#xff0c;帮助你提高职场沟通能力。 1. 倾听 倾听是沟通中最重要的技能之一…

社招准备和面试题

这次就整理下这次社招都做了哪些准备以及自己面试过的题目。 首先就是专业知识的准备&#xff0c;看了很多常用的机器学习算法&#xff0c;并对其算法做了推导。看了深度学习推荐系统这本书里面的模型&#xff0c;对自己简历中涉及到的模型重点掌握&#xff0c;比如DIN、DIEN、…

创客匠人6月功能更新:服务商管理、直播、学员版APP全新上线

创客匠人6月功能更新&#xff0c;包括服务商管理、直播、学员版APP、圈子、商城、店铺等众多产品升级&#xff0c;我们一起来看看吧。 正式升级时间&#xff1a;6月20日 一、服务商管理 1.服务商模块排版优化&#xff1a;支持查看整个团队的用户信息和业绩明细。 2.支持记…

嵌套滚动实践:onInterceptTouchEvent与NestedScrolling【实用为准】

嵌套滚动&#xff1a;内外两层均可滚动&#xff0c;比如上半部分是一个有限的列表&#xff0c;下半部分是WebView&#xff0c;在内层上半部分展示到底的时候&#xff0c;外部父布局整体滚动内部View&#xff0c;将底部WevView拉起来&#xff0c;滚动到顶部之后再将滚动交给内部…

SQL Server 无备份情况下误操作数据恢复(3)

原文链接&#xff1a;https://blog.csdn.net/dba_huangzj/article/details/8491327 问题&#xff1a; 经常看到有人误删数据&#xff0c;或者误操作&#xff0c;特别是update和delete的时候没有加where&#xff0c;然后就喊爹喊娘了。人非圣贤孰能无过&#xff0c;做错可以理解…

Verilog 高级知识点---状态机

目录 状态机 1、Mealy 状态机 2、Moore 状态机 3、三段式状态机 状态机 Verilog 是硬件描述语言&#xff0c;硬件电路是并行执行的&#xff0c;当需要按照流程或者步骤来完成某个功能时&#xff0c;代码中通常会使用很多个 if 嵌套语句来实现&#xff0c;这样就增加了代码…

2DUI跟踪3D模型,更精准的嵌套与跟踪

实现的效果&#xff1a; 1、2DUI跟踪模型指定位置&#xff0c;跟随模型移动 2、2DUI时刻面向摄像机 首先准备一个模型。如下图&#xff1a; 在此模型层级下新建Canvas&#xff08;画布&#xff09; 改显示模式为世界空间 在canvas下创建Image&#xff08;图像&#xff09; 放…

包看包会Stable Diffusion原理,新手也能看明白

知道看文章的人怎么看&#xff0c;听我讲的人经常反应的就是听不明白。于是我又在网上找了一下&#xff0c;发现这篇文章讲的很好&#xff0c;算得上是深入浅出&#xff0c;可惜是英文的&#xff0c;就把它翻译了一下&#xff1a; https://stable-diffusion-art.com/how-stabl…