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.