2010-01-14 3 views

ответ

270

С весной 3.0 вы также можете выбросить исключение объявленного с @ResponseStatus аннотацию:

@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

Интересно. Можете ли вы указать, какой HttpStatus использовать на сайте throw (т. Е. Не скомпилировать его в класс Exception)? –

+1

@mattb: Я думаю, что точка '@ ResponseStatus' заключается в том, что вы определяете целую группу строго типизированных, хорошо названных классов исключений, каждый со своим собственным' @ ResponseStatus'. Таким образом, вы отделите свой код контроллера от деталей кодов состояния HTTP. – skaffman

+0

Я вижу. Довольно опрятная идея. Мне нужно начать использовать аннотации 3.0 и узнать все это добро! –

29

Перепишите ваш метод подписи так, что он принимает HttpServletResponse в качестве параметра, так что вы можете позвоните по телефону setStatus(int).

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

+3

Это единственный правильный ответ, если кто-то ищет способ сообщить http-запросу, что совершил ошибку, не наводя команду prod ops кучей исключений, которые они не могут исправить. –

+1

'setStatus (int)' javadoc утверждает следующее: Если этот метод используется для установки кода ошибки, тогда механизм страницы ошибки контейнера не будет запущен. Если есть ошибка, и вызывающий объект хочет вызвать страницу ошибки, определенную в веб-приложении, вместо этого следует использовать 'sendError'. –

23

Я хотел бы отметить, что есть исключения (и не только) для 404 по умолчанию, представленного весна. См. Spring documentation. Так что, если вам не нужно собственное исключение, вы можете просто сделать это:

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

    ... 

    } 
+9

Это похоже на конкретный случай - когда Spring не может найти обработчик. Дело в том, что Spring * может * найти обработчик, но пользователь хочет вернуть 404 по другой причине. –

+2

Я использую его, когда мое отображение ulr для метода обработчика является динамическим. Когда сущность не существует на основе '@ PathVariable', с моей точки зрения не обрабатывается запрос. Считаете ли вы, что лучше/чище использовать собственное Exception, аннотированное с помощью @ @ResponseStatus (value = HttpStatus.NOT_FOUND) '? –

+1

В вашем случае это звучит прекрасно, но я не знаю, что я бы рекомендовал исключения, найденные в ссылке, которую вы предоставили, чтобы обрабатывать все случаи, когда необходимо исключение - иногда вы должны сделать свой собственный. –

0

Просто вы можете использовать web.xml добавить код ошибки и страницу 404 ошибки. Но убедитесь, что страница ошибки 404 не должна находиться под WEB-INF.

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

Это самый простой способ сделать это, но у этого есть некоторые ограничения. Предположим, если вы хотите добавить тот же стиль для этой страницы, что и другие страницы. Таким образом, вы не можете этого сделать. Вы должны использовать @ResponseStatus(value = HttpStatus.NOT_FOUND)

+0

Это способ сделать это, но рассмотрите с ним 'HttpServletResponse # sendError (HttpServletResponse.SC_NOT_FOUND); return null; 'из кода контроллера. Теперь со стороны ответ не похож на обычный 404, который не попал ни в один контроллер. –

+0

это не вызывает 404, он просто обрабатывает его, если происходит –

8

Если ваш метод контроллер что-то вроде обработки, то ResponseEntity файл очень удобно:

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

Настройка web.xml с установкой

<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> 

Создать новый контроллер

/** 
    * 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

Вы можете использовать @ControllerAdvice для обработки ваших исключений, Поведение по умолчанию, которое аннотированный класс @ControllerAdvice поможет всем известным контроллерам.

поэтому он будет вызываться, если у любого контроллера, у которого есть ошибка 404.

как следующее:

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

и отобразить эту ошибку 404 ответа в вашем web.xml, как следующее:

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

Надежда, что помогает.

+2

. Вы указали исключения типа Exception (и подклассы) с кодом состояния 404. Вы когда-нибудь думали, что есть внутренние ошибки сервера? Как вы планируете обрабатывать данные в своем GlobalControllerExceptionHandler? – rohanagarwal

+0

Это НЕ работало для контроллеров REST, возвращает пустой ответ. – rustyx

13

С весны 3.0.2 вы можете вернуть ResponseEntity<T> в результате метода контроллера:

@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> является более гибким, чем @ResponseBody аннотации - см another question)

+0

гибкий курс, но побеждает преимущества декларативного программирования – rohanagarwal

4

Я бы рекомендовал бросать HttpClientErrorException, например,

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

Вы должны помнить, что это можно сделать только до того, как все будет записано в сервлет выходной поток.

+2

Это исключение вызывается Spring HTTP-клиентом. Spring MVC, похоже, не признает это исключение. Какую версию Spring вы используете? Вы получаете 404 с этим исключением? – Eduardo

+0

Это приводит к возврату Spring Boot: 'Ошибка страницы Whitelabel \ n .... \ n Произошла непредвиденная ошибка (type = Internal Server Error, status = 500). \ n 404 Это ваша ошибка: – slim

+0

Это исключение для HTTP-клиента, а не для контроллера. Поэтому использование в указанном контексте неуместно. – Alexey

5

Хотя отмеченный ответ верный, существует способ достижения этого без исключений. Служба возвращает Optional<T> объекта поиска, и он отображается в HttpStatus.OK, если найден, и до 404, если пустой.

@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

Кроме того, если вы хотите вернуть 404 статус из контроллера все, что вам нужно сделать, это

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

Делая это, вы получите сообщение об ошибке 404 в случае, если вы хотите, чтобы вернуть 404 от вашего контроллера.