2010-01-14 34 views
154

¿Cómo obtengo un controlador Spring 3.0 para activar un 404?Disparador 404 en controlador Spring-MVC?

que tienen un controlador con @RequestMapping(value = "/**", method = RequestMethod.GET) y por alguna URLs acceder al controlador, quiero que el recipiente para llegar a un 404.

Respuesta

270

Desde Spring 3.0 también se puede generar una excepción declarada con @ResponseStatus anotación:

@ResponseStatus(value = HttpStatus.NOT_FOUND) 
public class ResourceNotFoundException extends RuntimeException { 
    ... 
} 

@Controller 
public class SomeController { 
    @RequestMapping..... 
    public void handleCall() { 
     if (isFound()) { 
      // whatever 
     } 
     else { 
      throw new ResourceNotFoundException(); 
     } 
    } 
} 
+2

Interesante. ¿Puedes especificar qué HttpStatus usar en el sitio de lanzamiento (es decir, no tenerlo compilado en la clase Excepción)? –

+1

@mattb: Creo que el objetivo de '@ ResponseStatus' es que defina un conjunto completo de clases de excepción bien tipadas y fuertemente tipadas, cada una con su propio' @ ResponseStatus'. De esta forma, desacoplarás tu código de controlador del detalle de los códigos de estado HTTP. – skaffman

+0

Ya veo. Idea bastante clara. ¡Necesito comenzar a usar las modificaciones de 3.0 y aprender todo esto bondad! –

29

Vuelva a escribir su método de firma para que acepte HttpServletResponse como parámetro, para que pueda llama al setStatus(int) en él.

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-arguments

+3

Esta es la única respuesta correcta si alguien está buscando una forma de decirle al solicitante HTTP que cometió un error al no inundar al equipo de prod ops con un montón de excepciones que no pueden solucionar. –

+1

'setStatus (int)' javadoc establece de la siguiente manera: Si este método se usa para establecer un código de error, entonces el mecanismo de la página de error del contenedor no se activará. Si hay un error y la persona que llama desea invocar una página de error definida en la aplicación web, se debe usar 'sendError' en su lugar. –

23

me gustaría mencionar que hay una excepción (no sólo) para 404 por defecto proporcionada por el resorte. Vea Spring documentation para más detalles. Así que si usted no necesita su propia excepción puede simplemente hacer esto:

@RequestMapping(value = "/**", method = RequestMethod.GET) 
public ModelAndView show() throws NoSuchRequestHandlingMethodException { 
    if(something == null) 
     throw new NoSuchRequestHandlingMethodException("show", YourClass.class); 

    ... 

    } 
+9

Esto parece estar destinado a un caso específico, cuando Spring no puede encontrar un controlador. El caso en cuestión es cuando Spring * puede * encontrar un controlador, pero el usuario quiere devolver un 404 por otro motivo. –

+2

Lo estoy usando cuando mi mapeo ulr para el método del manejador es dinámico. Cuando la entidad no existe basada en '@ PathVariable', no existe un manejo de solicitudes desde mi punto de vista. ¿Crees que es mejor/más limpio usar tu propia excepción anotada con '@ResponseStatus (value = HttpStatus.NOT_FOUND) '? –

+1

En su caso, parece correcto, pero no sé si recomendaría las excepciones que se encuentran en el enlace que proporcionó para manejar todos los casos en que sea necesaria una excepción, a veces debe hacer la suya propia. –

0

Simplemente puede utilizar web.xml para agregar el código de error y la página de error 404. Pero asegúrese de que la página de error 404 no se ubique en WEB-INF.

<error-page> 
    <error-code>404</error-code> 
    <location>/404.html</location> 
</error-page> 

Esta es la forma más sencilla de hacerlo, pero esto tiene algunas limitaciones. Supongamos que si desea agregar el mismo estilo para esta página que ha agregado otras páginas. De esta manera no puedes hacerlo. Usted tiene que utilizar el @ResponseStatus(value = HttpStatus.NOT_FOUND)

+0

Esta es la forma de hacerlo, pero considere con 'HttpServletResponse # sendError (HttpServletResponse.SC_NOT_FOUND); return null; 'del código del controlador. Ahora desde el exterior, la respuesta no se ve diferente a un 404 normal que no golpeó ningún controlador. –

+0

esto no desencadena un 404, simplemente lo maneja si ocurre –

8

Si su método de control es algo así como el manejo de entonces ResponseEntity archivo es muy práctico:

@Controller 
public class SomeController { 
    @RequestMapping..... 
    public ResponseEntity handleCall() { 
     if (isFound()) { 
      return new ResponseEntity(...); 
     } 
     else { 
      return new ResponseEntity(404); 
     } 
    } 
} 
0

Configurar web.xml con el establecimiento de

<error-page> 
    <error-code>500</error-code> 
    <location>/error/500</location> 
</error-page> 

<error-page> 
    <error-code>404</error-code> 
    <location>/error/404</location> 
</error-page> 

Crear nuevo controlador

