没有处理程序在spring boot中发现异常和静态资源

时间:2016-10-11 09:11:55

标签: java spring-boot

我有一个Spring Boot网络应用程序,我在ControllerAdvice课程中捕获了自定义异常。问题是Spring Boot默认情况下不会抛出异常,如果没有找到处理程序(它将json发送回客户端)。

我想要的是在NoHandlerFoundException课程中抓住ControllerAdvice。为了实现这一点,我明确配置了

spring.mvc.throw-exception-if-no-handler-found=true
spring.resources.add-mappings=false

这个技巧完成了这项工作,现在我可以捕获NoHandlerFoundException但它禁用Spring来自动配置静态资源的路径。所以我的所有静态资源现在都不能用于客户端。我尝试使用另外一个没有帮助的配置来解决这个问题

spring.resources.static-locations=classpath:/resources/static/

当使用Spring Boot禁用自动配置时,有人可以建议如何在spring.resources.add-mappings=false中映射静态资源吗?

谢谢!

3 个答案:

答案 0 :(得分:4)

如果静态资源仅限于特定的URL路径,则只能配置由Spring静态资源处理程序处理的路径。在此示例中,/doc URL路径由类路径中/resources/static/doc/文件夹中的静态资源提供:

spring.mvc.static-path-pattern=/doc/**
spring.resources.static-locations=classpath:/resources/static/doc/

您需要删除此配置:

spring.resources.add-mappings=false

答案 1 :(得分:1)

而不是在配置属性中添加以下行

@Configuration
public class CustomErrorAttributes extends DefaultErrorAttributes {

    @Bean
    public ErrorAttributes errorAttributes() {

        return new DefaultErrorAttributes() {
            @Override
            public Map<String, Object> getErrorAttributes(RequestAttributes requestAttributes, boolean includeStackTrace) {

                Map<String, Object> errorAttributes = super.getErrorAttributes(requestAttributes, includeStackTrace);
                Map<String, Object> newErrorAttributes = new LinkedHashMap<String, Object>();
                Object errorMessage = requestAttributes.getAttribute(RequestDispatcher.ERROR_MESSAGE, RequestAttributes.SCOPE_REQUEST);
                if (errorMessage != null) {
                    newErrorAttributes.put("response-type",  "error");
                    newErrorAttributes.put("error-code", errorAttributes.get("status"));
                    newErrorAttributes.put("message",  errorAttributes.get("message"));
                    newErrorAttributes.put("error-message",  errorAttributes.get("error"));
                }
                return newErrorAttributes;
            }

        };
    }
} 

编写自定义错误属性,如下所示:

    <!DOCTYPE html>
<html>
<head>
    <title></title>
    <script
    src="https://code.jquery.com/jquery-3.1.1.min.js"
    integrity="sha256-hVVnYaiADRTO2PzUGmuLJr8BLUSjGIZsDYGmIJLv2b8="
    crossorigin="anonymous"></script>
</head>
<body>
  <form method="POST" id="userform">
      <input type="text" name="firstname" id="firstname">
      <input type="text" name="lastname" id="lastname">
  </form>

  <script type="text/javascript">
    $("#userform").submit(function(e){
       return false;    
   });

    $("#userform input").keydown(function(e) {
        if(e.which == 13) {
            userInput = $(this).val();
            $(this).val(userInput.substring(0,0));
            $("#userform input#firstname").focus();
        }    
    });    
</script>
</body>
</html>

答案 2 :(得分:1)

我遇到了相同的问题,经过研究,我发现显然不可能同时启用这两个选项(即通过设置NoHandlerFoundException抛出spring.mvc.throw-exception-if-no-handler-found=true并自动提供静态资源)。 / p>

要启用抛出NoHandlerFoundException的选项,需要将spring.resources.add-mappings设置为false,否则将无法工作。此外,在我的测试设置中,无法禁用spring.resources.add-mappings并手动指定静态资源的URL(例如,通过应用程序属性spring.mvc.static-path-patternspring.resources.static-locations或以编程方式通过覆盖public void addResourceHandlers(ResourceHandlerRegistry registry)) ),因为spring.resources.add-mappings=false设置似乎被否决了。

最后,我实现了以下变通办法,以通过自己的控制器实现手动提供静态资源:

@Controller
public class StaticWebContentController {
    
    private Map<String, byte[]> cache = new HashMap<String,byte[]>();

    @RequestMapping(value = "/css/{file}", method = RequestMethod.GET)
    public ResponseEntity<byte[]> getCssFile(@PathVariable("file") String name){
        ResponseEntity<byte[]> responseEntity = loadResource(".\\static\\css\\"+name,"text/css");
        return responseEntity;
    }

    @RequestMapping(value = "/img/bootstrap-icons-1.1.0/{file}", method = RequestMethod.GET)
    public ResponseEntity<byte[]> getimgFile(@PathVariable("file") String name){
        ResponseEntity<byte[]> responseEntity = loadResource(".\\static\\img\\bootstrap-icons-1.1.0\\"+name,"image/svg+xml");
        return responseEntity;
    }

    @RequestMapping(value = "/js/{file}", method = RequestMethod.GET)
    public ResponseEntity<byte[]> getJsFile(@PathVariable("file") String name){
        ResponseEntity<byte[]> responseEntity = loadResource(".\\static\\js\\"+name,"text/javascript");
        return responseEntity;
    }

    private ResponseEntity<byte[]> loadResource(String path, String contentType){
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.add("Content-Type", contentType);
        if(hasCachedContent(path)){
            return new ResponseEntity<byte[]>(getCachedContent(path),responseHeaders,HttpStatus.OK);
        }else{
            Resource resource = new ClassPathResource(path);
            if(resource.exists()){
                try{
                    InputStream inputStream = resource.getInputStream();
                    byte[] content = inputStream.readAllBytes();
                    putCache(path, content);
                    return new ResponseEntity<byte[]>(content,responseHeaders,HttpStatus.OK);
                }catch(IOException e){
                    throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR,e.getMessage());
                }
            }else{
                throw new ResponseStatusException(HttpStatus.NOT_FOUND,"The requested resource '"+path+"' does not exist'");
            }
        }   
    }

    private byte[] getCachedContent(String path){
        return cache.get(path);
    }

    private boolean hasCachedContent(String path){
        return cache.containsKey(path);
    }

    private void putCache(String path, byte[] content){
        cache.put(path, content);
    }

}

在我的应用程序中,我有三种类型的静态资源位于三个不同的子文件夹中。每种类型均由单独的端点处理,以便正确设置Content-Type头。此外,控制器会缓存每个资源,以避免再次从硬盘重新加载请求的资源。

这可能不是最佳解决方案,但是,对于我的应用程序,这是可行的解决方法。任何改进建议都将受到高度赞赏!