微服务架构之全局异常处理

  • 一、定义全局异常处理类(GlobalExceptionHandler)
    • 1、在cloud-common模块中创建全局异常处理类GlobalExceptionHandler
    • 2、编写全局异常类代码
  • 二、测试未使用全局异常捕捉方法异常
    • 1、启动user模块进行测试
    • 2、运行结果
  • 三、测试使用全局异常捕捉方法异常
    • 1、user测试编码
    • 2、运行结果
  • 四、Controller层使用@Valid +@RequestBody 校验入参对象属性
今天的学习内容是在微服务的公共模块中创建全局异常处理对象,对业务异常进行拦截处理,学完这篇将会学到从零开始也会编写全局异常处理类了。
  • 我们在对业务进行处理时,当数据库操作失败,或遇到未受检测的异常时让 Service 层抛出运行时异常,Spring 事物管理器就会进行回滚。
  • 但是我们就会在Controller层编写try-catch 捕捉Service 层的异常,然后进行错误信息封装再返回给客户端,否则会返回一些不友好的错误信息到客户端。但是,Controller 层每个方法体都写一些模板化的 try-catch 的代码,这样的代码很冗余、臃肿、难维护,而且要对 Service 层的不同异常进行不同处理,那么业务逻辑就会更复杂。
  • 使用@ControllerAdvice + @ExceptionHandler 进行全局异常处理,可以简化Controller与Service层对业务异常的处理,使代码看起来更简洁、清晰、易维护。
  • @ControllerAdvice 使用在类上,@ExceptionHandler使用在方法上。

一、定义全局异常处理类(GlobalExceptionHandler)

1、在cloud-common模块中创建全局异常处理类GlobalExceptionHandler

cloud-common模块搭建请参考前面章节,链接:https://editor.csdn.net/md/?articleId=109964260

2、编写全局异常类代码

package yooo.yun.com.common.exception;import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpMediaTypeException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestController;
import yooo.yun.com.common.api.ApiCode;
import yooo.yun.com.common.api.ApiResult;import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;/*** @author wangjiao* @since 2020/11/14*/
@ControllerAdvice
@RestController
@Slf4j
public class GlobalExceptionHandler {/*** 非法参数验证异常** @param ex ex* @return res*/@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(value = HttpStatus.OK)public ApiResult handleMethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {BindingResult bindingResult = ex.getBindingResult();List<String> list = new ArrayList<>();List<FieldError> fieldErrors = bindingResult.getFieldErrors();for (FieldError fieldError : fieldErrors) {list.add(fieldError.getDefaultMessage());}Collections.sort(list);log.error("fieldErrors:[ex:{}]", JSON.toJSONString(list));return ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, list);}/*** 系统登录异常处理** @param exception exception* @return res*/@ExceptionHandler(value = SysLoginException.class)@ResponseStatus(HttpStatus.OK)public ApiResult sysLoginExceptionHandler(SysLoginException exception) {log.warn("sysLoginExceptionHandler:系统登录异常[exception:{}]", exception.getMessage());return ApiResult.fail(ApiCode.LOGIN_EXCEPTION);}/*** HTTP解析请求参数异常** @param e e* @return res*/@ExceptionHandler(value = HttpMessageNotReadableException.class)@ResponseStatus(HttpStatus.OK)public ApiResult httpMessageNotReadableException(HttpMessageNotReadableException e) {log.error("httpMessageNotReadableException:[e:{}]", e.getMessage());return ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, ApiCode.PARAMETER_PARSE_EXCEPTION);}/*** HTTP** @param exception exception* @return res*/@ExceptionHandler(value = HttpMediaTypeException.class)@ResponseStatus(HttpStatus.OK)public ApiResult httpMediaTypeException(HttpMediaTypeException exception) {log.error("httpMediaTypeException:[exception:{}]", exception.getMessage());return ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, ApiCode.HTTP_MEDIA_TYPE_EXCEPTION);}/*** 自定义业务/数据异常处理** @param exception exception* @return res*/@ExceptionHandler(value = {SpringBootPlusException.class})@ResponseStatus(HttpStatus.OK)public ApiResult springBootPlusExceptionHandler(SpringBootPlusException exception) {log.error("springBootPlusException:[exception:{}]", exception.getMessage());int errorCode;if (exception instanceof BusinessException) {errorCode = ApiCode.BUSINESS_EXCEPTION.getCode();} else if (exception instanceof DaoException) {errorCode = ApiCode.DAO_EXCEPTION.getCode();} else if (exception instanceof VerificationCodeException) {errorCode = ApiCode.VERIFICATION_CODE_EXCEPTION.getCode();} else {errorCode = ApiCode.SPRING_BOOT_PLUS_EXCEPTION.getCode();}return new ApiResult().setCode(errorCode).setMsg(exception.getMessage());}/*** 登陆授权异常处理** @param exception exception* @return res*/@ExceptionHandler(value = AuthenticationException.class)@ResponseStatus(HttpStatus.OK)public ApiResult authenticationExceptionHandler(AuthenticationException exception) {log.error("authenticationExceptionHandler:[exception:{}]", exception.getMessage());return new ApiResult().setCode(ApiCode.AUTHENTICATION_EXCEPTION.getCode()).setMsg(exception.getMessage());}/*** 未认证异常处理** @param exception exception* @return res*/@ExceptionHandler(value = UnauthenticatedException.class)@ResponseStatus(HttpStatus.OK)public ApiResult unauthenticatedExceptionHandler(UnauthenticatedException exception) {log.error("unauthenticatedExceptionHandler:[exception:{}]", exception.getMessage());return ApiResult.fail(ApiCode.UNAUTHENTICATED_EXCEPTION);}/*** 未授权异常处理** @param exception exception* @return res*/@ExceptionHandler(value = UnauthorizedException.class)@ResponseStatus(HttpStatus.OK)public ApiResult unauthorizedExceptionHandler(UnauthorizedException exception) {log.error("unauthorizedExceptionHandler:[exception:{}]", exception.getMessage());return ApiResult.fail(ApiCode.UNAUTHORIZED_EXCEPTION);}/*** SQL 语法异常** @param exception exception* @return res*/@ExceptionHandler(value = BadSqlGrammarException.class)@ResponseStatus(HttpStatus.OK)public ApiResult badSqlGrammarException(BadSqlGrammarException exception) {log.info("badSqlGrammarException:[exception:{}]", exception.getMessage());return ApiResult.fail(ApiCode.SQL_ERROR_EXCEPTION);}/*** 默认的异常处理** @param exception exception* @return res*/@ExceptionHandler(value = Exception.class)@ResponseStatus(HttpStatus.OK)public ApiResult exceptionHandler(Exception exception) {log.error("exceptionHandler:[exception:{}]", exception.getMessage());if (Objects.nonNull(exception.getMessage())) {return ApiResult.fail(exception.getMessage());}return ApiResult.fail(ApiCode.SYSTEM_EXCEPTION);}
}

