范文健康探索娱乐情感热点
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文

springboot项目中简单的统一异常处理

  刚工作时,接触的第一个项目是一个新开发的运维系统,该项目是springboot 框架,也按照控制层(controller),业务层(service),数据层(dao)的结构进行的开发。而进入到开发中,难免会遇到许多业务异常,和运行时异常需要处理。那时候,项目没有统一的返回实体包装数据,返回的数据结构很随意,甚至很多异常都不会去处理,任由错误经框架抛出,很是粗暴。
  后续开发过程中,意识到任由异常抛出,这样不妥,且前端需要"优雅的"展示异常信息。于是开始采用 try catch 捕获异常后,获取异常信息,赋给异常字段后返回给前端。甚至图方便直接 controller 里面直接获取。@Controller public class AutoController {      @Autowired     private UserInfoService userInfoService;      @RequestMapping("/test")     @ResponseBody     public ResultDto test(){         try{             String name = userInfoService.getName();             ResultDto resultDto = new ResultDto();             resultDto.setData(name);             return resultDto;         }catch (Exception e){             ResultDto resultDto = new ResultDto();             resultDto.setErrorInfo(e.getMessage());             return resultDto;         }              }
  这种方式简直折磨人,每一个controller 都搞一堆 try catch 。而且,业务层的代码,遇到问题也是new 一个对象处理,后面当我接触老的项目的时候,我发现很多异常都是这么处理的,着实让人崩溃。ResultDto resultDto = new ResultDto(); resultDto.setErrorInfo("参数错误");
  后面的工作中认识到,其实项目中的统一异常处理真的很简单创建一个统一返回包装类package com.chinamobile.cmss.dmp.deployer.common.response;  import com.chinamobile.cmss.dmp.deployer.common.response.HttpStatusJsonSerializer; import com.chinamobile.cmss.dmp.deployer.exception.BusinessException; import com.fasterxml.jackson.databind.annotation.JsonSerialize; import lombok.AllArgsConstructor; import lombok.Builder; import lombok.Data; import lombok.NoArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity;  /**  * @description:  * @date: 2020/11/12/16:05  */ @AllArgsConstructor @NoArgsConstructor @Builder @Data public class ApiResponse {      /**      * http状态码      */     @JsonSerialize(using = HttpStatusJsonSerializer.class)     private HttpStatus status;     /**      * 系统错误码      */     private String code;     /**      * 提示信息,展示给用户      */     private String message;     /**      * 调试信息      */     private Object debugInfo;     /**      * 响应主体      */     private Object content; }
  2.创建一个包装返回实体的工具类,定义一些成功返回的方法。package com.chinamobile.cmss.dmp.deployer.common.response;  import org.springframework.http.HttpStatus;  /**  * 封装统一返回类  *  * @author  */ public class Response {      /**      * 具有返回数据的封装      *      * @param content 数据内容      * @return ApiResponse      */     public static ApiResponse invokeSuccess(Object content){         ApiResponse apiResponse = ApiResponse.builder()                 .status(HttpStatus.OK)                 .code(SystemCode.OK)                 .message("请求成功")                 .content(content)                 .build();         return apiResponse;     }      /**      * 没有返回数据的封装      *      * @return ApiResponse      */     public static ApiResponse invokeSuccess(){         ApiResponse apiResponse = ApiResponse.builder()                 .status(HttpStatus.OK)                 .code(SystemCode.OK)                 .message("请求成功")                 .content(null)                 .build();         return apiResponse;     }      /**      * @param content 返回数据      * @param message 消息      * @return ApiResponse      */     public static ApiResponse invokeSuccess(Object content,String message){         ApiResponse apiResponse = ApiResponse.builder()                 .status(HttpStatus.OK)                 .code(SystemCode.OK)                 .message(message)                 .content(content)                 .build();         return apiResponse;     }      /**      *      * @param status 请求状态      * @param code 状态码      * @param content 返回内容      * @param message 消息      * @return ApiResponse      */     public static ApiResponse invoke(HttpStatus status, String code, Object content, String message){         ApiResponse apiResponse = ApiResponse.builder()                 .status(status)                 .code(code)                 .message(message)                 .content(content)                 .build();         return apiResponse;     }      /**      *      * @param status 请求状态      * @param code 状态码      * @param message 消息      * @return ApiResponse      */     public static ApiResponse invoke(HttpStatus status, String code, String message){         ApiResponse apiResponse = ApiResponse.builder()                 .status(status)                 .code(code)                 .message(message)                 .build();         return apiResponse;     } }
  3.创建一个定义错误信息的枚举,定义业务错误信息package com.li.core.hellomeeting.common.Response;  /**  * 返回码和返回消息  *  */ public enum ResponseCodeEnum {      SUCCESS(200,"请求成功"),      INTERNAL_SERVER_ERROR(500,"服务器内部错误"),      /** 参数错误 **/     PARAM_INVALID_ERROR(1001,"参数校验错误"),      USER_NOTE_EXIST(2004,"用户不存在"),      FORBIDDEN(403,"禁止访问"),      UNAUTHORIZED(401,"未登录");      private Integer code;      private String message;      ResponseCodeEnum(Integer code, String message) {         this.code = code;         this.message = message;     }      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;     }  }
  3.创建一个业务异常类,继承 RuntimeException 类package com.li.core.hellomeeting.exception;  import com.li.core.hellomeeting.common.Response.ResponseResult;  /**  * 统一业务异常  *  */ public class BusinessException extends RuntimeException{      private ResponseResult responseResult;      public BusinessException(String message) {         super(message);     }      public BusinessException(String message, Throwable cause) {         super(message, cause);     }      public BusinessException(Throwable cause) {         super(cause);     }      public BusinessException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {         super(message, cause, enableSuppression, writableStackTrace);     }      public ResponseResult getResponseResult() {         return responseResult;     }      public void setResponseResult(ResponseResult responseResult) {         this.responseResult = responseResult;     } }
  4.创建一个异常捕获处理类,使用 @RestControllerAdvice 注解,拦截抛出的异常。package com.li.core.hellomeeting.exception;  import com.li.core.hellomeeting.common.Response.ErrorInfo; import com.li.core.hellomeeting.common.Response.ResponseResult; import lombok.extern.slf4j.Slf4j; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.security.access.AccessDeniedException; import org.springframework.validation.BindException; import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.MissingServletRequestParameterException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.multipart.MultipartException;  import java.util.List; import java.util.stream.Collectors;  import static com.li.core.hellomeeting.common.Response.StatusCode.*; import static com.li.core.hellomeeting.common.Response.StatusCode.PERMISSION_NO_ACCESS;   /**  * 全局异常拦截  *  * @author  */ @Slf4j @RestControllerAdvice public class GlobalExceptionHandler {      private final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);      /**      * 参数校验错误      *      * @param e 错误信息      * @return ResponseResult      */     @ExceptionHandler(value = BindException.class)     public ResponseResult handleBindException(BindException e){         log.error("参数校验错误", e);         ErrorInfo errorInfo = new ErrorInfo();         List fieldErrorInfos = e.getFieldErrors().stream()                 .map(fieldError -> new ErrorInfo.FieldErrorInfo(fieldError.getField(),fieldError.getRejectedValue(),fieldError.getDefaultMessage()))                 .collect(Collectors.toList());         errorInfo.setFieldErrorInfos(fieldErrorInfos);         return ResponseResult.builder()                 .code(PARAM_IS_INVALID.code())                 .message(PARAM_IS_INVALID.message())                 .flag(PARAM_IS_INVALID.status())                 .build();     }      /**      *处理参数错误信息      *      * @param e 错误信息      * @return ResponseResult      */     @ExceptionHandler(value = MethodArgumentNotValidException.class)     public ResponseResult handleBindException(MethodArgumentNotValidException e) {         log.error("参数错误{}", e);         return ResponseResult.builder()                 .code(PARAM_IS_INVALID.code())                 .message(PARAM_IS_INVALID.message())                 .flag(PARAM_IS_INVALID.status())                 .build();     }      /**      *处理非法的请求方法错误      *      * @param e 错误信息      * @return ResponseResult      */     @ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)     public ResponseResult handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {         String msg = String.format("不支持 [%s] 请求", e.getMethod());         log.error(msg+"{}", e);         return ResponseResult.builder()                 .code(METHOD_NOT_ALLOWED.code())                 .message(METHOD_NOT_ALLOWED.message())                 .flag(METHOD_NOT_ALLOWED.status())                 .build();     }      /**      * 处理参数缺失错误信息      *      * @param e 错误信息      * @return ResponseResult      */     @ExceptionHandler(value = MissingServletRequestParameterException.class)     public ResponseResult handleMissingServletRequestParameterException(MissingServletRequestParameterException e) {         String msg = String.format("缺少 %s 参数", e.getParameterName());         log.error(msg+"{}", e);         return ResponseResult.builder()                 .code(PARAM_NOT_COMPLETE.code())                 .message(PARAM_NOT_COMPLETE.message())                 .flag(PARAM_NOT_COMPLETE.status())                 .build();     }      /**      * 处理上传异常信息      *      * @param e 错误信息      * @return ResponseResult      */     @ExceptionHandler(value = MultipartException.class)     public ResponseResult handleMultipartException(MultipartException e) {         log.error("上传异常{}", e);         return ResponseResult.builder()                 .code(EXCEED_MAX_SIZE.code())                 .message(EXCEED_MAX_SIZE.message())                 .flag(EXCEED_MAX_SIZE.status())                 .build();     }      /**      * 处理访问权限错误      *      * @param e 错误信息      * @return ResponseResult      */     @ResponseBody     @ExceptionHandler(AccessDeniedException.class)     public ResponseResult handleAccessDeniedException(AccessDeniedException e) {         return ResponseResult.builder()                 .code(PERMISSION_NO_ACCESS.code())                 .message(PERMISSION_NO_ACCESS.message())                 .flag(PERMISSION_NO_ACCESS.status())                 .build();     }      /**      * 处理全局异常      * 通常处理统一的未知异常      *      * @param e 异常信息      * @return ResponseResult      */     @ExceptionHandler(value = Exception.class)     public ResponseResult handleException(Exception e) {         log.error("服务器内部错误", e);         return ResponseResult.builder()                 .code(INTERNAL_SERVER_ERROR.code())                 .message(INTERNAL_SERVER_ERROR.message())                 .flag(INTERNAL_SERVER_ERROR.status())                 .build();     }      /**      * 处理业务异常      * 如果携带了一个 ResponseResult,则提取出来进行返回      * 否则返回 null      *      * @param e 错误信息      * @return ResponseResult      */     @ExceptionHandler(value = BusinessException.class)     public ResponseResult handleBusinessException(BusinessException e) {         log.error(e.getMessage(), e);         ResponseResult responseResult;         if(e.getResponseResult() != null){             responseResult = e.getResponseResult();         }else{             log.error("服务器内部错误{}", e.getCause());             responseResult = ResponseResult.builder()                     .code(INTERNAL_SERVER_ERROR.code())                     .message(INTERNAL_SERVER_ERROR.message())                     .flag(INTERNAL_SERVER_ERROR.status())                     .build();         }         return responseResult;     }   }
  5.封装一些异常错误,配合定义好的错误枚举类使用。package com.chinamobile.cmss.dmp.deployer.exception;  import com.chinamobile.cmss.dmp.deployer.common.response.Response; import com.chinamobile.cmss.dmp.deployer.common.response.SystemCode; import org.springframework.http.HttpStatus;  /**  * 异常统一抛出封装  *  */ public class MyException {      /**      *抛出错误信息      *      * @param status 状态      * @param code 状态码      * @param content 内容      * @param message 错误信息      * @return BusinessException      */     public BusinessException throwException(HttpStatus status, String code, Object content, String message){         BusinessException businessException = new BusinessException(message);         businessException.setApiResponse(Response.invoke(status,code,content,message));         return businessException;     }      /**      * 参数错误异常      * @param message 异常信息      * @return BusinessException      */     public BusinessException badRequest(String message){         BusinessException businessException = new BusinessException(message);         businessException.setApiResponse(Response.invoke(HttpStatus.BAD_REQUEST, SystemCode.BAD_REQUEST,null,message));         return businessException;     }      /**      * 找不到目标值错误      *      * @param message 错误信息      * @return BusinessException      */     public BusinessException notFound(String message){         BusinessException businessException = new BusinessException(message);         businessException.setApiResponse(Response.invoke(HttpStatus.NOT_FOUND, SystemCode.NOT_FOUND,null,message));         return businessException;     }      /**      * 无权限错误      *      * @param message 错误信息      * @return BusinessException      */     public BusinessException forbideen(String message){         BusinessException businessException = new BusinessException(message);         businessException.setApiResponse(Response.invoke(HttpStatus.FORBIDDEN,SystemCode.FORBIDDEN,null,message));         return businessException;     } }
  在业务中使用,截取个例子一部分代码@Override     public void deployService(DeployParam deployParam){         log.info("------> 【自动化部署接口】参数:{}",deployParam);         //校验一下         checkParam(deployParam);         //获取环境配置信息         ServiceDeployInfoDto serviceDeployInfoDto = getServiceDeployInfoDto(deployParam);         log.info("------> 整合环境配置信息:{}",serviceDeployInfoDto);         //判断服务是否在部署中         boolean status = DeployUtils.isDeploying(deployParam.getEnv(),deployParam.getInstance());         log.info("------> 判断当前实例是否正在部署,status: {}",status);         if(status){             log.error("{} 服务正在部署中,请稍后再部署",deployParam.getInstance());             throw new MyException().badRequest("该服务正在部署中,请稍后");         }         //2.开始部署         log.info("------>  开始进行异步部署......");         if(deployParam.getInstance().equals("openapi2")){             serviceDeployInfoDto.setInstanceName("openapi");         }         deployManager.deployService(serviceDeployInfoDto);     }
  在controller 中使用@PostMapping(value = "/deploy")     public ResponseEntity deploy(@RequestParam("file") MultipartFile file,@Validated DeployParam deployParam,BindingResult result){         ControllerUtils.checkBindingResult(result);         deployParam.setFile(file);         deployService.deployService(deployParam);         return ResponseEntity.ok(Response.invokeSuccess());     }
碧蓝幻想Versus关于GBVS出新角色给想入游戏的新玩家的一些科普作者NGA是武藏亲哦12月14日新角色维拉要出了,给想入手GBVS的新玩家一些科普角色知识以及游戏内容,本人也稍微入手玩了1年左右。因为没钱买PS4的原因,所以只能在电脑上买ste热血传奇手机版游戏界面大解析主菜单区域功能主菜单区域键位功能,可以在游戏界面中间最下方的红蓝显示处点击展开,再次点击则可隐藏,常规的角色背包技能装备组队,等常用按键都可在此轻松找到聊天区域功能聊天按键聊天按键原神匪贼之窝位置大全原神调查点匪贼之窝位置在哪儿?在原神游戏中,近期的活动任务需要玩家解救小动物,很多玩家不清楚调查点匪贼之窝位置在哪儿,下面为大家带来了原神匪贼之窝位置大全,一起来看看吧。原神调查点哈利波特手游双人野排最不希望看到的队友流派是什么?多比躺枪哈利波特魔法觉醒(以下简称哈利波特手游)作为一款卡牌游戏,不仅结合了了即时战略,而且在社交上是一个不小突破,因为可以打双人排位,4人2v2的卡牌对战是相当刺激的,因为和不认识的玩家哈利波特魔法觉醒拼图寻宝大全哈利波特拼图寻宝每日拼图线索位置第一天至第七天线索攻略哈利波特魔法觉醒火热上线了,在开服活动中,拼图寻宝的玩法吸引了众多玩家关注。我们每日登陆游戏后,都会收到拼图碎片的线索,收集齐碎片后,就能完成拼图寻宝的任务了。每日拼图寻宝线索的具LPL全明星Solo赛赛事分析!入围赛注本次Solo赛机制毒圈机制,不再是一血。而是谁能活到最后第一场WBG。Bin贾克斯vsLNG。Light剑姬BINwin阿bin致命节奏武器对阵剑姬,武器骗出剑姬w之后。贴墙防止英雄联盟各位置难度拍排名应该怎么排?难度排名,第一永远是中单,不论版本怎么改变,都不可能有一个位置的难度能够超过中单。先说结论再说原因因为顶尖的中路,可以凭一己之力代领队伍胜利,而其他任何一个位置都做不到。评论区好多数码宝贝手游,木偶兽迎来史诗级削弱,此消彼长后,影响不大随着周四更新预告的到来,又有一些数码兽即将迎来调整。其中就包括目前版本比较强势的木偶兽。作为当前版本比较无脑的数码兽,木偶兽的AP削减,对于大部分数码兽来说,都能起到很好的克制作用幻塔游戏中的武器平平无奇?开启拟态后让你爱到不行对于玩游戏的小伙伴们来说,武器可以算是游戏中最常见也最基础的系统了。武侠游戏中可能会有类似屠龙刀倚天剑等神兵利器科幻题材游戏中可能会有手枪冲击炮等高科技产物。怎么说呢,虽然可能游戏新游预报丨幻塔将上线!无边存在迷雾公式来袭新的一周又要到啦!在下周新游中,期待已久的幻塔终于要正式上线了!不知道大家都做好准备了吗?而无边存在迷雾公式苍之骑士团2等潜力新作也即将开测,真是等不及了话不多说,就让我们一起来看光环无限最强近战武器决斗能量剑光剑获得方法各位小伙伴大家好,这里是玩咖游戏宝典东东。在玩家的殷切期望下光环无限终于正式发布了,想必许多玩家还在为没有趁手的武器发愁,本次小编就带大家来看看光环无限战役模式中最强近战武器决斗能
RNG小虎MSI重回中路!中单盲僧神出鬼没,小组赛有望冲击8连胜?目前2021MSI正在如火如荼地进行中,作为LPL赛区的参赛队伍,RNG自然吸引了许多玩家的目光。不过和大家预想的不一样,虽然RNG在LPL的夺冠之旅并不顺利,但在MSI上他们却展LOL新英雄格温上线!厄斐琉斯全面加强,诺手皎月被赶进了野区?随着各大赛区春季赛的结束,拳头也开始着手准备即将举办的MSI。不过在此之前,官方发布了新版本,新英雄格温和五款新皮肤正式上线和大家见面。作为一名AP战士,格温和之前的英雄有很多不同RNG打服了对手?UOL赛后承认之前觉得能赢他们,现在直接放弃了经过几日的较量后,本次MSI在A组的比赛已经告一段落,代表LPL出征的RNG率先晋级淘汰赛。虽然RNG在LPL拿到了春季赛冠军,但赛前依旧有玩家并不看好他们的MSI之旅。毕竟这支RRNG爆冷后拿对手泄愤,巨大差距遭官方吐槽把我们错当成PSG了?在本届MSI的比赛中,RNG战队的表现让很多人眼前一亮。虽然不少人赛前都认为他们有争冠的实力,但没想到从小组赛一路过来RNG居然一场未败,特别是在面对世界冠军战队DK时也轻松获得了FPX一穿4晋级决赛!金咕咕阿卡丽中路单杀,西卡圣枪哥有问题在本次LPL季后赛中,IG无疑是赛前大家都很看好的队伍。虽然他们常规赛的战绩不佳,但依旧有许多粉丝期待他们看到一穿6成功夺冠。不过可惜的是,在首轮比赛IG就不敌RA淘汰出局,夺冠梦IG宁王终于被认可了?官宣入选电竞名人堂,夏季赛或以首发回归对于很多LPL玩家来说,虽然IG战队最近几个赛季的成绩不是很理想,但他们在大家心里依旧拥有很高的地位。原因无他,IG在S8赛季的夺冠不仅帮助LPL拿到了第一座世界冠军奖杯,也让很多卡萨抢龙难救主!EDG双C再度碾压TES,阿水终于败给了歪破在上一场比赛中,由于RNG遭到FPX零封,导致不少玩家认为常规赛的排名非常虚假,RNG和EDG的真实实力其实并没有大家想象中那么强。因此尽管TES的下一个对手是本赛季崛起的EDG,Viper梦回S9?圣枪哥变成国产剑皇,FPX打破红色方不胜魔咒在LPL春季季后赛的半决赛阶段,FPX和EDG和我们带来了一场非常精彩的比赛。虽然EDG在常规赛的表现非常好,但由于FPX一路从6强杀了上来,导致许多人认为FPX手感非常火热,EDLPL夺冠全靠韩国人?LCK记者公开嘲讽LPL,玩家回应无法反驳随着春季赛正式结束之后,一年一度的MSI大赛很快就要开打,各大战队也都先后到达举办地备战。作为LPL的春季赛冠军,RNG的MSI之旅受到很多玩家期待,不少人都希望看到他们能够获得好UZI和我打BO5没赢过,Imp与女粉双排再放狠话,粉丝无力反驳说起LPL人气最高的选手是谁,相信不少人都会提到UZI。作为一名老牌选手,虽然UZI很早就出道代表皇族出战,但他的人气却始终不减,随着RNG登顶S8赛季的MSI更是达到了巅峰。不过RNG双杀PGG!Cryin公屏打字请教Bolo梗,粉丝对面心态崩了在MSI第二日的比赛中,RNG再次迎来了PGG的挑战。由于上一场比赛大胜PGG,因此赛前不少人都看好RNG能够双杀对手。由于本次MSI采用了新赛制,RNG只要赢下这场比赛,那么他们