Spring Boot-Jackson EntityNotFoundException返回200而不是500响应

时间:2020-10-21 22:43:45

标签: java spring-boot hibernate jackson weblogic

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

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

我正在调用Spring Boot服务并返回JSON对象。我正在使用自定义异常处理程序。

在反序列化期间发生EntityNotFoundException时,它不返回500响应,而是返回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; 
   
}

如何做到这一点,以便该服务返回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$000(ErrorPageFilter.java:59)
                at org.springframework.boot.web.support.ErrorPageFilter$1.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$1.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格式错误。

2 个答案:

答案 0 :(得分:0)

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

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

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


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

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

答案 1 :(得分:0)

您可以通过在查询中进行内部联接来避免未找到实体错误。下面的示例使用本机查询格式。这更像是一种解决方法,但足以解决我的情况。我现在将其标记为答案。

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