Jak uzyskać kontroler Spring 3.0, aby uruchomić 404?
Mam kontroler z @RequestMapping(value = "/**", method = RequestMethod.GET)
niektórymi adresami URL uzyskującymi dostęp do kontrolera, chcę, aby kontener wymyślił 404.
Jak uzyskać kontroler Spring 3.0, aby uruchomić 404?
Mam kontroler z @RequestMapping(value = "/**", method = RequestMethod.GET)
niektórymi adresami URL uzyskującymi dostęp do kontrolera, chcę, aby kontener wymyślił 404.
Odpowiedzi:
Od wiosny 3.0 można również wyjątek zadeklarowana z @ResponseStatus
adnotacją:
@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
to, że definiujesz całą grupę silnie typowanych, dobrze nazwanych klas wyjątków, każda z własną @ResponseStatus
. W ten sposób oddzielasz kod kontrolera od szczegółów kodów stanu HTTP.
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Your reason")
ResourceNotFound.fillInStackTrace()
go pustą implementacją.
Począwszy od wersji 5.0 niekoniecznie musisz tworzyć dodatkowe wyjątki:
throw new ResponseStatusException(NOT_FOUND, "Unable to find resource");
Ponadto możesz obejmować wiele scenariuszy za pomocą jednego wbudowanego wyjątku i masz większą kontrolę.
Zobacz więcej:
Przepisz sygnaturę metody, aby akceptowała HttpServletResponse
jako parametr, abyś mógł ją wywołać setStatus(int)
.
setStatus(int)
javadoc stwierdza, co następuje: Jeśli ta metoda zostanie użyta do ustawienia kodu błędu, wówczas mechanizm strony błędu kontenera nie zostanie uruchomiony. Jeśli wystąpił błąd, a osoba dzwoniąca chce wywołać stronę błędu zdefiniowaną w aplikacji internetowej, sendError
należy go użyć.
Chciałbym wspomnieć, że istnieje wyjątek (nie tylko) dla 404 domyślnie dostarczony przez Spring. Zobacz szczegóły w dokumentacji wiosennej . Jeśli więc nie potrzebujesz własnego wyjątku, możesz po prostu to zrobić:
@RequestMapping(value = "/**", method = RequestMethod.GET)
public ModelAndView show() throws NoSuchRequestHandlingMethodException {
if(something == null)
throw new NoSuchRequestHandlingMethodException("show", YourClass.class);
...
}
@PathVariable
z mojego punktu widzenia nie ma obsługi żądań. Czy uważasz, że lepiej / czysto używać własnego wyjątku opatrzonego adnotacjami @ResponseStatus(value = HttpStatus.NOT_FOUND)
?
Od wersji 3.0.2 możesz zwrócić ResponseEntity <T> w wyniku zastosowania metody kontrolera:
@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> jest bardziej elastyczna niż adnotacja @ResponseBody - zobacz inne pytanie )
możesz użyć @ControllerAdvice do obsługi wyjątków. Domyślne zachowanie klasy z adnotacjami @ControllerAdvice pomoże wszystkim znanym kontrolerom.
więc zostanie wywołany, gdy dowolny kontroler, który masz, zgłasza błąd 404.
jak następujące:
@ControllerAdvice
class GlobalControllerExceptionHandler {
@ResponseStatus(HttpStatus.NOT_FOUND) // 404
@ExceptionHandler(Exception.class)
public void handleNoTFound() {
// Nothing to do
}
}
i zamapuj ten błąd odpowiedzi 404 w pliku web.xml, na przykład:
<error-page>
<error-code>404</error-code>
<location>/Error404.html</location>
</error-page>
Mam nadzieję, że to pomaga.
Jeśli twoja metoda kontrolera służy do obsługi plików, ResponseEntity
jest to bardzo przydatne:
@Controller
public class SomeController {
@RequestMapping.....
public ResponseEntity handleCall() {
if (isFound()) {
return new ResponseEntity(...);
}
else {
return new ResponseEntity(404);
}
}
}
Chociaż zaznaczona odpowiedź jest poprawna, istnieje sposób na osiągnięcie tego bez wyjątków. Usługa zwraca Optional<T>
szukany obiekt, który jest odwzorowywany na, HttpStatus.OK
jeśli został znaleziony, i na 404, jeśli jest pusty.
@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);
}
}
Ja polecam rzucania HttpClientErrorException , jak to
@RequestMapping(value = "/sample/")
public void sample() {
if (somethingIsWrong()) {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
}
}
Musisz pamiętać, że można to zrobić tylko przed zapisaniem czegokolwiek w strumieniu wyjściowym serwletu.
Whitelabel Error Page \n .... \n There was an unexpected error (type=Internal Server Error, status=500). \n 404 This is your not found error
To trochę za późno, ale jeśli używasz Spring Data REST, to już jest. org.springframework.data.rest.webmvc.ResourceNotFoundException
Używa także @ResponseStatus
adnotacji. Nie ma już potrzeby tworzenia niestandardowego wyjątku czasu wykonywania.
Również, jeśli chcesz zwrócić status 404 ze swojego kontrolera, wystarczy to zrobić
@RequestMapping(value = "/somthing", method = RequestMethod.POST)
@ResponseBody
public HttpStatus doSomthing(@RequestBody String employeeId) {
try{
return HttpStatus.OK;
}
catch(Exception ex){
return HttpStatus.NOT_FOUND;
}
}
W ten sposób otrzymasz błąd 404 w przypadku, gdy chcesz zwrócić 404 ze swojego kontrolera.
Wystarczy użyć pliku web.xml, aby dodać kod błędu i stronę błędu 404. Ale upewnij się, że strona błędu 404 nie może znaleźć się pod WEB-INF.
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
Jest to najprostszy sposób na zrobienie tego, ale ma to pewne ograniczenia. Załóżmy, że chcesz dodać ten sam styl dla tej strony, co inne strony. W ten sposób nie możesz tego zrobić. Musisz użyć@ResponseStatus(value = HttpStatus.NOT_FOUND)
HttpServletResponse#sendError(HttpServletResponse.SC_NOT_FOUND); return null;
z kodu kontrolera. Teraz z zewnątrz odpowiedź nie różni się niczym od zwykłego 404, który nie uderzył w żaden kontroler.
Skonfiguruj plik web.xml z ustawieniem
<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>
Utwórz nowy kontroler
/**
* 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;
}
}
Ponieważ zawsze dobrze jest mieć co najmniej dziesięć sposobów na zrobienie tego samego:
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);
}
}