Spring-MVC 컨트롤러에서 트리거 404?


194

Spring 3.0 컨트롤러가 404를 트리거하도록하려면 어떻게해야 합니까?

컨트롤러가 있고 컨트롤러에 액세스하는 @RequestMapping(value = "/**", method = RequestMethod.GET)일부 URL의 경우 컨테이너에 404가 필요합니다.

답변:


326

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(); 
        }
    }
}

2
흥미 롭군 throw 사이트에서 사용할 HttpStatus를 지정할 수 있습니까 (예 : Exception 클래스로 컴파일하지 않았습니까)?
— matt b

1
@ mattb : 요점은 @ResponseStatus강력하게 형식화되고 이름이 지정된 예외 클래스를 각각 고유 한 클래스로 정의하는 것 @ResponseStatus입니다. 이렇게하면 HTTP 상태 코드의 세부 사항에서 컨트롤러 코드를 분리 할 수 ​​있습니다.
— skaffman

10
오류에 대한 자세한 설명이 포함 된 본문을 반환하도록 지원할 수 있습니까?
— 톰

7
@Tom :@ResponseStatus(value = HttpStatus.NOT_FOUND, reason="Your reason")
— Nailgun

6
흐름 제어에만이 ResourceNotFound 예외를 사용 ResourceNotFound.fillInStackTrace()하는 경우 빈 구현 으로 재정의하는 것이 좋습니다 .
— Ralph


36

메소드 서명 HttpServletResponse이 매개 변수로 승인 되도록 호출 setStatus(int)하여 호출 할 수 있도록 다시 작성하십시오 .

http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/mvc.html#mvc-ann-requestmapping-arguments


8
이것은 누군가가 http 요청자에게 실수를 저지르는 동안 그들이 해결할 수없는 많은 예외로 prod ops 팀을 범람시키지 않는 방법을 찾고 있다면 유일한 정답입니다.
— Alex R

4
setStatus(int)이 메소드를 사용해 에러 코드를 설정하면 (자), 컨테이너의 에러 페이지기구는 트리거되지 않습니다. 오류가 있고 호출자가 웹 애플리케이션에 정의 된 오류 페이지를 호출하려는 경우 sendError대신 사용해야합니다.
— Philippe Gioseffi

@AlexR 처리 된 예외로 인해 운영팀이 넘쳐서는 안됩니다. 그렇다면, 로깅이 잘못 수행 된 것입니다.
— Raedwald

25

Spring에서 제공하는 기본적으로 404에 대한 예외가 있음을 언급하고 싶습니다. 자세한 내용은 Spring 설명서 를 참조하십시오. 따라서 자신의 예외가 필요하지 않은 경우 간단히 다음을 수행 할 수 있습니다.

 @RequestMapping(value = "/**", method = RequestMethod.GET)
 public ModelAndView show() throws NoSuchRequestHandlingMethodException {
    if(something == null)
         throw new NoSuchRequestHandlingMethodException("show", YourClass.class);

    ...

  }

11
이것은 Spring이 핸들러를 찾을 수없는 특정 경우를위한 것으로 보입니다. 문제는 Spring 이 핸들러를 찾을 수 있지만 사용자가 다른 이유로 404를 반환하려고 할 때입니다.
— Roy Truelove

2
핸들러 메소드에 대한 ulr 매핑이 동적 일 때 사용하고 있습니다. 엔티티가 존재하지 않으면 @PathVariable내 관점에서 요청을 처리 하지 않습니다 . 주석이 달린 자신의 예외를 사용하는 것이 더 좋고 깨끗하다고 ​​생각하십니까 @ResponseStatus(value = HttpStatus.NOT_FOUND) ?
— michal.kreuzman

1
귀하의 경우에는 괜찮은 것처럼 들리지만 필요한 예외가있는 모든 경우를 처리하기 위해 제공 한 링크에있는 예외를 추천 할 것을 알지 못합니다.
— Roy Truelove

Spring은 하나의 예외와 404에 대해서만 하나를 제공했습니다. 404Exception으로 이름을 지정하거나 하나를 작성해야합니다. 그러나 지금은 404가 필요할 때마다 이것을 던지는 것이 좋다고 생각합니다.
— autra

기술적으로는 괜찮습니다-404 상태 헤더를 보내 게됩니다. 그러나 자동 오류 메시지-응답 내용- "이름을 가진 요청 처리 방법이 없습니다 ..."는 사용자에게 보여주고 싶지 않은 것입니다.
— Olli