二、测试未使用全局异常捕捉方法异常

1、启动user模块进行测试

  • 因为common模块是属于微服务的公共模块,所以其他微服务模块只需要在pom文件中引入common模块的依赖就可以直接使用common中配置的信息。
  • user模块引入common模块依赖
 <dependency><groupId>yooo.yun.com</groupId><artifactId>cloud-common</artifactId><version>1.0-SNAPSHOT</version><scope>compile</scope></dependency>
  • 代码中Controller层使用try catch捕捉service抛出的异常,编码如下:
package yooo.yun.com.user.controller.saas;import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import yooo.yun.com.common.api.ApiCode;
import yooo.yun.com.common.api.ApiResult;
import yooo.yun.com.common.entity.pojo.UserPoJo;
import yooo.yun.com.common.entity.request.UserLoginReq;
import yooo.yun.com.common.entity.request.UserReq;
import yooo.yun.com.user.service.UserService;import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Objects;/*** @author WangJiao* @since 2020/10/14*/
@Slf4j
@RequestMapping(value = "/saas/user")
@RestController("sUserC")
public class UserController {@Resource private UserService service;/*** 用户注册** @param req 注册信息* @return obj*/@PostMapping("/register")@ApiOperation("注册")public ApiResult register(@Valid @RequestBody UserReq req){log.info("register:[req:{}]", JSON.toJSONString(req));if (!Objects.equals(req.getPassword(), req.getRePassword())) {return ApiResult.fail(ApiCode.USER_TWO_PASSWORDS_INCONSISTENT);}try{UserPoJo findUser = service.getByTel(req.getTel());if (Objects.nonNull(findUser)) {return ApiResult.fail(ApiCode.USER_ACCOUNT_REGISTERED);}// md5加密req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));boolean res = service.save(UserPoJo.of(req));log.info("register:[res:{}]", res);return ApiResult.ok(res);}catch (Exception e) {e.printStackTrace();return ApiResult.fail(e.getMessage());}}
}
  • UserService编码:
package yooo.yun.com.user.service;import yooo.yun.com.common.entity.pojo.UserPoJo;
import yooo.yun.com.common.service.BaseService;/*** @author WangJiao* @since 2020/11/12*/
public interface UserService extends BaseService<UserPoJo> {/*** query user info by tel** @param tel the tel* @return user*/UserPoJo getByTel(String tel) throws Exception;
}
  • UserServiceImpl编码:
package yooo.yun.com.user.service.impl;import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import yooo.yun.com.common.entity.pojo.UserPoJo;
import yooo.yun.com.common.service.Impl.BaseServiceImpl;
import yooo.yun.com.user.mapper.UserMapper;
import yooo.yun.com.user.service.UserService;import javax.annotation.Resource;/*** @author WangJiao* @since 2020/11/12*/
@Slf4j
@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserPoJo> implements UserService {@Resource private UserMapper mapper;@Overridepublic UserPoJo getByTel(String tel) throws Exception{log.info("getByTel:[tel:{}]", tel);return mapper.selectOne(Wrappers.<UserPoJo>lambdaQuery().eq(UserPoJo::getTel, tel)) throws Exception;}
}

2、运行结果

