2016-11-15 3 views
2

Я нахожусь в создании REST API с использованием Spring 4 MVC. Я бы хотел, чтобы при запросе недопустимой конечной точки можно было предоставить объект ошибки JSON по умолчанию. Я читал о @ControllerAdvice и @ExceptionHandler, который я попытался использовать правильно:@ControllerAdvice не возвращается ResponseEntity <T> (T является POJO)

package com.yopyop.wackend.controller; 

import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 

import org.springframework.http.HttpHeaders; 
import org.springframework.http.HttpStatus; 
import org.springframework.http.MediaType; 
import org.springframework.http.ResponseEntity; 
import org.springframework.web.bind.annotation.ControllerAdvice; 
import org.springframework.web.bind.annotation.ExceptionHandler; 

import org.springframework.web.context.request.WebRequest; 
import org.springframework.web.servlet.NoHandlerFoundException; 

import com.yopyop.wackend.controller.ErrorResponse; 
import com.yopyop.wackend.service.NotFoundException; 


@ControllerAdvice 
public class ExceptionControllerAdvice { 

    @ExceptionHandler(Exception.class) 
    public ResponseEntity<ErrorResponse> exceptionHandler(Exception ex) { 

     ErrorResponse error = new ErrorResponse(); 
     error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); 

     if (ex.getClass()==NotFoundException.class) { 
      error.setMessage("ExceptionControllerAdvice() Not found"); 
      error.setErrorCode(HttpStatus.NOT_FOUND.value()); 
      return new ResponseEntity<ErrorResponse>(error, HttpStatus.NOT_FOUND); 
     } 
     else { 
      error.setMessage("ExceptionControllerAdvice() " + ex.getClass() + "(" + ex.getMessage() + ")"); 
      error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); 
     } 

     return new ResponseEntity<ErrorResponse>(error, HttpStatus.INTERNAL_SERVER_ERROR); 
    } 

    @ExceptionHandler({NoHandlerFoundException.class}) 
    ResponseEntity<ErrorResponse> handleNoHandlerFoundException(NoHandlerFoundException ex, 
      WebRequest request) { 

     HttpHeaders headers = new HttpHeaders(); 
     headers.setContentType(MediaType.APPLICATION_JSON); 

     ErrorResponse error = new ErrorResponse(); 
     error.setErrorCode(HttpStatus.INTERNAL_SERVER_ERROR.value()); 
     error.setMessage("ExceptionControllerAdvice() " + ex.getClass() + "(" + ex.getMessage() + ")"); 

     return new ResponseEntity<ErrorResponse>(error, HttpStatus.INTERNAL_SERVER_ERROR); 
    } 
} 

Мой класс ErrorResponse выглядит следующим образом:

package com.yopyop.wackend.controller; 

public class ErrorResponse { 
    private int errorCode; 
    private String message; 

    public int getErrorCode() { 
     return errorCode; 
    } 
    public void setErrorCode(int errorCode) { 
     this.errorCode = errorCode; 
    } 
    public String getMessage() { 
     return message; 
    } 
    public void setMessage(String message) { 
     this.message = message; 
    } 
} 

Я изменил web.xml так, что NoHandlerFound исключение:

<!DOCTYPE web-app PUBLIC 
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
"http://java.sun.com/dtd/web-app_2_3.dtd" > 

<web-app> 
    <display-name>Wackend WebApp</display-name> 
    <servlet> 
<servlet-name>wackend</servlet-name> 
<servlet-class> 
    org.springframework.web.servlet.DispatcherServlet 
</servlet-class> 
<init-param> 
    <param-name>throwExceptionIfNoHandlerFound</param-name> 
    <param-value>true</param-value> 
</init-param> 

<load-on-startup>1</load-on-startup> 
</servlet> 

<servlet-mapping> 
<servlet-name>wackend</servlet-name> 
<url-pattern>/</url-pattern> 
</servlet-mapping> 
</web-app> 

Nevetheless, когда запрос на неподключенный конечный получен, я получаю:

