Spring 引导 - Jackson EntityNotFoundException returns 200 而不是 500 响应

Spring Boot - Jackson EntityNotFoundException returns 200 instead of 500 response

异常处理程序是 returning 200 响应,即使我在遇到此异常时已在处理程序 (HttpStatus.INTERNAL_SERVER_ERROR) 中将其指定为 return 500。

我正在使用 Spring Boot v1.5.4.RELEASE.

我正在调用一个 Spring 引导服务 returning 一个 JSON 对象。我正在使用自定义异常处理程序。

当在反序列化期间发生 EntityNotFoundException 时,它不会 returning 500 响应,而是 returns 200 响应并将错误嵌入正文输出中。这是由数据错误引起的,由于外键无效,在数据库中找不到 ManyToOne 关系。

请注意,我使用本机查询来提取实体。

@Entity
@Table(name = "PARENT_ENTITY")
public class ParentEntity {

    @JsonView({MyViews.ParentEntity.class})
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name="CHILD_KEY")
    protected ChildEntity childKey; 
   
}

我怎样才能使服务 return 的响应是 500 而不是 200?

代码示例:

@ControllerAdvice
public class RestExceptionHandler extends ResponseEntityExceptionHandler{

  @ExceptionHandler(EntityNotFoundException.class)
  @ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR, reason = "INTERNAL_SERVER_ERROR")      
  protected ResponseEntity<Object> handleEntityNotFoundException(EntityNotFoundException ex) {
       
    ApiError apiError = new ApiError(HttpStatus.INTERNAL_SERVER_ERROR);
    apiError.setMessage(ex.getMessage());      
    apiError.setStackTrace(StringUtil.jsonEscapeNewlines(ExceptionUtils.getStackTrace(ex)));  
    return new ResponseEntity<>(apiError, apiError.getStatus())        
  }
}

服务输出示例:

响应代码:200

正文:

