項目背景
某項目背景下,希望前後端開發分離,運行時前後端需共用端口,需要注意的是:要求在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();
}
}
}
}