คำตอบ:
ตั้งแต่ 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สำหรับรายละเอียด ดังนั้นหากคุณไม่ต้องการข้อยกเว้นของคุณเองคุณสามารถทำได้:
@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);
}
}