/** 
    * Error Controller. handles the calls for 404, 500 and 401 HTTP Status codes. 
    */ 
    @Controller 
    @RequestMapping(value = ErrorController.ERROR_URL, produces = MediaType.APPLICATION_XHTML_XML_VALUE) 
    public class ErrorController { 


     /** 
     * The constant ERROR_URL. 
     */ 
     public static final String ERROR_URL = "/error"; 


     /** 
     * The constant TILE_ERROR. 
     */ 
     public static final String TILE_ERROR = "error.page"; 


     /** 
     * Page Not Found. 
     * 
     * @return Home Page 
     */ 
     @RequestMapping(value = "/404", produces = MediaType.APPLICATION_XHTML_XML_VALUE) 
     public ModelAndView notFound() { 

      ModelAndView model = new ModelAndView(TILE_ERROR); 
      model.addObject("message", "The page you requested could not be found. This location may not be current."); 

      return model; 
     } 

     /** 
     * Error page. 
     * 
     * @return the model and view 
     */ 
     @RequestMapping(value = "/500", produces = MediaType.APPLICATION_XHTML_XML_VALUE) 
     public ModelAndView errorPage() { 
      ModelAndView model = new ModelAndView(TILE_ERROR); 
      model.addObject("message", "The page you requested could not be found. This location may not be current, due to the recent site redesign."); 

      return model; 
     } 
} 
12

puede usar el @ControllerAdvice para manejar sus excepciones, El comportamiento predeterminado de la clase anotada @ControllerAdvice ayudará a todos los Controladores conocidos.

por lo que será invocado cuando cualquier Controlador haya arrojado el error 404.

como la siguiente:

@ControllerAdvice 
class GlobalControllerExceptionHandler { 
    @ResponseStatus(HttpStatus.NOT_FOUND) // 404 
    @ExceptionHandler(Exception.class) 
    public void handleNoTFound() { 
     // Nothing to do 
    } 
} 

y el mapa de este error de respuesta 404 en su web.xml, como la siguiente:

<error-page> 
     <error-code>404</error-code> 
     <location>/Error404.html</location> 
</error-page> 

espero que ayude.

+2

ha asignado excepciones de tipo Excepción (y subclases) con un código de estado 404. ¿Alguna vez pensaste que hay errores internos en el servidor? ¿Cómo planeas manejarlos en tu GlobalControllerExceptionHandler? – rohanagarwal

+0

Esto NO funcionó para los controladores REST, devuelve una respuesta vacía. – rustyx

13

Desde Spring 3.0.2 puede devolver ResponseEntity<T> como resultado del método del controlador:

@RequestMapping..... 
public ResponseEntity<Object> handleCall() { 
    if (isFound()) { 
     // do what you want 
     return new ResponseEntity<>(HttpStatus.OK); 
    } 
    else { 
     return new ResponseEntity<>(HttpStatus.NOT_FOUND); 
    } 
} 

(ResponseEntity <T> es una anotación más flexible que @ResponseBody - ver another question)

+0

of-course flexible, pero anula los beneficios de la programación declarativa – rohanagarwal

4

te recomiendo tirar HttpClientErrorException, como este

@RequestMapping(value = "/sample/") 
public void sample() { 
    if (somethingIsWrong()) { 
     throw new HttpClientErrorException(HttpStatus.NOT_FOUND); 
    } 
} 

Debe recordar que esto se puede hacer solo antes de que se escriba nada al servlet flujo de salida.

+2

Esa excepción la arroja el cliente Spring HTTP. Spring MVC parece no reconocer esa excepción. ¿Qué versión de primavera estás usando? ¿Estás obteniendo un 404 con esa excepción? – Eduardo

+0

Esto hace que Spring Boot regrese: 'Whitelabel Error Page \ n .... \ n Hubo un error inesperado (tipo = Internal Server Error, status = 500). \ n 404 Este es el error no encontrado' – slim

+0

Esta es una excepción para un cliente HTTP, no para un controlador. Entonces usarlo en el contexto especificado es inapropiado. – Alexey

5

Si bien la respuesta correcta es correcta, hay una manera de lograr esto sin excepciones. El servicio está devolviendo Optional<T> del objeto buscado y esto se asigna a HttpStatus.OK si se encuentra y a 404 si está vacío.

@Controller 
public class SomeController { 

    @RequestMapping..... 
    public ResponseEntity<Object> handleCall() { 
     return service.find(param).map(result -> new ResponseEntity<>(result, HttpStatus.OK)) 
       .orElse(new ResponseEntity<>(HttpStatus.NOT_FOUND)); 
    } 
} 

@Service 
public class Service{ 

    public Optional<Object> find(String param){ 
     if(!found()){ 
      return Optional.empty(); 
     } 
     ... 
     return Optional.of(data); 
    } 

} 
1

Además, si desea volver estado 404 desde su controlador único que necesita es hacer esto

@RequestMapping(value = "/somthing", method = RequestMethod.POST) 
@ResponseBody 
public HttpStatus doSomthing(@RequestBody String employeeId) { 
    try{ 
    return HttpStatus.OK; 
    } 
    catch(Exception ex){ 
    return HttpStatus.NOT_FOUND; 
    } 
} 

Al hacer esto, recibirá un error 404 en el caso cuando se desea devolver un 404 desde tu controlador.

Cuestiones relacionadas