> 22:47:28.545 [http-nio-8080-exec-15] DEBUG 
> o.s.web.servlet.DispatcherServlet - DispatcherServlet with name 
> 'wackend' processing GET request for [/wackend/swagger-ui.html] 
> 22:47:28.548 [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.m.a.RequestMappingHandlerMapping - Looking up handler method 
> for path /swagger-ui.html 22:47:28.552 [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.m.a.RequestMappingHandlerMapping - Returning handler method 
> [public void 
> com.yopyop.wackend.controller.DefaultController.unmappedRequest(javax.servlet.http.HttpServletRequest) 
> throws org.springframework.web.servlet.NoHandlerFoundException] 
> 22:47:28.552 [http-nio-8080-exec-15] DEBUG 
> o.s.b.f.s.DefaultListableBeanFactory - Returning cached instance of 
> singleton bean 'defaultController' 22:47:28.553 
> [http-nio-8080-exec-15] DEBUG o.s.web.servlet.DispatcherServlet - 
> Last-Modified value for [/wackend/swagger-ui.html] is: -1 22:47:28.566 
> [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception 
> from handler [public void 
> com.yopyop.wackend.controller.DefaultController.unmappedRequest(javax.servlet.http.HttpServletRequest) 
> throws org.springframework.web.servlet.NoHandlerFoundException]: 
> org.springframework.web.servlet.NoHandlerFoundException: No handler 
> found for GET /wackend/swagger-ui.html, headers={} 22:47:28.567 
> [http-nio-8080-exec-15] DEBUG o.s.b.f.s.DefaultListableBeanFactory - 
> Returning cached instance of singleton bean 
> 'exceptionControllerAdvice' 22:47:28.567 [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Invoking 
> @ExceptionHandler method: 
> org.springframework.http.ResponseEntity<com.yopyop.wackend.controller.ErrorResponse> 
> com.yopyop.wackend.controller.ExceptionControllerAdvice.handleNoHandlerFoundException(org.springframework.web.servlet.NoHandlerFoundException,org.springframework.web.context.request.WebRequest) 
> 22:47:28.603 [http-nio-8080-exec-15] ERROR 
> o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Failed to invoke 
> @ExceptionHandler method: 
> org.springframework.http.ResponseEntity<com.yopyop.wackend.controller.ErrorResponse> 
> com.yopyop.wackend.controller.ExceptionControllerAdvice.handleNoHandlerFoundException(org.springframework.web.servlet.NoHandlerFoundException,org.springframework.web.context.request.WebRequest) 
> org.springframework.web.HttpMediaTypeNotAcceptableException: Could not 
> find acceptable representation at 
> org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:134) 
> ~[spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE] at 
> org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:146) 
> ~[spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE] at 
> org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71) 
> ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE] [...] at 
> java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
> [na:1.8.0_101] at 
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
> [na:1.8.0_101] at 
> org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
> [tomcat-util.jar:8.0.36] at java.lang.Thread.run(Thread.java:745) 
> [na:1.8.0_101] 22:47:28.603 [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Resolving exception 
> from handler [public void 
> com.yopyop.wackend.controller.DefaultController.unmappedRequest(javax.servlet.http.HttpServletRequest) 
> throws org.springframework.web.servlet.NoHandlerFoundException]: 
> org.springframework.web.servlet.NoHandlerFoundException: No handler 
> found for GET /wackend/swagger-ui.html, headers={} 22:47:28.603 
> [http-nio-8080-exec-15] DEBUG o.s.b.f.s.DefaultListableBeanFactory - 
> Returning cached instance of singleton bean 
> 'exceptionControllerAdvice' 22:47:28.603 [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Invoking 
> @ExceptionHandler method: 
> org.springframework.http.ResponseEntity<com.yopyop.wackend.controller.ErrorResponse> 
> com.yopyop.wackend.controller.ExceptionControllerAdvice.handleNoHandlerFoundException(org.springframework.web.servlet.NoHandlerFoundException,org.springframework.web.context.request.WebRequest) 
> 22:47:28.604 [http-nio-8080-exec-15] ERROR 
> o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver - Failed to invoke 
> @ExceptionHandler method: 
> org.springframework.http.ResponseEntity<com.yopyop.wackend.controller.ErrorResponse> 
> com.yopyop.wackend.controller.ExceptionControllerAdvice.handleNoHandlerFoundException(org.springframework.web.servlet.NoHandlerFoundException,org.springframework.web.context.request.WebRequest) 
> org.springframework.web.HttpMediaTypeNotAcceptableException: Could not 
> find acceptable representation at 
> org.springframework.web.servlet.mvc.method.annotation.AbstractMessageConverterMethodProcessor.writeWithMessageConverters(AbstractMessageConverterMethodProcessor.java:134) 
> ~[spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE] at 
> org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor.handleReturnValue(HttpEntityMethodProcessor.java:146) 
> ~[spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE] at 
> org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite.handleReturnValue(HandlerMethodReturnValueHandlerComposite.java:71) 
> ~[spring-web-4.1.6.RELEASE.jar:4.1.6.RELEASE]  at 
> org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:126) 
> ~[spring-webmvc-4.1.6.RELEASE.jar:4.1.6.RELEASE] [...] at 
> java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
> [na:1.8.0_101] at 
> org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) 
> [tomcat-util.jar:8.0.36] at java.lang.Thread.run(Thread.java:745) 
> [na:1.8.0_101] 22:47:28.604 [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.a.ResponseStatusExceptionResolver - Resolving exception from 
> handler [public void 
> com.yopyop.wackend.controller.DefaultController.unmappedRequest(javax.servlet.http.HttpServletRequest) 
> throws org.springframework.web.servlet.NoHandlerFoundException]: 
> org.springframework.web.servlet.NoHandlerFoundException: No handler 
> found for GET /wackend/swagger-ui.html, headers={} 22:47:28.604 
> [http-nio-8080-exec-15] DEBUG 
> o.s.w.s.m.s.DefaultHandlerExceptionResolver - Resolving exception from 
> handler [public void 
> com.yopyop.wackend.controller.DefaultController.unmappedRequest(javax.servlet.http.HttpServletRequest) 
> throws org.springframework.web.servlet.NoHandlerFoundException]: 
> org.springframework.web.servlet.NoHandlerFoundException: No handler 
> found for GET /wackend/swagger-ui.html, headers={} 22:47:28.604 
> [http-nio-8080-exec-15] DEBUG o.s.web.servlet.DispatcherServlet - Null 
> ModelAndView returned to DispatcherServlet with name 'wackend': 
> assuming HandlerAdapter completed request handling 22:47:28.604 
> [http-nio-8080-exec-15] DEBUG o.s.web.servlet.DispatcherServlet - 
> Successfully completed request 

, а затем возвращается стандартная страница Tomcat 404. Пожалуйста, не то, что:

  1. возвращение новый ResponseEntity (ошибка, HttpStatus.INTERNAL_SERVER_ERROR);

    возвращает HTTP 500 с пустым телом (лучше, чем страницы Tomcat по умолчанию)

  2. возвращение новый ResponseEntity ("Woot", HttpStatus.INTERNAL_SERVER_ERROR); вернет HTTP 500 с woot как тело.

Похоже, что сопоставление JSON не может быть выполнено с моим классом ErrorResponse.

Кроме того, я использую контроллер по умолчанию, но я думаю, что это бесполезно, так как я использую @ControllerAdvice. Я вставить здесь для информации:

package com.yopyop.wackend.controller; 

import javax.servlet.http.HttpServletRequest; 

import org.springframework.http.HttpHeaders; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.servlet.NoHandlerFoundException; 

/** 
* Default controller that exists to return a proper REST response for unmapped requests. 
*/ 
@Controller 
public class DefaultController { 

    @RequestMapping("/**") 
    public void unmappedRequest(HttpServletRequest request) throws NoHandlerFoundException { 
     String uri = request.getRequestURI(); 
     String method = request.getMethod(); 
     HttpHeaders h = new HttpHeaders(); 

     throw new NoHandlerFoundException(method, uri, h); 
    } 
} 

Мой REST API также использует ResponseEntity <> возвращает и преуспевает в возвращении собственных полезных нагрузок JSON.

ответ

0

Я не знаю, что именно ответ, но, возможно, проблема в конфигурации JSON. Сначала ваш @Controller не является @RestController, и вы не указываете явно, что производится. Надеюсь, вы сделаете это в своем запросе, поэтому весна знает, что делать. Я думаю, что тип mime из @Controller наследуется и используется для преобразования.

Вы можете попытаться добавить точку останова в свой конвертер сообщений HTTP. В каждом конверторе есть mathod supports попробуйте поймать ваш код здесь. Проверьте, какой преобразователь возвращается true. Весна использует первый, если более чем один передает условия. Вы также можете найти, какие конвертеры доступны для вашего запроса и какой конвертер требуется.

http://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/http/converter/AbstractHttpMessageConverter.html#supports-java.lang.Class-

Смежные вопросы