默認靜態資源映射目錄
默認映射路徑
在平常的 web 開發中,避免不了需要訪問靜態資源,如常規的樣式,JS,圖片,上傳文件等;Spring Boot 默認配置對靜態資源映射提供了如下路徑的映射 /static (or /public or /resources or /META-INF/resources) ,如下:
/META-INF/resources/ classpath:/resources/ classpath:/static/ classpath:/public/
可以在源碼中可以查看到
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };
當然可以通過配置的方式自定義靜態資源的路徑,但是會覆蓋默認約定的映射目錄(默認的配置不可用)
# Locations of static resources.
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/
一般情況沒有特殊需求不建議自定義配置,使用默認的就好,約定大於配置嘛。也就是在 resources 目錄下 public、resources、static(新建項目自帶) 三個目錄。
默認訪問路由
靜態資源的默認路由匹配 /** , 路由會從這三個目錄中尋找靜態資源,如果有則返回,當然可以配置改變默認的路由,如下:
spring.mvc.static-path-pattern=/resources/**
OK,我新建了一個項目,結構目錄如下:
比如在 static 目錄下新增一個 MP_verify_46Daxcm7OmhjBcYa.txt 文本文件,瀏覽器訪問 http://localhost:8080/MP_verify_46Daxcm7OmhjBcYa.txt 即可,引用 css,js ,圖片等資源也不需要再加 static 目錄了。
自定義靜態資源映射目錄
自定義靜態資源映射目錄可以通過上述配置的方式配置,當然也可以通過編碼的方式實現
WebConfig
@Configuration public class WebConfig extends WebMvcConfigurerAdapter { @Override public void addResourceHandlers(ResourceHandlerRegistry registry) { //將訪問/static/** 的路由映射到classpath:/static/ 目錄下 registry.addResourceHandler("/static/**").addResourceLocations("classpath:/static/"); } @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/").setViewName("index"); registry.addViewController("/groovy").setViewName("hello"); registry.addViewController("/app").setViewName("app"); } }
上傳文件映射路徑配置
默認 Spring Boot 是內置了 Tomcat 以單個 Jar 包的運行(當然也可以使用 war 包的方式運行在容器里),Spring Boot 項目啟動的時候會跟根據約定把靜態文件加載到 classpath 目錄下,如果要上傳文件或寫文件日志的話,必須把訪問的路由映射到服務器的文件目錄。
FileUploadController
private final ResourceLoader resourceLoader;
@Autowired
public UploadController(ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}
/**
* 上傳文件
* @param file
* @param model
* @param request
* @return
*/
@RequestMapping(method = RequestMethod.POST, value = "/")
public String upload(@RequestParam("file") MultipartFile file, Model model, HttpServletRequest request) {
if (!file.isEmpty()) {
try {
Files.copy(file.getInputStream(), Paths.get("/upload", file.getOriginalFilename()));
model.addAttribute("message", "You successfully uploaded " + file.getOriginalFilename() + "!");
} catch (IOException|RuntimeException e) {
model.addAttribute("message", "Failued to upload " + file.getOriginalFilename() + " => " + e.getMessage());
}
} else {
model.addAttribute("message", "Failed to upload " + file.getOriginalFilename() + " because it was empty");
}
return "redirect:/";
}
}
/**
* 綁定微信用戶 (頭像圖片編碼base64)
* @param weixinBindRequest
* @param session
* @return
*/
@ResponseBody
@RequestMapping(value = "/uploadImgbase64",method= RequestMethod.POST)
public WeixinBindResponse uploadImgbase64(@RequestBody WeixinBindRequest weixinBindRequest, HttpSession session) {
//logger.info("weixinbind req: " + JSON.toJSONString(weixinBindRequest));
WeixinBindResponse response= new WeixinBindResponse();
logger.info("weixinbind openId: "+weixinBindRequest.getOpenid());
//保存用戶頭像
for (int i=0;i<weixinBindRequest.getImgs().length;i++){
String dataPrix = "";
String data = "";
String suffix = "";
String [] d = weixinBindRequest.getImgs()[i].split("base64,");
if(d != null && d.length == 2){
dataPrix = d[0];
data = d[1];
}
if("data:image/jpeg;".equalsIgnoreCase(dataPrix)){//data:image/jpeg;base64,base64編碼的jpeg圖片數據
suffix = ".jpg";
} else if("data:image/x-icon;".equalsIgnoreCase(dataPrix)){//data:image/x-icon;base64,base64編碼的icon圖片數據
suffix = ".ico";
} else if("data:image/gif;".equalsIgnoreCase(dataPrix)){//data:image/gif;base64,base64編碼的gif圖片數據
suffix = ".gif";
} else if("data:image/png;".equalsIgnoreCase(dataPrix)){//data:image/png;base64,base64編碼的png圖片數據
suffix = ".png";
}
String fileName = weixinBindRequest.getOpenid() +"_"+i + suffix;
try{
// request.getSession().getServletContext().getRealPath("upload");
// String path = String.valueOf(Paths.get("upload", weixinBindRequest.getOpenid()));
FileUtils.writeByteArrayToFile(new File("upload", fileName), Base64Utils.decodeFromString(data));
}catch(Exception ee){
}
}
//微信綁定用戶信息
boolean flag = this.userSerice.bindWeixinUser(weixinBindRequest);
if(!flag){
response.setIsError(true);
response.setErrorCode(500);
response.setErrorMsg("微信綁定用戶信息失敗!!!");
return response;
}
response.setIsError(false);
response.setErrorCode(200);
response.setErrorMsg("微信綁定用戶信息成功!!!");
return response;
}
/**
* 顯示圖片
* @param filename
* @return
*/
@RequestMapping(method = RequestMethod.GET, value = "/{filename:.+}")
@ResponseBody
public ResponseEntity<?> getFile(@PathVariable String filename) {
try {
return ResponseEntity.ok(resourceLoader.getResource("file:" + Paths.get("upload", filename).toString()));
} catch (Exception e) {
return ResponseEntity.notFound().build();
}
}
上傳文件的路徑會項目根目錄上創建,所以不能被直接訪問到 ,Spring 提供了 ResourceLoader ,利於這個類可以加載非應用目錄的里文件然后返回,具體看官方的列子吧:
https://spring.io/guides/gs/uploading-files/
https://github.com/spring-guides/gs-uploading-files.git
上傳文件大小限制
最后別忘了配置文件大小的限制
spring.http.multipart.max-file-size=128KB
spring.http.multipart.max-request-size=128KB
遇到的問題:
如果使用了 nginx 代理提示如下錯誤:
Troubleshooting “Request Entity Too Large” (HTTP 413) error message returned to browser
nginx 中配置 client_max_body_size 允許的大小
client_max_body_size 100m;
client_body_buffer_size 128k;
配置附錄:
# SPRING RESOURCES HANDLING (ResourceProperties)
spring.resources.add-mappings=true # Enable default resource handling.
spring.resources.cache-period= # Cache period for the resources served by the resource handler, in seconds.
spring.resources.chain.cache=true # Enable caching in the Resource chain.
spring.resources.chain.enabled= # Enable the Spring Resource Handling chain. Disabled by default unless at least one strategy has been enabled.
spring.resources.chain.gzipped=false # Enable resolution of already gzipped resources.
spring.resources.chain.html-application-cache=false # Enable HTML5 application cache manifest rewriting.
spring.resources.chain.strategy.content.enabled=false # Enable the content Version Strategy.
spring.resources.chain.strategy.content.paths=/** # Comma-separated list of patterns to apply to the Version Strategy.
spring.resources.chain.strategy.fixed.enabled=false # Enable the fixed Version Strategy.
spring.resources.chain.strategy.fixed.paths=/** # Comma-separated list of patterns to apply to the Version Strategy.
spring.resources.chain.strategy.fixed.version= # Version string to use for the Version Strategy.
spring.resources.static-locations=classpath:/META-INF/resources/,classpath:/resources/,classpath:/static/,classpath:/public/ # Locations of static resources.
REFER:
https://spring.io/blog/2014/07/24/spring-framework-4-1-handling-static-web-resources
https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-spring-mvc-static-content

