首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Spring使用@ControllerAdvice注解优雅地处理异常信息

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

作者头像
I Teach You 我教你
发布于 2023-07-18 14:17:03
发布于 2023-07-18 14:17:03
1.9K0
举报

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

统一异常处理

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

全局异常捕捉处理

代码语言:javascript
复制
  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}

自定义异常类

代码语言:javascript
复制
 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

代码语言:javascript
复制
 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}

测试类

代码语言:javascript
复制
 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接口,可得到以下结果:

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

代码语言:javascript
复制
 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}

这样子很方便吧~

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020/07/07 ,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • 统一异常处理
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档