24

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 주석보다 더 유연합니다. 다른 질문을 참조하십시오 )


2
의 코스 유연하지만 선언적 프로그래밍의 장점 패배
— rohanagarwal

3
PROD에서 Sentry 또는 이와 유사한 것을 사용하고 실제 오류가 아닌 오류로 스팸 메일을 보내지 않으려면이 예외가 아닌 상황에서 예외를 사용하는 것과 비교하여이 솔루션이 훨씬 좋습니다.
— Tobias Hermann

바디를 실제 객체로 채우는 방법을 잊지 마십시오. 일반적인 "객체"예제 : 객체 returnItemBody = new Object (); Return ResponseEntity.status (HttpStatus.OK) .body (returnItemBody);
— granadaCoder

16

@ControllerAdvice 를 사용하여 예외를 처리 할 수 있습니다. @ControllerAdvice 주석 클래스의 기본 동작은 알려진 모든 컨트롤러를 지원합니다.

따라서 404 오류가 발생하면 컨트롤러가 호출됩니다.

다음과 같이 :

@ControllerAdvice
class GlobalControllerExceptionHandler {
    @ResponseStatus(HttpStatus.NOT_FOUND)  // 404
    @ExceptionHandler(Exception.class)
    public void handleNoTFound() {
        // Nothing to do
    }
}

web.xml에이 404 응답 오류를 다음과 같이 매핑하십시오.

<error-page>
        <error-code>404</error-code>
        <location>/Error404.html</location>
</error-page>

희망이 도움이됩니다.


2
404 상태 코드를 사용하여 Exception (및 서브 클래스) 유형의 예외를 맵핑했습니다. 내부 서버 오류가 있다고 생각한 적이 있습니까? GlobalControllerExceptionHandler에서 어떻게 처리 할 계획입니까?
— rohanagarwal

REST 컨트롤러에서는 작동하지 않으며 빈 응답을 리턴합니다.
— rustyx

10

컨트롤러 방법이 파일 처리와 같은 것이면 ResponseEntity매우 편리합니다.

@Controller
public class SomeController {
    @RequestMapping.....
    public ResponseEntity handleCall() {
        if (isFound()) {
            return new ResponseEntity(...);
        }
        else {
            return new ResponseEntity(404);
        }
    }
}

9

표시된 답변은 정확하지만 예외없이 이것을 달성하는 방법이 있습니다. 서비스가 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); 
    }

}

나는 일반적 으로이 접근법을 좋아하지만 옵션을 사용하면 때로는 안티 패턴이됩니다. 컬렉션을 반환 할 때 복잡해집니다.
— jfzr

7

내가 던지는 권하고 싶습니다 HttpClientErrorException을 다음과 같이

@RequestMapping(value = "/sample/")
public void sample() {
    if (somethingIsWrong()) {
        throw new HttpClientErrorException(HttpStatus.NOT_FOUND);
    }
}

이는 서블릿 출력 스트림에 무언가를 쓰기 전에 만 수행 할 수 있음을 기억해야합니다.


4
이 예외는 Spring HTTP 클라이언트에 의해 발생합니다. Spring MVC는 그 예외를 인식하지 못하는 것 같습니다. 어떤 Spring 버전을 사용하고 있습니까? 그 예외로 404를 받고 있습니까?
— Eduardo

1
이렇게하면 스프링 부트가 다음과 같이 반환됩니다.Whitelabel Error Page \n .... \n There was an unexpected error (type=Internal Server Error, status=500). \n 404 This is your not found error
— Slim

이것은 컨트롤러가 아닌 HTTP 클라이언트의 예외입니다. 따라서 지정된 컨텍스트에서 사용하는 것은 부적절합니다.
— Alexey

3

이것은 약간 늦었지만 Spring Data REST 를 사용하는 경우 이미 주석 org.springframework.data.rest.webmvc.ResourceNotFoundException 을 사용합니다 @ResponseStatus. 더 이상 사용자 정의 런타임 예외를 만들 필요가 없습니다.


2

또한 컨트롤러에서 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 오류가 발생합니다.


0

간단히 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와 다르지 않습니다.
— Darryl Miles

이것은 404를 트리거하지 않으며, 발생하는 경우에만 처리합니다.
— Alex R

0

설정으로 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;
        }
}

0

항상 같은 일을하는 열 가지 이상의 방법을 갖는 것이 좋습니다.

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);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.