在Spring-MVC控制器中触发404?

NA.*_*NA. 182 java spring spring-mvc

如何让Spring 3.0控制器触发404?

我有一个控制器,@RequestMapping(value = "/**", method = RequestMethod.GET)有些URL访问控制器,我希望容器能够提供404.

axt*_*avt 312

从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(); 
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 这可以扩展到支持返回包含有关错误的更多描述的正文吗? (9认同)
  • @Tom:`@ResponseStatus(value = HttpStatus.NOT_FOUND,reason ="你的理由")` (7认同)
  • 如果仅将此ResourceNotFound异常用于流控制,那么使用空实现覆盖`ResourceNotFound.fillInStackTrace()`可能是个好主意. (6认同)
  • 有趣.你能指定在throw网站上使用哪个HttpStatus(即没有将它编译成Exception类)? (2认同)

mat*_*t b 36

重写您的方法签名,使其HttpServletResponse作为参数接受,以便您可以调用setStatus(int)它.

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

  • 这是唯一正确的答案,如果有人正在寻找一种方法来告诉http请求者他们犯了一个错误,同时没有充斥prod ops团队他们无法解决的一堆例外. (8认同)
  • `setStatus(int)`javadoc如下:如果使用此方法设置错误代码,则不会触发容器的错误页面机制.如果出现错误并且调用者希望调用Web应用程序中定义的错误页面,则必须使用"sendError". (4认同)

mic*_*man 25

我想提一下,由Spring提供的默认值为404(不仅仅是).请参阅Spring文档了解详细信息 因此,如果您不需要自己的例外,您可以这样做:

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

    ...

  }
Run Code Online (Sandbox Code Playgroud)

  • 这看起来是针对特定情况 - 当Spring找不到处理程序时.有问题的情况是Spring*可以*找到一个处理程序,但用户想要返回404另一个原因. (11认同)
  • 当我的处理程序方法的ulr映射是动态的时,我正在使用它.当基于`@PathVariable`的实体不存在时,从我的角度来看,没有请求处理.你认为用@ResponseStatus(value = HttpStatus.NOT_FOUND)注释你自己的Exception更好/更干净吗? (2认同)

Lu5*_*u55 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

(ResponseEntity <T>比@ResponseBody注释更灵活 - 请参阅另一个问题)

  • 如果您在PROD中使用Sentry或类似设备,并且不希望使用没有实际错误的错误对其进行垃圾邮件,则与使用此异常情况的例外情况相比,此解决方案要好得多. (3认同)
  • 灵活的课程设置,但没有声明式编程的好处 (2认同)

小智 16

您可以使用@ControllerAdvice来处理异常,@ ControllerAdvice注释类的默认行为将协助所有已知的控制器.

所以当你有任何控制器抛出404错误时会调用它.

如下:

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

并在您的web.xml中映射此404响应错误,如下所示:

<error-page>
        <error-code>404</error-code>
        <location>/Error404.html</location>
</error-page>
Run Code Online (Sandbox Code Playgroud)

希望有助于.

  • 您已使用404状态代码映射了Exception(和子类)类型的异常.你有没有想过有内部服务器错误?你打算如何处理GlobalControllerExceptionHandler中的那些? (2认同)

Jon*_*oni 14

从Spring 5.0开始,您不必创建其他异常:

throw new ResponseStatusException(NOT_FOUND, "Unable to find resource");
Run Code Online (Sandbox Code Playgroud)

此外,您可以使用一个内置的例外情况涵盖多种情况,并且您拥有更多的控制权。

看更多:

  • 请注意,由于存在泄露信息的风险,从 Spring Boot 2.3 开始,该原因将不会发送。 (2认同)

Ral*_*lph 10

如果您的控制器方法适用于文件处理,那么ResponseEntity非常方便:

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


小智 7

我建议像这样抛出HttpClientErrorException

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

您必须记住,只有在将任何内容写入servlet输出流之前,才能执行此操作.

  • Spring HTTP客户端抛出该异常.Spring MVC似乎不承认异常.您使用的是什么Spring版本?你有这个例外的404吗? (4认同)

use*_*883 7

虽然明确的答案是正确的,但有一种方法可以实现这一点,没有例外.该服务返回Optional<T>搜索到的对象,HttpStatus.OK如果找到则映射到404,如果为空则映射到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); 
    }

}
Run Code Online (Sandbox Code Playgroud)