您的位置:首页 > 编程语言 > Java开发

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

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

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

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

三,解决方案:

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

[java] view
plain copy

public class RateLimitInterceptor extends HandlerInterceptorAdapter{  

  

    @Autowired private RedisService rs;  

  

    /** 

     * 流量控制检查入口 

     */  

    @Override  

    public boolean preHandle(HttpServletRequest request,  

            HttpServletResponse response, Object handler) throws RequiredParameterException, SignException, RateLimitException,Exception {  

        super.preHandle(request, response, handler);  

        String appKey = request.getParameter("appKey");  

        //判断appKey是否为空或是否合法  

        if(appKey == null){  

            throw new RequiredParameterException("");  

        }else if(AppKeyUtils.isFormatCorrect(appKey) || !rs.isExist(appKey)){  

              

            throw new SignException();  

              

        }else {  

            try {  

                AppCall appCall = AppCall.create(appKey, AppKeyUtils.getPlanDetails(appKey));  

                appCall.decrease();  

                rs.save(appCall);  

                System.out.println("RateLimitInterceptor pass.");  

            } catch (RateLimitException e) {  

                //抛出超限异常  

                throw new RateLimitException();  

            }  

        }  

        return true;  

    }  

  

}  

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

[java] view
plain copy

throw new SignException();  

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

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

[java] view
plain copy

@ControllerAdvice  

public class GlobalExceptionHandler {  

  

    @ExceptionHandler(SQLException.class)  

    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)  

    @ResponseBody  

    public ExceptionResponse handleSQLException(HttpServletRequest request, Exception ex) {  

        String message = ex.getMessage();  

        return ExceptionResponse.create(HttpStatus.INTERNAL_SERVER_ERROR.value(), message);  

    }  

       

    @ResponseStatus(value=HttpStatus.NOT_FOUND, reason="IOException occured")  

    @ExceptionHandler(IOException.class)  

    @ResponseBody  

    public void handleIOException(){  

        //returning 404 error code  

    }  

      

    @ResponseStatus(HttpStatus.BAD_REQUEST)  

    @ResponseBody  

    @ExceptionHandler(SignException.class)  

    public ExceptionResponse signException(SignException ex) {  

        return ex.getEr();  

    }  

  

}  

在方法的头上注解:

[java] view
plain copy

@ExceptionHandler(SignException.class)  

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

注解:

[java] view
plain copy

@ResponseBody  

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

注解:

[java] view
plain copy

@ResponseStatus(HttpStatus.BAD_REQUEST)  

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

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

[java] view
plain copy

/** 

 * 返回的json数据 

 * @author craig 

 * 

 */  

public class ExceptionResponse {  

      

    private String message;  

    private Integer code;  

      

    /** 

     * Construction Method 

     * @param code 

     * @param message 

     */  

    public ExceptionResponse(Integer code, String message){  

        this.message = message;  

        this.code = code;  

    }  

      

    public static ExceptionResponse create(Integer code, String message){  

        return new ExceptionResponse(code, message);  

    }  

      

    public Integer getCode() {  

        return code;  

    }  

    public String getMessage() {  

        return message;  

    }  

      

}  

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

[java] view
plain copy

/** 

 * 签名异常 

 * @author tuxiao.czz 

 * 

 */  

public class SignException extends Exception {  

  

    private static final long serialVersionUID = 4714113994147018010L;  

    private String message = "AppKey is not correct, please check.";  

    private Integer code = 10002;  

          

    private ExceptionResponse er;  

      

    public SignException() {  

        er = ExceptionResponse.create(code, message);  

    }  

      

    public ExceptionResponse getEr() {  

        return er;  

    }  

      

}  

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

以上便是实现“自定义异常json化处理”的相关代码和说明。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: