微服务架构之全局异常处理
- 一、定义全局异常处理类(GlobalExceptionHandler)
- 二、测试未使用全局异常捕捉方法异常
- 三、测试使用全局异常捕捉方法异常
- 四、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;
@Override
public 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;
@Override
public 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到了喔!需要的小伙伴,快动手练练吧!