您的位置 首页 >  博文

Spring使用@ControllerAdvice注解优雅地处理异常信息

@ControllerAdvice,是Spring3.2+提供的新注解,它是一个Controller增强器,可对Controller中被 @RequestMapping注解的方法加一些逻辑处理。最常用的就是异常处理。

统一异常处理

需要配合@ExceptionHandler使用。当将异常抛到Controller时,可以对异常进行统一处理,规定返回的json格式或是跳转到一个错误页面。

全局异常捕捉处理

  1package cn.itechyou.cms.exception;
 2
 3import org.apache.shiro.authz.UnauthorizedException;
 4import org.slf4j.Logger;
 5import org.slf4j.LoggerFactory;
 6import org.springframework.http.HttpStatus;
 7import org.springframework.http.converter.HttpMessageNotReadableException;
 8import org.springframework.web.HttpMediaTypeNotSupportedException;
 9import org.springframework.web.HttpRequestMethodNotSupportedException;
10import org.springframework.web.bind.annotation.ControllerAdvice;
11import org.springframework.web.bind.annotation.ExceptionHandler;
12import org.springframework.web.bind.annotation.ResponseStatus;
13import org.springframework.web.servlet.ModelAndView;
14import org.springframework.web.servlet.NoHandlerFoundException;
15
16import cn.itechyou.cms.common.ExceptionEnum;
17
18/**
19 * 全局异常处理
20 * 
21 * @author Wangjunnan
22 * 
23 */

24@ControllerAdvice
25public class GlobalExceptionHandler {
26
27    private Logger logger = LoggerFactory.getLogger(this.getClass());
28
29    /**
30     * 400 - 错误的请求
31     */

32    @ResponseStatus(HttpStatus.BAD_REQUEST)
33    @ExceptionHandler(HttpMessageNotReadableException.class)
34    public ModelAndView handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
35        logger.error("错误的请求", e);
36        ModelAndView mv = new ModelAndView();
37        mv.setViewName("error/400");
38        mv.addObject("code", ExceptionEnum.HTTP_BAD_REQUEST.getCode());
39        mv.addObject("message", ExceptionEnum.HTTP_BAD_REQUEST.getMessage());
40        return mv;
41    }
42
43    /**
44     * 403 - 禁止访问
45     */

46    @ResponseStatus(HttpStatus.FORBIDDEN)
47    @ExceptionHandler(UnauthorizedException.class)
48    public ModelAndView handleUnauthorizedException(UnauthorizedException e) {
49        logger.error("禁止访问", e);
50        ModelAndView mv = new ModelAndView();
51        mv.setViewName("error/403");
52        mv.addObject("code", ExceptionEnum.HTTP_FORBIDDEN.getCode());
53        mv.addObject("message", ExceptionEnum.HTTP_FORBIDDEN.getMessage());
54        return mv;
55    }
56
57    /**
58     * 404 -没有找到
59     */

60    @ResponseStatus(HttpStatus.NOT_FOUND)
61    @ExceptionHandler(NoHandlerFoundException.class)
62    public ModelAndView handleNotFoundException(NoHandlerFoundException e) {
63        logger.error("资源没有找到", e);
64        ModelAndView mv = new ModelAndView();
65        mv.setViewName("error/404");
66        mv.addObject("code", ExceptionEnum.HTTP_NOT_FOUND.getCode());
67        mv.addObject("message", ExceptionEnum.HTTP_NOT_FOUND.getMessage());
68        return mv;
69    }
70
71    /**
72     * 405 - 方法不允许
73     */

74    @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
75    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
76    public ModelAndView handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
77        logger.error("没有权限!", e);
78        ModelAndView mv = new ModelAndView();
79        mv.setViewName("error/405");
80        mv.addObject("code", ExceptionEnum.HTTP_METHOD_NOT_ALLOWED.getCode());
81        mv.addObject("message", ExceptionEnum.HTTP_METHOD_NOT_ALLOWED.getMessage());
82        return mv;
83    }
84
85    /**
86     * 415 - 不支持的媒体类型
87     */

88    @ResponseStatus(HttpStatus.UNSUPPORTED_MEDIA_TYPE)
89    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
90    public ModelAndView handleHttpMediaTypeNotSupportedException(HttpMediaTypeNotSupportedException e) {
91        logger.error("不支持的媒体类型", e);
92        ModelAndView mv = new ModelAndView();
93        mv.setViewName("error/415");
94        mv.addObject("code", ExceptionEnum.HTTP_UNSUPPORTED_MEDIA_TYPE.getCode());
95        mv.addObject("message", ExceptionEnum.HTTP_UNSUPPORTED_MEDIA_TYPE.getMessage());
96        return mv;
97    }
98
99    /**
100     * 500 - 内部服务器错误
101     */

