项目背景
某项目背景下,希望前后端开发分离,运行时前后端需共用端口,需要注意的是:要求在nginx反向代理之前就实现共用端口,所以最简单的方案就是采用spring-boot 路由来编码实现代理,这里只论证了技术点,实际项目改造需要进一步优化
要点:
- 正确的设置静态文件目录,这里只是抛砖引玉,实际项目中请动态获取,或者根据配置获取
- 无论是html文件,还是静态文件,都需要获取到准确的minetype ,通过sdk提供的基本api是做不到的,所以我们采用了第三方库Tika,只有准确的描述ContentType,浏览器才能正确的加载静态资源
- 采用了持续输出流的方式写入响应结果,确保不会因为文件过大导致的内存溢出问题
具体代码如下:
package com.yyht.basic.mgt.controller;
import org.springframework.core.io.FileSystemResource;
import cn.kawins.mybatis.base.BaseController;
import com.yyht.basic.mgt.model.InstalledContent;
import io.swagger.annotations.Api;
import org.apache.tika.Tika;
import org.apache.tika.mime.MediaType;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.HandlerMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* 静态资源代理服务
*
* @author dangcc
*/
@RestController
@RequestMapping("")
@Api(tags = "静态资源代理")
public class TestController extends BaseController<InstalledContent> {
private final Path staticDir = Paths.get("D:\workspace\web\dist\");
@GetMapping(value = "/html/**")
public void getFile(HttpServletRequest request, HttpServletResponse response) throws IOException {
String filepath = (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
Pattern pattern = Pattern.compile(".*/html/(.*)");
Matcher matcher = pattern.matcher(filepath);
if (matcher.matches()) {
filepath= matcher.group(1);
}
if (StringUtils.isEmpty(filepath)) {
filepath = "index.html";
}
Path file = staticDir.resolve(filepath);
//检测文件是否存在
if (!Files.exists(file)) {
//返回404的状态
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
FileSystemResource resource = new FileSystemResource(file);
if (!resource.exists() || !resource.isReadable()) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
return;
}
//采取获取mimetype第三方库 这个很重要,因为mime对了浏览器才会正常加载文件流,否则会拒绝载入
//gradle 安装插件 implementation 'org.apache.tika:tika-core:1.27'
Tika tika = new Tika();
MediaType mediaType = MediaType.parse(tika.detect(file));
response.setContentType(mediaType.toString());
response.setContentLength((int) Files.size(file));
InputStream inputStream = null;
OutputStream outputStream = null;
try {
inputStream = resource.getInputStream();
outputStream = response.getOutputStream();
byte[] buffer = new byte[1024];
int bytesRead;
//输出流
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
} finally {
if (inputStream != null) {
inputStream.close();
}
if (outputStream != null) {
outputStream.close();
}
}
}
}