  • sql异常,但是抛出了一段不友好的信息给客户端
  • 所以我们只要对BadSqlGrammarException进行异常信息拦截,客户端只需要提示sql异常即可。
org.springframework.jdbc.BadSqlGrammarException: Error querying database.  Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException: Table 'cloud_user.r_user' doesn't exist

三、测试使用全局异常捕捉方法异常

1、user测试编码

package yooo.yun.com.user.controller.saas;import com.alibaba.fastjson.JSON;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;
import yooo.yun.com.common.api.ApiCode;
import yooo.yun.com.common.api.ApiResult;
import yooo.yun.com.common.entity.pojo.UserPoJo;
import yooo.yun.com.common.entity.request.UserLoginReq;
import yooo.yun.com.common.entity.request.UserReq;
import yooo.yun.com.user.service.UserService;import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.Objects;/*** @author WangJiao* @since 2020/10/14*/
@Slf4j
@RequestMapping(value = "/saas/user")
@RestController("sUserC")
public class UserController {@Resource private UserService service;/*** 用户注册** @param req 注册信息* @return obj*/@PostMapping("/register")@ApiOperation("注册")public ApiResult register(@Valid @RequestBody UserReq req){log.info("register:[req:{}]", JSON.toJSONString(req));if (!Objects.equals(req.getPassword(), req.getRePassword())) {return ApiResult.fail(ApiCode.USER_TWO_PASSWORDS_INCONSISTENT);}UserPoJo findUser = service.getByTel(req.getTel());if (Objects.nonNull(findUser)) {return ApiResult.fail(ApiCode.USER_ACCOUNT_REGISTERED);}// md5加密req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));boolean res = service.save(UserPoJo.of(req));log.info("register:[res:{}]", res);return ApiResult.ok(res);}
}
  • UserService代码:
package yooo.yun.com.user.service;import yooo.yun.com.common.entity.pojo.UserPoJo;
import yooo.yun.com.common.service.BaseService;/*** @author WangJiao* @since 2020/11/12*/
public interface UserService extends BaseService<UserPoJo> {/*** query user info by tel** @param tel the tel* @return user*/UserPoJo getByTel(String tel);
}
  • UserServiceImpl实现类编码:
package yooo.yun.com.user.service.impl;import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import yooo.yun.com.common.entity.pojo.UserPoJo;
import yooo.yun.com.common.service.Impl.BaseServiceImpl;
import yooo.yun.com.user.mapper.UserMapper;
import yooo.yun.com.user.service.UserService;import javax.annotation.Resource;/*** @author WangJiao* @since 2020/11/12*/
@Slf4j
@Service
public class UserServiceImpl extends BaseServiceImpl<UserMapper, UserPoJo> implements UserService {@Resource private UserMapper mapper;@Overridepublic UserPoJo getByTel(String tel) {log.info("getByTel:[tel:{}]", tel);return mapper.selectOne(Wrappers.<UserPoJo>lambdaQuery().eq(UserPoJo::getTel, tel));}
}

2、运行结果

  • 返回友好的信息给客户端。

  • 原因是我们定义的全局异常类对业务层抛出的异常进行了拦截处理,这一段代码处理如下:
  /* SQL 语法异常** @param exception exception* @return res*/@ExceptionHandler(value = BadSqlGrammarException.class)@ResponseStatus(HttpStatus.OK)public ApiResult badSqlGrammarException(BadSqlGrammarException exception) {log.info("badSqlGrammarException:[exception:{}]", exception.getMessage());return ApiResult.fail(ApiCode.SQL_ERROR_EXCEPTION);}

四、Controller层使用@Valid +@RequestBody 校验入参对象属性

