Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 715|回复: 0

使用Spring MVC的@ControllerAdvice注解做Json的异常处理

[复制链接]
  • TA的每日心情
    奋斗
    2024-11-24 15:47
  • 签到天数: 804 天

    [LV.10]以坛为家III

    2053

    主题

    2111

    帖子

    72万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    726782
    发表于 2021-9-5 14:42:10 | 显示全部楼层 |阅读模式

    一,本文介绍Spring MVC的自定义异常处理,即在Controller中抛出自定义的异常时,客户端收到更友好的JSON格式的提示。而不是常见的报错页面。

    二,场景描述:实现公用API,验证API key的逻辑,放在拦截器中判断(等同于在Controller中)并抛出异常,用户收到类似下图的提示:

    其中,Http状态Code也能自由控制。

     

    三,解决方案:

    1,在RateLimitInterceptor.java拦截器中抛出异常:

     1 public class RateLimitInterceptor extends HandlerInterceptorAdapter{
     2  
     3     @Autowired private RedisService rs;
     4  
     5     /**
     6      * 流量控制检查入口
     7      */
     8     @Override
     9     public boolean preHandle(HttpServletRequest request,
    10             HttpServletResponse response, Object handler) throws RequiredParameterException, SignException, RateLimitException,Exception {
    11         super.preHandle(request, response, handler);
    12         String appKey = request.getParameter("appKey");
    13         //判断appKey是否为空或是否合法
    14         if(appKey == null){
    15             throw new RequiredParameterException("");
    16         }else if(AppKeyUtils.isFormatCorrect(appKey) || !rs.isExist(appKey)){
    17             
    18             throw new SignException();
    19             
    20         }else {
    21             try {
    22                 AppCall appCall = AppCall.create(appKey, AppKeyUtils.getPlanDetails(appKey));
    23                 appCall.decrease();
    24                 rs.save(appCall);
    25                 System.out.println("RateLimitInterceptor pass.");
    26             } catch (RateLimitException e) {
    27                 //抛出超限异常
    28                 throw new RateLimitException();
    29             }
    30         }
    31         return true;
    32     }
    33  
    34 }

    当代码走到(具体怎样走到,需考虑具体业务逻辑,上述代码使用AppCall类来封装,这是后话)

    1 throw new SignException();

    时,Spring将自动捕获这个异常。然后做一些处理。这是正常的流程。那么Spring如何自动不火

    2,使用Spring MVC的@ControllerAdvice,在GlobalExceptionHandler.java类中实现全局的异常处理类:

     1 @ControllerAdvice
     2 public class GlobalExceptionHandler {
     3  
     4     @ExceptionHandler(SQLException.class)
     5     @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
     6     @ResponseBody
     7     public ExceptionResponse handleSQLException(HttpServletRequest request, Exception ex) {
     8         String message = ex.getMessage();
     9         return ExceptionResponse.create(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);
    10     }
    11      
    12     @ResponseStatus(value=HttpStatus.NOT_FOUND, reason="IOException occured")
    13     @ExceptionHandler(IOException.class)
    14     @ResponseBody
    15     public void handleIOException(){
    16         //returning 404 error code
    17     }
    18     
    19     @ResponseStatus(HttpStatus.BAD_REQUEST)
    20     @ResponseBody
    21     @ExceptionHandler(SignException.class)
    22     public ExceptionResponse signException(SignException ex) {
    23         return ex.getEr();
    24     }
    25  
    26 }

    在方法的头上注解:

    1 @ExceptionHandler(SignException.class)

    即表示让Spring捕获到所有抛出的SignException异常,并交由这个被注解的方法处理。

    注解:

    1 @ResponseBody

    即表示返回的对象,Spring会自动把该对象进行json转化,最后写入到Response中。

    注解:

    1 @ResponseStatus(HttpStatus.BAD_REQUEST)

    表示设置状态码。如果应用级别的错误,此处其实永远返回200也是可以接受的,但是要在你自定义的异常串和异常码中做好交代。

    本文的方案自定义了一个ExceptionResponse.java类,如下:

     1 /**
     2  * 返回的json数据
     3  * @author craig
     4  *
     5  */
     6 public class ExceptionResponse {
     7     
     8     private String message;
     9     private Integer code;
    10     
    11     /**
    12      * Construction Method
    13      * @param code
    14      * @param message
    15      */
    16     public ExceptionResponse(Integer code, String message){
    17         this.message = message;
    18         this.code = code;
    19     }
    20     
    21     public static ExceptionResponse create(Integer code, String message){
    22         return new ExceptionResponse(code, message);
    23     }
    24     
    25     public Integer getCode() {
    26         return code;
    27     }
    28     public String getMessage() {
    29         return message;
    30     }
    31     
    32 }

    如你所知,这个类就是最后传到用户面前的一个异常类,code和message根据业务定义并让用户知晓。而自定义的SignException.java实际上起到了一个桥梁的作用。Spring把SignException对象捕获到,转成相应的ExceptionResponse对象,剩下的就是如何优雅实现的问题了。 如下是SignException.java的实现:

     1 /**
     2  * 签名异常
     3  * @author tuxiao.czz
     4  *
     5  */
     6 public class SignException extends Exception {
     7  
     8     private static final long serialVersionUID = 4714113994147018010L;
     9     private String message = "AppKey is not correct, please check.";
    10     private Integer code = 10002;
    11         
    12     private ExceptionResponse er;
    13     
    14     public SignException() {
    15         er = ExceptionResponse.create(code, message);
    16     }
    17     
    18     public ExceptionResponse getEr() {
    19         return er;
    20     }
    21     
    22 }

    所有关于这个异常的code和message都写在这个类里,个人感觉还是可以接受。当然还有另外一种实现,就是只拦截、定义一种Exception类,然后传不同的code和message进去,然后做相应的处理。这些都是比较灵活的。

    以上便是实现“自定义异常json化处理”的相关代码和说明。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-12-22 12:02 , Processed in 0.067942 second(s), 30 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表