[
    {
        "field1": "data1",
        "childEntity": {
            "childKey":"100100"
        }       
    },
    {
        "field1":"data2"
        "childEntity": {
            "childKey": {
                "status": "INTERNAL_SERVER_ERROR",                  
                "message": "Could not write JSON: Unable to find com.test.entity.ChildEntity with id 123456; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Unable to find com.test.entity.ChildEntity with id 123456;        (through reference chain: java.util.ArrayList[40]->com.test.entity.ParentEntity[\"childKey\"])",                    
                "stackTrace": "org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Unable to find com.test.entity.ChildEntity with id 123456       ; nested exception is com.fasterxml.jackson.databind.JsonMappingException: ... org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:299)
                at org.springframework.http.converter.AbstractGenericHttpMessageConverter.write(AbstractGenericHttpMessageConverter.java:106)
                at org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:231)
                at org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor.handleReturnValue(RequestResponseBodyMethodProcessor.java:174)
                at org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:81)
                at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:113)
                at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
                at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
                at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
                at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:967)
                at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:901)
                at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:970)
                at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:872)
                at javax.servlet.http.HttpServlet.service(HttpServlet.java:751)
                at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:846)
                at javax.servlet.http.HttpServlet.service(HttpServlet.java:844)
                at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:280)
                at weblogic.servlet.internal.StubSecurityHelper$ServletServiceAction.run(StubSecurityHelper.java:254)
                at weblogic.servlet.internal.StubSecurityHelper.invokeServlet(StubSecurityHelper.java:136)
                at weblogic.servlet.internal.ServletStubImpl.execute(ServletStubImpl.java:346)
                at weblogic.servlet.internal.TailFilter.doFilter(TailFilter.java:25)
                at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
                at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:115)
                at org.springframework.boot.web.support.ErrorPageFilter.access[=14=]0(ErrorPageFilter.java:59)
                at org.springframework.boot.web.support.ErrorPageFilter.doFilterInternal(ErrorPageFilter.java:90)
                at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                at org.springframework.boot.web.support.ErrorPageFilter.doFilter(ErrorPageFilter.java:108)
                at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
                at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:81)
                at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
                at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:105)
                at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
                at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)
                at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
                at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
                at oracle.security.jps.ee.http.JpsAbsFilter.run(JpsAbsFilter.java:137)
                at java.security.AccessController.doPrivileged(Native Method)
                at oracle.security.jps.util.JpsSubject.doAsPrivileged(JpsSubject.java:315)
                at oracle.security.jps.ee.util.JpsPlatformUtil.runJaasMode(JpsPlatformUtil.java:460)
                at oracle.security.jps.ee.http.JpsAbsFilter.runJaasMode(JpsAbsFilter.java:120)
                at oracle.security.jps.ee.http.JpsAbsFilter.doFilter(JpsAbsFilter.java:217)
                at oracle.security.jps.ee.http.JpsFilter.doFilter(JpsFilter.java:81)
                at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
                at oracle.dms.servlet.DMSServletFilter.doFilter(DMSServletFilter.java:220)
                at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:79)
                at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.wrapRun(WebAppServletContext.java:3456)
                at weblogic.servlet.internal.WebAppServletContext$ServletInvocationAction.run(WebAppServletContext.java:3422)
                at weblogic.security.acl.internal.AuthenticatedSubject.doAs(AuthenticatedSubject.java:323)
                at weblogic.security.service.SecurityManager.runAs(SecurityManager.java:120)
                at weblogic.servlet.provider.WlsSubjectHandle.run(WlsSubjectHandle.java:57)
                at weblogic.servlet.internal.WebAppServletContext.doSecuredExecute(WebAppServletContext.java:2280)
                at weblogic.servlet.internal.WebAppServletContext.securedExecute(WebAppServletContext.java:2196)
                at weblogic.servlet.internal.WebAppServletContext.execute(WebAppServletContext.java:2174)
                at weblogic.servlet.internal.ServletRequestImpl.run(ServletRequestImpl.java:1632)
                at weblogic.servlet.provider.ContainerSupportProviderImpl$WlsRequestExecutor.run(ContainerSupportProviderImpl.java:256)
                at weblogic.work.ExecuteThread.execute(ExecuteThread.java:311)
                at weblogic.work.ExecuteThread.run(ExecuteThread.java:263)
            Caused by: com.fasterxml.jackson.databind.JsonMappingException: Unable to find com.test.entity.ChildEntity with id 123456;
                at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:388)
                at com.fasterxml.jackson.databind.JsonMappingException.wrapWithPath(JsonMappingException.java:348)
                at com.fasterxml.jackson.databind.ser.std.StdSerializer.wrapAndThrow(StdSerializer.java:343)
                at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:698)
                at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
                at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serializeContents(CollectionSerializer.java:149)
                at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:112)
                at com.fasterxml.jackson.databind.ser.std.CollectionSerializer.serialize(CollectionSerializer.java:25)
                at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:416)
                at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1425)
                at com.fasterxml.jackson.databind.ObjectWriter.writeValue(ObjectWriter.java:951)
                at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.writeInternal(AbstractJackson2HttpMessageConverter.java:292)
                ... 58 more\
            Caused by: javax.persistence.EntityNotFoundException: Unable to find com.test.entity.ChildEntity with id 123456;
                at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$JpaEntityNotFoundDelegate.handleEntityNotFound(EntityManagerFactoryBuilderImpl.java:144)
                at org.hibernate.proxy.AbstractLazyInitializer.checkTargetState(AbstractLazyInitializer.java:242)
                at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:159)
                at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:266)
                at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:73)
                at com.test.entity.ParentEntity_$$_jvst2de_11.getChildKey(ParentEntity_$$_jvst2de_11.java)
                at com.test.entity.ParentEntity.getChildKey(ParentEntity.java:887)
                at sun.reflect.GeneratedMethodAccessor5472.invoke(Unknown Source)
                at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
                at java.lang.reflect.Method.invoke(Method.java:498)
                at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:664)
                at com.fasterxml.jackson.databind.ser.impl.FilteredBeanPropertyWriter$SingleView.serializeAsField(FilteredBeanPropertyWriter.java:69)
                at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:690)
                ... 66 more\
            ",
                "headers": null
            }

#note:我并没有为了这个例子而把它剪掉。这在实际 json 响应中被切断,导致格式错误 json.

我想知道您的请求是否由同一个异常处理程序处理。

您已将用户消息设置为“数据问题”,但您的输出响应显示为空。

apiError.setUserMessage("Data issue:" + ex.getMessage());


//based on your code it should have at least "Data issue:"
"userMessage": null,

请确保验证您发布的代码是否作为此请求的一部分被调用。当然,您可以添加一条日志消息来确认这一点。如果您能够在本地复制问题,那么您可以保留一个断点并确认是否调用了相同的异常处理程序。

您可以通过在查询中进行内连接来避免找不到实体的错误。下面的示例使用本机查询格式。这更像是一种变通解决方案,但足以解决我的问题。我暂时标记为答案。

select pe.* from PARENT_ENTITY pe 
inner join CHILD_ENTITY ce on pe.CHILD_KEY = ce.rowid_org_cust