  • @Valid +@RequestBody作用于Post或Put接口,校验对象中的基础属性字段,简化校验操作,减少对空参数的校验。
  • user入参对象编码如下:
package yooo.yun.com.common.entity.request;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;import javax.validation.constraints.NotBlank;
import java.io.Serializable;/*** 用户表** @author WangJiao* @since 2019-12-19*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("用户信息请求")
public class UserReq implements Serializable {private static final long serialVersionUID = 1L;@NotBlank(message = "电话不能为空")@ApiModelProperty(value = "电话", example = "15675454322")private String tel;@NotBlank(message = "密码不能为空")@ApiModelProperty(value = "密码", example = "yyy23")private String password;@NotBlank(message = "确认密码不能为空")@ApiModelProperty(value = "确认密码", example = "yyy23")private String rePassword;@ApiModelProperty(value = "用户头像", example = "http://test.jpg")private String avatar;@NotBlank(message = "用户名不能为空")@ApiModelProperty(value = "姓名", example = "周深")private String name;public static UserReq of() {return new UserReq();}
}
  • 测试方法
 /*** 用户注册** @param req 注册信息* @return obj*/@PostMapping("/register")@ApiOperation("注册")public ApiResult register(@Valid @RequestBody UserReq req){log.info("register:[req:{}]", JSON.toJSONString(req));if (!Objects.equals(req.getPassword(), req.getRePassword())) {return ApiResult.fail(ApiCode.USER_TWO_PASSWORDS_INCONSISTENT);}UserPoJo findUser = service.getByTel(req.getTel());if (Objects.nonNull(findUser)) {return ApiResult.fail(ApiCode.USER_ACCOUNT_REGISTERED);}// md5加密req.setPassword(DigestUtils.md5DigestAsHex(req.getPassword().getBytes()));boolean res = service.save(UserPoJo.of(req));log.info("register:[res:{}]", res);return ApiResult.ok(res);}
}
  • 测试结果:
  • 控制台打印的错误信息如下:
2020-11-24 14:40:36.875 ERROR 21372 [nio-5050-exec-1] y.y.c.c.e.GlobalExceptionHandler         [53] : fieldErrors:[ex:["密码不能为空"]]
org.springframework.web.bind.MethodArgumentNotValidException: Validation failed for argument at index 0 in method: public yooo.yun.com.common.api.ApiResult yooo.yun.com.user.controller.saas.UserController.register(yooo.yun.com.common.entity.request.UserReq), with 1 error(s): [Field error in object 'userReq' on field 'password': rejected value []; codes [NotBlank.userReq.password,NotBlank.password,NotBlank.java.lang.String,NotBlank];arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [userReq.password,password]; arguments []; default message [password]]; default message [密码不能为空]]  at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.resolveArgument(RequestResponseBodyMethodProcessor.java:138) at org.springframework.web.method.support.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java:124) at org.springframework.web.method.support.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java:161) at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:131) at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:102) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:891) at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:991) at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:925) at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:981) at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:884) at javax.servlet.http.HttpServlet.service(HttpServlet.java:661) at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:858) at javax.servlet.http.HttpServlet.service(HttpServlet.java:742) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.boot.actuate.web.trace.servlet.HttpTraceFilter.doFilterInternal(HttpTraceFilter.java:90) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.filterAndRecordMetrics(WebMvcMetricsFilter.java:117) at org.springframework.boot.actuate.metrics.web.servlet.WebMvcMetricsFilter.doFilterInternal(WebMvcMetricsFilter.java:106) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200) at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342) at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800) at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) at java.lang.Thread.run(Thread.java:748) 
  • 全局异常对非法参数异常进行了封装,返回友好的提示给前端:
/*** 非法参数验证异常** @param ex ex* @return res*/@ExceptionHandler(MethodArgumentNotValidException.class)@ResponseStatus(value = HttpStatus.OK)public ApiResult handleMethodArgumentNotValidExceptionHandler(MethodArgumentNotValidException ex) {BindingResult bindingResult = ex.getBindingResult();List<String> list = new ArrayList<>();List<FieldError> fieldErrors = bindingResult.getFieldErrors();for (FieldError fieldError : fieldErrors) {list.add(fieldError.getDefaultMessage());}Collections.sort(list);log.error("fieldErrors:[ex:{}]", JSON.toJSONString(list));return ApiResult.fail(ApiCode.PARAMETER_EXCEPTION, list);}

