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

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());     }
想长寿要先排出毒素,5种助排毒的食物尝试吃,或能促进长寿随着人们经历水平的提高,越来越多的人意识到养生未病先防的重要性,毕竟从古至今延长寿命一直是人类追求的目标。而想要延长自己的寿命,根本性的因素就是保持身体的健康,也就是说只有身体健康天涯明月刀七夕时装被怒喷,造型太和风,打完折还要328?临近七夕,各大游戏厂商也是纷纷推出各种七夕活动,来庆祝传统节日的到来,这其中大多数网游都会选择推出七夕时装。不过时装这种事物,如果处于及格线以上还好,玩家哪怕不喜欢也不会被喷,但要你是否遇到过PS5的待机模式BUG?PS5是有史以来最好的主机之一,其游戏体验非常棒,只不过可能有一个小问题待机模式。据游戏媒体IGN报道,早在去年底,有玩家表示当PS5进入待机模式后无法唤醒,只能按住电源键15秒,第五人格主播明星乱斗Y5复仇GB,但最大赢家是PG北京时间5月30日,第五人格主播明星乱斗进入到了最后一日的赛程。在当日的赛程中共计有两场比赛,分别是GB对阵Y5以及Y5对阵PG。下面来看看这两场比赛的精彩时刻吧。根据赛前积分榜的switch日报爆新款NS底座和屏幕更大!高达SEED推出新游戏新动画爆新款NS更多细节来自西班牙游戏媒体Vandal报道称,他们从一家亚洲零部件制造商处获得了新型NS的部分细节,可以推测出新款switch的一些细节。首先是底座方面,新的主机的底座后自动驾驶测试里程暴增,头部公司如何挖掘数据金矿?智能汽车时代的数据革命。2021年,Robotaxi无人车的规模化与自动驾驶技术的前装量产,已经成为汽车科技发展的两个重要主题。百度在去年底公布其L4自动驾驶车队规模达到500台。阿里180亿ABS项目被终止,网友关心花呗借呗还能用吗5月25日,蚂蚁集团旗下借呗和花呗两个ABS终止发行,共计180亿人民币。网友所以呢?跟我有什么关系?今年4月份,金融管理部门就约谈过蚂蚁集团,根据整改要求,将花呗借呗纳入消费金融海淀再败诉网友称和南山必胜客差太远近日,新浪微博诉今日头条抓取微博内容一案,在海淀法院一审宣判。虽然今日头条主张涉案的用户在两个平台都开了号,已经获得了用户授权,法院还是判了被告败诉,要求其赔偿新浪微博2000万元主打30万内的纯电动车市场?蔚来将推出入门车型Gemini和传统的燃油车不同,新能源车自诞生以来就被资本高高捧起,再加上特斯拉的成功,让众多资本界大佬纷纷想要置身于新能源这片红海,出促使了众多造车新势力的崛起其中,不得不提一个品牌,那就是黄铮之后再无拼多多市值2月来已跌掉一个半比亚迪拼多多发布了看起来很美的数据,却跌了很多,事实上,今年以来,拼多多2月份以来已经跌了1000亿美元了,相当于一个半比亚迪。比亚迪和拼多多所在的行业都是泡沫严重的行业,拼多多跌的这么华为最大尺寸智慧屏正式开售85英寸,定价超2万点击右上角关注我们,每天给您带来最新最潮的科技资讯,让您足不出户也知道科技圈大事!4月8日,华为正式发布了智慧屏V系列的升级产品。第二代的华为智慧屏V系列重点更新了智慧能力和音质表
荒野大镖客2VRMod截图切身体验亚瑟摩根人生在等待GTA6等R星新作的同时,玩家们也不忘在GTA5荒野大镖客2中回味麦可崔佛和亚瑟摩根的纸醉金迷。而此前为GTA5制作VRMod的大神LukeRoss又带来了新的作品大镖客2V英雄联盟职业选手打比赛的时候,休息完毕总会带几个杯子上场,里面装的是奶茶吗?目前lpl春季赛正在如火如荼的进行当中。不过今年的网友眼神似乎有些犀利。在中途休息环节之后,选手登场比赛时,此时的镜头会给到他们登场的样子。这时候每位选手手中都有最少一个杯子。有的龙珠中可以无视对手实力的强大技能有哪些?只想到三个。1。气圆斩动画原创剧情不在讨论范围!这是一个可以无视对方防御的技能,首次登场于赛亚人篇,克林自创的招式,根据设定书的设定当时克林的战斗力只有1770,而拿帕的战斗力高达魔兽世界被诅咒的纪念品,曾经拍卖行标价数十万金币,这件道具有何特别之处?前言魔兽世界9。0版本前夕任务线的开放,让练小号的玩家有了一个快速提升装备等级的途径,然而随着去刷前夕稀有怪的玩家越来越多,一件稀有怪掉落的白色道具却引起了玩家们的关注,这件道具就赛博朋克2077八折促销电脑玩家值得入手赛博朋克2077在EPIC游戏平台正进行八折促销活动,感兴趣的玩家们可以趁机入手。赛博朋克2077是一款开放世界动作冒险游戏,故事发生在夜之城。这是一座五光十色的大都会,权力更迭和半条命Alyx敌人原本可以识别玩家竖中指半条命Alyx在2020年上市之后,收获了来自玩家和媒体的一致褒奖,成为史上最佳的VR游戏之一。这款游戏中,玩家和场景的互动级别达到了空前程度,但在最终版里还是没有实现开发人员的所英雄联盟手游国服先锋测试已经开启!和国际服对比,有这几个变化听说5月21日,英雄联盟手游国服第一批测试已经开始了。并且在我第三次预约以后,官方又再一次通过QQ给我推送了预约消息。这已经是我第四次预约了。跟着我又去查看了一番我在腾讯先游里面的吃鸡握把解析从射击原理透析握把选择,助你从小白进阶高端玩家大家好,我是离咕咕。今天给大家带来一个关于握把的详细攻略解答。前言这篇攻略我很久之前就打算做了,因为很多新手玩家和初步进阶的玩家对于握把的选择并不是十分了解。而目前网络上又存在很多盘点下那些曾经红极一时的女主播!现在他们过的还好吗?赵丽颖和冯绍峰走到一起还领证的消息让微博直接被刷爆了,无数粉丝送上祝福,赵丽颖的微博粉丝在一天之内狂涨100万。当然今天不是和大家谈娱乐圈的八卦,而是说说我们的直播圈的反差。和娱乐厂长回归全队智商上线,Ray杀疯了,赢了比赛却把自己打哭了!在厂长回归后,连续三场首发将Haro死死按在了替补席上,而全队的表现也是得到了巨大的提升。自厂长登场后的这三场比赛,EDG全队与此前截然不同,不仅整体打得更有章法,还给几名队友套上隐形守护者武藤纯子直播首秀颜值遭质疑,余小C都怪摄像头隐形守护者武藤纯子直播首秀颜值遭质疑,余小C都怪摄像头!大家好,我是电竞清流浪子语,关注了解更多电竞,游戏,主播资讯!相信不少游戏玩家都听过或者玩过一款影视剧的互动游戏隐形守护者,