我有一个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
中映射静态资源吗?
谢谢!
答案 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-pattern
和spring.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
头。此外,控制器会缓存每个资源,以避免再次从硬盘重新加载请求的资源。
这可能不是最佳解决方案,但是,对于我的应用程序,这是可行的解决方法。任何改进建议都将受到高度赞赏!