Câu trả lời:
Kể từ Mùa xuân 3.0, bạn cũng có thể ném Ngoại lệ được khai báo với @ResponseStatus
chú thích:
@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
là bạn xác định một nhóm các lớp ngoại lệ được đánh máy mạnh, được đặt tên tốt, mỗi lớp có một lớp riêng @ResponseStatus
. Bằng cách đó, bạn tách mã điều khiển của mình khỏi chi tiết mã trạng thái HTTP.
@ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Your reason")
ResourceNotFound.fillInStackTrace()
bằng một triển khai trống.
Bắt đầu từ Spring 5.0, bạn không nhất thiết phải tạo thêm ngoại lệ:
throw new ResponseStatusException(NOT_FOUND, "Unable to find resource");
Ngoài ra, bạn có thể bao gồm nhiều kịch bản với một, ngoại lệ tích hợp và bạn có nhiều quyền kiểm soát hơn.
Xem thêm:
Viết lại chữ ký phương thức của bạn để nó chấp nhận HttpServletResponse
như một tham số, để bạn có thể gọi setStatus(int)
nó.
setStatus(int)
javadoc tuyên bố như sau: Nếu phương pháp này được sử dụng để đặt mã lỗi, thì cơ chế trang lỗi của bộ chứa sẽ không được kích hoạt. Nếu có lỗi và người gọi muốn gọi một trang lỗi được xác định trong ứng dụng web, thì sendError
phải sử dụng thay thế.
Tôi muốn đề cập rằng có ngoại lệ (không chỉ) cho 404 theo mặc định được cung cấp bởi Spring. Xem tài liệu mùa xuân để biết chi tiết. Vì vậy, nếu bạn không cần ngoại lệ của riêng mình, bạn chỉ cần làm điều này:
@RequestMapping(value = "/**", method = RequestMethod.GET)
public ModelAndView show() throws NoSuchRequestHandlingMethodException {
if(something == null)
throw new NoSuchRequestHandlingMethodException("show", YourClass.class);
...
}
@PathVariable
không có xử lý yêu cầu theo quan điểm của tôi. Bạn có nghĩ rằng sẽ tốt hơn / sạch hơn khi sử dụng chú thích Ngoại lệ của riêng bạn @ResponseStatus(value = HttpStatus.NOT_FOUND)
không?
Kể từ Spring 3.0.2, bạn có thể trả về FeedbackEntity <T> do phương thức của bộ điều khiển:
@RequestMapping.....
public ResponseEntity<Object> handleCall() {
if (isFound()) {
// do what you want
return new ResponseEntity<>(HttpStatus.OK);
}
else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}
(FeedbackEntity <T> linh hoạt hơn chú thích @ResponseBody - xem câu hỏi khác )
bạn có thể sử dụng @ControllAdvice để xử lý Ngoại lệ của mình, Hành vi mặc định mà lớp chú thích @ControllAdvice sẽ hỗ trợ tất cả các Bộ điều khiển đã biết.
vì vậy nó sẽ được gọi khi bất kỳ Trình điều khiển nào bạn gặp lỗi 404.
như sau:
@ControllerAdvice
class GlobalControllerExceptionHandler {
@ResponseStatus(HttpStatus.NOT_FOUND) // 404
@ExceptionHandler(Exception.class)
public void handleNoTFound() {
// Nothing to do
}
}
và ánh xạ lỗi phản hồi 404 này trong tệp webDB của bạn, như sau:
<error-page>
<error-code>404</error-code>
<location>/Error404.html</location>
</error-page>
Mong rằng sẽ giúp.
Nếu phương thức điều khiển của bạn dành cho một cái gì đó như xử lý tệp thì ResponseEntity
rất tiện dụng:
@Controller
public class SomeController {
@RequestMapping.....
public ResponseEntity handleCall() {
if (isFound()) {
return new ResponseEntity(...);
}
else {
return new ResponseEntity(404);
}
}
}
Trong khi câu trả lời được đánh dấu là chính xác, có một cách để đạt được điều này mà không có ngoại lệ. Dịch vụ đang trả về Optional<T>
đối tượng được tìm kiếm và điều này được ánh xạ tới HttpStatus.OK
nếu tìm thấy và thành 404 nếu trống.
@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);
}
}
Tôi khuyên bạn nên ném httpClientErrorException , như thế này
@RequestMapping(value = "/sample/")
public void sample() {
if (somethingIsWrong()) {
throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
}
}
Bạn phải nhớ rằng điều này chỉ có thể được thực hiện trước khi mọi thứ được ghi vào luồng đầu ra của 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
Điều này hơi muộn, nhưng nếu bạn đang sử dụng Spring Data REST thì đã có org.springframework.data.rest.webmvc.ResourceNotFoundException
Nó cũng sử dụng @ResponseStatus
chú thích. Không cần phải tạo một ngoại lệ thời gian chạy tùy chỉnh nữa.
Ngoài ra nếu bạn muốn trả về trạng thái 404 từ bộ điều khiển của mình, tất cả những gì bạn cần là làm điều này
@RequestMapping(value = "/somthing", method = RequestMethod.POST)
@ResponseBody
public HttpStatus doSomthing(@RequestBody String employeeId) {
try{
return HttpStatus.OK;
}
catch(Exception ex){
return HttpStatus.NOT_FOUND;
}
}
Bằng cách này, bạn sẽ nhận được một lỗi 404 trong trường hợp khi bạn muốn trả về 404 từ bộ điều khiển của bạn.
Đơn giản là bạn có thể sử dụng web.xml để thêm mã lỗi và trang lỗi 404. Nhưng đảm bảo trang lỗi 404 không được định vị trong WEB-INF.
<error-page>
<error-code>404</error-code>
<location>/404.html</location>
</error-page>
Đây là cách đơn giản nhất để làm điều này nhưng điều này có một số hạn chế. Giả sử nếu bạn muốn thêm cùng một kiểu cho trang này mà bạn đã thêm các trang khác. Theo cách này, bạn không thể làm điều đó. Bạn phải sử dụng@ResponseStatus(value = HttpStatus.NOT_FOUND)
HttpServletResponse#sendError(HttpServletResponse.SC_NOT_FOUND); return null;
từ mã điều khiển. Bây giờ, từ bên ngoài, phản hồi trông không khác với 404 thông thường không gặp bất kỳ bộ điều khiển nào.
Định cấu hình tệp web.xml bằng cài đặt
<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>
Tạo bộ điều khiển mới
/**
* 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;
}
}
Bởi vì thật tốt khi có ít nhất mười cách để làm điều tương tự:
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);
}
}