Risposte:
Dalla primavera 3.0 puoi anche lanciare un'eccezione dichiarata con @ResponseStatus
annotazione:
@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
sia che tu definisca un intero gruppo di classi di eccezioni ben tipizzate e ben denominate, ognuna con la propria @ResponseStatus
. In questo modo, si disaccoppia il codice del controller dai dettagli dei codici di stato HTTP.
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Your reason")
ResourceNotFound.fillInStackTrace()
con un'implementazione vuota.
A partire dalla primavera 5.0, non è necessario creare eccezioni aggiuntive:
throw new ResponseStatusException(NOT_FOUND, "Unable to find resource");
Inoltre, puoi coprire più scenari con uno, un'eccezione integrata e hai un maggiore controllo.
Vedi altro:
Riscrivi la firma del tuo metodo in modo che accetti HttpServletResponse
come parametro, in modo da poterlo chiamare setStatus(int)
.
setStatus(int)
javadoc afferma quanto segue: Se si utilizza questo metodo per impostare un codice di errore, il meccanismo della pagina di errore del contenitore non verrà attivato. Se si verifica un errore e il chiamante desidera richiamare una pagina di errore definita nell'applicazione Web, è sendError
necessario utilizzare invece.
Vorrei menzionare che esiste un'eccezione (non solo) per 404 di default fornita da Spring. Vedere la documentazione di primavera per i dettagli. Quindi, se non hai bisogno della tua eccezione, puoi semplicemente farlo:
@RequestMapping(value = "/**", method = RequestMethod.GET)
public ModelAndView show() throws NoSuchRequestHandlingMethodException {
if(something == null)
throw new NoSuchRequestHandlingMethodException("show", YourClass.class);
...
}
@PathVariable
mio punto di vista, non è possibile gestire le richieste. Pensi che sia meglio / più pulito usare la tua eccezione annotata @ResponseStatus(value = HttpStatus.NOT_FOUND)
?
Dalla primavera 3.0.2 è possibile restituire ResponseEntity <T> come risultato del metodo del controller:
@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> è più flessibile dell'annotazione @ResponseBody - vedi un'altra domanda )
è possibile utilizzare @ControllerAdvice per gestire le eccezioni. Il comportamento predefinito della classe annotata @ControllerAdvice aiuterà tutti i controller noti.
quindi verrà chiamato quando qualsiasi controller che hai genera 404 errore.
come il seguente:
@ControllerAdvice
class GlobalControllerExceptionHandler {
@ResponseStatus(HttpStatus.NOT_FOUND) // 404
@ExceptionHandler(Exception.class)
public void handleNoTFound() {
// Nothing to do
}
}
e mappa questo errore di risposta 404 nel tuo web.xml, come il seguente:
<error-page>
<error-code>404</error-code>
<location>/Error404.html</location>
</error-page>
Spero che aiuti .
Se il tuo metodo controller è per qualcosa come la gestione dei file, allora ResponseEntity
è molto utile:
@Controller
public class SomeController {
@RequestMapping.....
public ResponseEntity handleCall() {
if (isFound()) {
return new ResponseEntity(...);
}
else {
return new ResponseEntity(404);
}
}
}
Mentre la risposta contrassegnata è corretta, esiste un modo per raggiungere questo obiettivo senza eccezioni. Il servizio sta restituendo Optional<T>
l'oggetto cercato e questo viene mappato su HttpStatus.OK
se trovato e su 404 se vuoto.
@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);
}
}
Consiglierei di lanciare HttpClientErrorException , in questo modo
@RequestMapping(value = "/sample/")
public void sample() {
if (somethingIsWrong()) {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
}
}
È necessario ricordare che ciò può essere fatto solo prima che qualsiasi cosa venga scritta nel flusso di output servlet.
Whitelabel Error Page \n .... \n There was an unexpected error (type=Internal Server Error, status=500). \n 404 This is your not found error
Questo è un po 'tardi, ma se stai usando Spring Data REST allora c'è già org.springframework.data.rest.webmvc.ResourceNotFoundException
Usa anche l' @ResponseStatus
annotazione. Non è più necessario creare un'eccezione di runtime personalizzata.
Inoltre, se si desidera restituire lo stato 404 dal controller, è sufficiente eseguire questa operazione
@RequestMapping(value = "/somthing", method = RequestMethod.POST)
@ResponseBody
public HttpStatus doSomthing(@RequestBody String employeeId) {
try{
return HttpStatus.OK;
}
catch(Exception ex){
return HttpStatus.NOT_FOUND;
}
}
In questo modo riceverai un errore 404 nel caso in cui desideri restituire un 404 dal tuo controller.
Semplicemente puoi usare web.xml per aggiungere il codice di errore e la pagina di errore 404. Ma assicurati che la pagina di errore 404 non debba essere localizzata in WEB-INF.
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
Questo è il modo più semplice per farlo, ma questo ha alcune limitazioni. Supponiamo che tu voglia aggiungere lo stesso stile per questa pagina che hai aggiunto altre pagine. In questo modo non puoi farlo. Devi usare il@ResponseStatus(value = HttpStatus.NOT_FOUND)
HttpServletResponse#sendError(HttpServletResponse.SC_NOT_FOUND); return null;
dal codice del controller. Ora dall'esterno la risposta non sembra diversa da un normale 404 che non ha colpito nessun controller.
Configura web.xml con impostazione
<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>
Crea nuovo controller
/**
* 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;
}
}
Perché è sempre bene avere almeno dieci modi di fare la stessa cosa:
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);
}
}