-_- 到这里,说明你已经get到了喔!需要的小伙伴,快动手练练吧!

微服务架构之全局异常(@ControllerAdvice + @ExceptionHandler)相关推荐

  1. 微服务架构分布式全局唯一ID生成策略及算法

    全局唯一的 ID 几乎是所有系统都会遇到的刚需.这个 id 在搜索, 存储数据, 加快检索速度 等等很多方面都有着重要的意义.工业上有多种策略来获取这个全局唯一的id,针对常见的几种场景,我在这里进行 ...

  2. 没有银弹,微服务架构改造的一条不归路。。。

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 来源:https://www.cnblogs.com/skabyy ...

  3. 可能是全网最通俗易懂的微服务架构改造解读

    古霜卡比 DBAplus社群排版 读完需要 10 分钟 速读仅需 4 分钟 作者介绍 古霜卡比,7年开发和架构经验.喜欢探索新事物.造轮子与瞎折腾.认为与其追逐日新月异的技术,不如研究底层的基础理论. ...

  4. 学习下什么是微服务架构/平台

    本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件.本文侧重于简明地表达微服务架构的全局图景,因此不会涉及具体如何使用组件等细节. 为了防止不提供原网址的转载,特在这 ...

  5. 首席架构师推荐:史上最全微服务架构简史详解!

    本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件.本文侧重于简明地表达微服务架构的全局图景,因此不会涉及具体如何使用组件等细节. 要理解微服务,首先要先理解不是微服 ...

  6. 如何有趣的解释什么是微服务架构

    点击上方"朱小厮的博客",选择"设为星标" 回复"1024"获取独家整理的学习资料 本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什 ...

  7. 微服务架构和相关的组件

    点击上方"芋道源码",选择"设为星标" 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | ...

  8. 超详细解析微服务架构,写得太好了!

    作者:古霜卡比 www.cnblogs.com/skabyy/p/11396571.html 本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件.本文侧重于简明地表达 ...

  9. 微服务架构超详细解析,写得太好了!

    本文将介绍微服务架构和相关的组件,介绍他们是什么以及为什么要使用微服务架构和这些组件.本文侧重于简明地表达微服务架构的全局图景,因此不会涉及具体如何使用组件等细节. 为了防止不提供原网址的转载,特在这 ...

最新文章

  1. C# .net core 解决ToLower中缺少CultureInfo格式重载
  2. 教务查询子系统时序图
  3. uwsgi的log日志中出现错误uWSGI listen queue of socket 4 full。
  4. 新版ADT出现appcompat_v7的问题
  5. eclipse设置自定义快捷键
  6. ext 如何判断是否是整数_Excel表格技巧—如何用ISNUMBER判断是否是数值
  7. JS 常用函数二(改变HTML样式)
  8. C#调用存储过程详解
  9. 两个字段位置相反去重_Flink零基础教程:并行度和数据重分布
  10. ssm上传文件获取路径_ssm框架实现图片上传显示并保存地址到数据库(示例代码)...
  11. unity scence灯光不显示_Unity基础教程系列(四)——多场景(Loading Levels)
  12. python将txt读入矩阵_python读入txt数据,并转成矩阵
  13. 《操作系统》实验报告——进程通信
  14. 晶闸管调压电路的matlab仿真,基于SIMULINK晶闸管调压电路仿真及分析.doc
  15. 基于selenium的大麦网自动抢票脚本实测(新年第一篇)
  16. win7 64 旗舰版虚拟GPU-VMware下+vs2013安装caffe+matlab+python
  17. 5G,仅仅是更快的网速吗?
  18. 设计模式之六大设计原则【入门】
  19. scotland yard
  20. 目标检测算法——GHM

热门文章

  1. React 高阶组件HOC使用总结
  2. python取json数组中的值
  3. 2021-2027全球与中国汽车CMOS图像传感器市场现状及未来发展趋势
  4. 哪来的gou zi 阿龙(最新更新于1.21日)
  5. Docker-----网络模式与资源控制管理
  6. 攻城略地mysql充值_攻城掠地充值有巨惠!平台折扣5.0超划算
  7. 给通信专业研究生——安心完成培养,你不是在劣势下和计算机学生抢饭碗来的
  8. python 通达信板块_通达信如何自定义选股,使用python在通达信里面选股
  9. ffmpeg库 pycharm_python+ffmpeg让字符跳动起来
  10. java苞子_由菌丝末端形成的一种囊状结构的孢子称为