背景
最近主要工作是开发文件服务相关接口,遇到很多性能问题,比如大文件读取内存溢出(java使用文件流上下传,防止内存溢出)、视频分片读取、浏览器图片缓存等问题。当时也想到一些解决方案,并完美解决。
后来发现,像Tomcat、Nginx这些应用服务器,对于这些问题,早已完美解决。
使用
项目是使用SpringBoot内置的Tomcat,用法如下:
使用外置静态资源目录作为文件下载服务,并开启文件缓存策略。
server:
port: 80
servlet:
encoding:
charset: UTF-8 # 设置UTF-8
force: true #是否在HTTP请求和响应上强制编码到已配置的字符集。
spring:
mvc:
static-path-pattern: /contentfile/**
resources:
# static-locations: classpath:/static
static-locations: file:./files/contentfile
cache:
cachecontrol:
max-age: 3600 #资源缓存时间,单位秒
chain:
compressed: true # 开启gzip压缩
cache: true # 启用缓存
servlet:
multipart:
# 设置单个文件大小
max-file-size: 500MB
# 设置单次请求文件的总大小
max-request-size: 500MB
针对文件可重命名下载的需求,可使用过滤器设置下载文件名,如下:
public class UrlFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String requestQuery = httpRequest.getQueryString();
String url = httpRequest.getServletPath().toLowerCase();
url += (StringUtils.isEmpty(requestQuery) ? "" : "?" + requestQuery);
System.out.println(url);
// 获取url参数
String downloadName = "";
if (!StringUtils.isEmpty(requestQuery)) {
var paramList = requestQuery.split("&");
for (String item : paramList) {
var query = item.split("=");
if (query.length == 2) {
if (!StringUtils.isEmpty(query[0]) && "downloadname".equals(query[0].toLowerCase())) {
downloadName = URLDecoder.decode(query[1], "UTF-8");
}
}
}
}
// 判断是否需要重命名下载
if (!StringUtils.isEmpty(downloadName)) {
String userAgent = httpRequest.getHeader("User-Agent");
userAgent = userAgent == null ? "" : userAgent.toLowerCase();
// 针对IE或者以IE为内核的浏览器:
if (userAgent.contains("msie") || userAgent.contains("trident")) {
downloadName = URLEncoder.encode(downloadName, "UTF-8");
downloadName = downloadName.replace("+", " ");
} else {
downloadName = new String(downloadName.getBytes(), "iso-8859-1");
}
httpResponse.setContentType("application/octet-stream; charset=UTF-8");
HttpResponseUtils.writeHeader(httpResponse, "Content-Disposition",
"attachment;filename=\"" + downloadName + "\"");
}
filterChain.doFilter(request, response);
return;
}
@Override
public void destroy() {
}
}
另外,外置静态资源目录还可以通过自定义静态资源映射配置类实现
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
// 存放文档的根目录
private static String rootPath = System.getProperty("user.dir");
// 资源映射路径
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/contentfile/**").addResourceLocations("file:./files/contentfile");
//registry.addResourceHandler("/contentfile/**").addResourceLocations("file:" + rootPath + "/files/contentfile/");
}
}