简体   繁体   中英

@ExceptionHandler response not working in Tomcat

I'm working to handle exceptions with Spring MVC. I'm using @ControllerAdvice and @ExceptionHandler. In order to return a JSON I tried both cases: @ResponseBody and ResponseEntity.

Here is my Controller:

@ControllerAdvice
public class GlobalExceptionController {

@ExceptionHandler(CustomGenericException.class)
@ResponseBody
public ErrorResource handleCustomException(CustomGenericException ex) {

        ErrorResource errorResource=new ErrorResource("Example 1");
    errorResource.error=ex.getErrCode();

    return errorResource;

}

@ExceptionHandler(Exception.class)
public ResponseEntity<ErrorResource> handleAllException(Exception ex) {

    ErrorResource errorResource=new ErrorResource("Example 2");
    errorResource.error=ex.getMessage();

    return new ResponseEntity<ErrorResource>(errorResource,HttpStatus.NOT_FOUND);

}

}
class ErrorResource {
public String error;

public ErrorResource(String a ){error=a;}
}

I'm using the tomcat 7 plugin for maven to run and debug the app, so when I debug I can see that the @ExceptionHandler is firing and executing the return statement. But instead of receiving a JSON what I'm getting is an HTTP 500 error:

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is com.mkyong.web.exception.CustomGenericException
org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:979)
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:858)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843)
javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)

If I return a view or a ModelView is working, but whenever I try to return a ResponseBody or ResponseEntity, I'm still getting the same error.

Finally, if instead of using tomcat, I use SpringBoot to run the app, I'm not getting the error and I'm response as I supposed to receive:

{"error":"E888"}

Why is not working with Tomcat?

Thanks.

The reason is the way Spring handle the exception. In plain Spring application without Boot @ExceptionHandler is used by exceptionResolver and it works for browser user or in other words it is thinked for render page when an exception arrives. The flow of the your request don't pass through the contenNegotiationResolver and for this reason you continue to get the exception. In Spring boot the fow of the life-cycle of the request was thinked for manage exception for browser user and not-browser-user like application, and for this reason it works, I can suggest of refers to the official documentation for more details.

Update for to answer at a comment.

In Spring boot you manage the exception in very different way respect plain spring mvc application for many details i suggest to se the documentation at link spring boot doc . If you want use a plain spring web application I can suggest to use an aspect. You could use the plain @ExceptionHandler usage and return a ModelView implementation in answer for the plain page request in @Controller Class without @ResponseBody and create an aspect with a that manage the exception for method annotated with @ResponseBody and that returned ResponseEntity. Thew aspect could be a think like below, note that in this sample I developed the poincut expression for intercept the methods that return an ResponseEntity under com.springapp.mvc package:

Aspect:

@Aspect
@Component
public class GlobalExceptionRestAOPController {


    private ObjectMapper objectMapper = new ObjectMapper();

    @Around("execution(org.springframework.http.ResponseEntity com.springapp.mvc..*(..))")
    public Object manageException(ProceedingJoinPoint pjp) throws Throwable{
        Object result;
        try{
            result = pjp.proceed();
        } catch (Exception e){
            // log it.
                       result = ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).contentType(MediaType.APPLICATION_JSON).body(objectMapper.writeValueAsString(new ExceptionReport(e.toString())));

        }

        return result;
    }
}

class ExceptionReport{
    private final String error;

    public ExceptionReport(String error) {
        this.error = error;
    }

    public String getError() {
        return error;
    }
}

don't forgot of insert in your configuration

xml style:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <aop:aspectj-autoproxy/>

    <context:component-scan base-package="com.springapp.mvc"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

...
</beans>    

Java style:

@Configuration
@EnableAspectJAutoProxy
...
class AspectConfiguration{
...
}

controller:

@Controller
public class HelloController {


    @RequestMapping(value = "/jsonHelloEx", method = RequestMethod.GET, produces = "application/json")
    public ResponseEntity printWelcomeWithException() {
        String nullableString = null;
        nullableString.equals("");
        return ResponseEntity.ok("Hello");
    }
}

I hope that it can help you

@ExceptionHandler method doesn't have a @ResponseBody return type it can only return a ModelView or a String which is translated to a view

The return type can be a String, which is interpreted as a view name or a ModelAndView object.

see here for more information: Spring @ExceptionHandler does not work with @ResponseBody

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM