我正在 Spring boot 中制作 RestApi。我尝试添加异常处理,以便客户端获得除 404 之外的有意义的响应。
这是我的 RestController:
@Path("/v1")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
@Slf4j
@Service
@RequiredArgsConstructor
public class UserRestService {
private final UserRepository userRepository;
@GET
@Path("/users/{publicId}")
public RestResponse<UserListItemRestDto> getUserByPublicId(@PathParam("publicId") UUID publicId) {
Optional<User> optionalUser = userRepository.findOneByPublicId(publicId);
if(optionalUser.isEmpty()){
throw new ApiRequestException("CANNOT FIND USER");
}
User user = optionalUser.get();
return RestResponse.of(UserListItemRestDto.builder()
.email(user.getEmail())
.name(user.getName())
.build());
}
...
我的异常处理程序:
@RestControllerAdvice
public class ApiExceptionHandler {
@ExceptionHandler(ApiRequestException.class)
public ResponseEntity<ApiException> handleApiRequestException(ApiRequestException e){
return new ResponseEntity<>(new ApiException(e.getMessage(),
e.getCause(),
HttpStatus.BAD_REQUEST,
ZonedDateTime.now()),HttpStatus.BAD_REQUEST);
}
}
我的自定义异常:
public class ApiRequestException extends RuntimeException{
public ApiRequestException(String message){
super(message);
}
public ApiRequestException(String message, Throwable cause){
super(message,cause);
}
}
当前如果没有用户发现它会抛出异常但不会得到处理。
org.jboss.resteasy.spi.UnhandledException: com.common.rest.exception.ApiRequestException: CANNOT FIND USER
at org.jboss.resteasy.core.ExceptionHandler.handleApplicationException(ExceptionHandler.java:105) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ExceptionHandler.handleException(ExceptionHandler.java:359) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.SynchronousDispatcher.writeException(SynchronousDispatcher.java:218) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:519) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:249) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:60) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:623) ~[tomcat-embed-core-9.0.78.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51) ~[tomcat-embed-websocket-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.29.jar:5.3.29]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.29.jar:5.3.29]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:481) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:390) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:52) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.78.jar:9.0.78]
at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]
Caused by: com.common.rest.exception.ApiRequestException: CANNOT FIND USER
at com.backend.flows.user.rest.UserRestService.getUserByPublicId(UserRestService.java:55) ~[classes/:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:408) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:69) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492) ~[resteasy-core-5.0.0.Final.jar:5.0.0.Final]
... 42 common frames omitted
处理程序是否未扫描,或者我遗漏了注释或配置错误?
这是因为你使用的是 JAX-RS (RESTEasy) 而不是 spring-mvc 来实现 REST API,而
@RestControllerAdvice
是 spring-mvc 的东西,所以 JAX-RS 无法理解它并且没有任何功能是正常的效果。
如何通过JAX-RS方式处理异常,请参考this。