102    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
103    @ExceptionHandler(Exception.class)
104    public ModelAndView handleUnauthorizedException(Exception e) {
105        logger.error("内部服务器错误", e);
106        ModelAndView mv = new ModelAndView();
107        mv.setViewName("error/500");
108        mv.addObject("code", ExceptionEnum.HTTP_INTERNAL_SERVER_ERROR.getCode());
109        mv.addObject("message", ExceptionEnum.HTTP_INTERNAL_SERVER_ERROR.getMessage());
110        return mv;
111    }
112
113    /**
114     * CMSException
115     */

116    @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
117    @ExceptionHandler(CmsException.class)
118    public ModelAndView cmsException(CmsException e) {
119        logger.error("异常:", e);
120        ModelAndView mv = new ModelAndView();
121        mv.setViewName("error/exception");
122        mv.addObject("code", e.getCode());
123        mv.addObject("message", e.getMessage());
124        mv.addObject("reason", e.getReason());
125        return mv;
126    }
127}

自定义异常类

 1package cn.itechyou.cms.exception;
2
3public class CmsException extends Exception {
4
5    private static final long serialVersionUID = 2415656102753230136L;
6
7    private String code;
8    private String message;
9    private String reason;
10
11    public CmsException() {
12        super();
13    }
14
15    public CmsException(String code, String message, String reason) {
16        super(message);
17        this.code = code;
18        this.message = message;
19        this.reason = reason;
20    }
21
22    public String getCode() {
23        return code;
24    }
25
26    public void setCode(String code) {
27        this.code = code;
28    }
29
30    public String getMessage() {
31        return message;
32    }
33
34    public void setMessage(String message) {
35        this.message = message;
36    }
37
38    public String getReason() {
39        return reason;
40    }
41
42    public void setReason(String reason) {
43        this.reason = reason;
44    }
45
46}

找不到模版文件Exception

 1package cn.itechyou.cms.exception;
2
3public class TemplateNotFoundException extends CmsException{
4
5    private static final long serialVersionUID = 3969404221975913175L;
6
7    public TemplateNotFoundException(String code, String message, String reason) {
8        super(code, message, reason);
9    }
10
11}

测试类

 1@RestController
2public class TestController {
3    @RequestMapping("testException")
4    public String testException() throws CmsException{
5        throw new TemplateNotFoundException(
6                    ExceptionEnum.TEMPLATE_NOTFOUND_EXCEPTION.getCode(),
7                    ExceptionEnum.TEMPLATE_NOTFOUND_EXCEPTION.getMessage(),
8                    "请仔细检查" + template.getAbsolutePath() + "文件,或检查application.yml中的资源目录配置项(web.resource-path)。");
9    }
10}

访问testException接口,可得到以下结果:

微信截图_20200707134138.png

如果需要返回json数据,而要渲染某个页面模板返回给浏览器,那么可以这么实现:

 1@ResponseBody
2@ExceptionHandler(value = CmsException.class)
3public Map<String,Object> jsonErrorHandler(CmsException ex) {
4    Map<String,Object> map = new HashMap<String,Object>();
5    map.put("code""40001");
6    //判断异常的类型,返回不一样的返回值
7    if(ex instanceof TemplateNotFoundException){
8        map.put("msg","缺少必需参数:"+((TemplateNotFoundException) ex).getMessage());
9    }else if(ex instanceof TemplateReadException){
10        map.put("msg", ((TemplateReadException) ex).getMessage());
11    }
12    return map;
13}

这样子很方便吧~

1577688142732060174.jpg

I Tech You, 我教你!(www.itechyou.cn)

一个专注于技术分享、免费教程、学习资源的博客!爱好网页技术、网络安全、技术分享、经验分享、IT资讯;最全网络技术学习资源,云服务器折扣活动分享。

欢迎关注,一起学习,共成长!


关于作者: 王俊南(Jonas)

昨夜寒蛩不住鸣。惊回千里梦,已三更。起来独自绕阶行。人悄悄,帘外月胧明。 白首为功名。旧山松竹老,阻归程。欲将心事付瑶琴。知音少,弦断有谁听。

热门文章