Как получить контроллер Spring 3.0 для запуска 404?
У меня есть контроллер, @RequestMapping(value = "/**", method = RequestMethod.GET)
и для некоторых URL-адресов, обращающихся к контроллеру, я хочу, чтобы контейнер выдал 404.
Как получить контроллер Spring 3.0 для запуска 404?
У меня есть контроллер, @RequestMapping(value = "/**", method = RequestMethod.GET)
и для некоторых URL-адресов, обращающихся к контроллеру, я хочу, чтобы контейнер выдал 404.
Ответы:
Начиная с Spring 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();
}
}
}
@ResponseStatus
том, что вы определяете целую кучу строго типизированных, хорошо названных классов исключений, каждый со своим собственным @ResponseStatus
. Таким образом, вы отделяете код контроллера от подробностей кодов состояния HTTP.
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Your reason")
ResourceNotFound.fillInStackTrace()
пустую реализацию.
Начиная с Spring 5.0, вам не обязательно создавать дополнительные исключения:
throw new ResponseStatusException(NOT_FOUND, "Unable to find resource");
Кроме того, вы можете охватить несколько сценариев одним встроенным исключением, и у вас будет больше контроля.
Узнать больше:
Перепишите сигнатуру вашего метода, чтобы он принимался HttpServletResponse
в качестве параметра, чтобы вы могли вызывать setStatus(int)
его.
setStatus(int)
Javadoc заявляет следующее: Если этот метод используется для установки кода ошибки, то механизм страницы ошибок контейнера не будет запущен. Если есть ошибка, и вызывающая сторона желает вызвать страницу ошибки, определенную в веб-приложении, то sendError
должна использоваться вместо этого.
Я хотел бы отметить, что есть исключение (не только) для 404 по умолчанию, предоставляемое Spring. Подробности смотрите в документации Spring . Поэтому, если вам не нужно ваше собственное исключение, вы можете просто сделать это:
@RequestMapping(value = "/**", method = RequestMethod.GET)
public ModelAndView show() throws NoSuchRequestHandlingMethodException {
if(something == null)
throw new NoSuchRequestHandlingMethodException("show", YourClass.class);
...
}
@PathVariable
с моей точки зрения, нет обработки запросов. Как вы думаете, лучше / чище использовать собственное исключение с пометкой @ResponseStatus(value = HttpStatus.NOT_FOUND)
?
Начиная с Spring 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 - см. Другой вопрос )
вы можете использовать @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>
Надеюсь, это поможет .
Если ваш метод контроллера для чего-то вроде обработки файлов, то ResponseEntity
это очень удобно:
@Controller
public class SomeController {
@RequestMapping.....
public ResponseEntity handleCall() {
if (isFound()) {
return new ResponseEntity(...);
}
else {
return new ResponseEntity(404);
}
}
}
Хотя отмеченный ответ является правильным, есть способ достичь этого без исключений. Служба возвращает 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);
}
}
Я бы порекомендовал выдать HttpClientErrorException , как это
@RequestMapping(value = "/sample/")
public void sample() {
if (somethingIsWrong()) {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
}
}
Вы должны помнить, что это можно сделать только до того, как что-либо будет записано в выходной поток сервлета.
Whitelabel Error Page \n .... \n There was an unexpected error (type=Internal Server Error, status=500). \n 404 This is your not found error
Это немного поздно, но если вы используете Spring Data REST, то уже есть. org.springframework.data.rest.webmvc.ResourceNotFoundException
Он также использует @ResponseStatus
аннотации. Больше нет необходимости создавать пользовательское исключение во время выполнения.
Также, если вы хотите вернуть статус 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 от вашего контроллера.
Просто вы можете использовать web.xml, чтобы добавить код ошибки и страницу ошибки 404. Но убедитесь, что страница ошибки 404 не должна находиться под WEB-INF.
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
Это самый простой способ сделать это, но это имеет некоторые ограничения. Предположим, если вы хотите добавить для этой страницы тот же стиль, что и для других страниц. Таким образом, вы не можете к этому. Вы должны использовать@ResponseStatus(value = HttpStatus.NOT_FOUND)
HttpServletResponse#sendError(HttpServletResponse.SC_NOT_FOUND); return null;
из кода контроллера. Теперь внешний вид отклика не отличается от обычного 404, который не попал ни в один контроллер.
Настройте 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;
}
}
Потому что всегда хорошо иметь как минимум десять способов сделать одно и то же:
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class Something {
@RequestMapping("/path")
public ModelAndView somethingPath() {
return new ModelAndView("/", HttpStatus.NOT_FOUND);
}
}