spring-boot實現靜態資源代理

項目背景

某項目背景下,希望前後端開發分離,運行時前後端需共用端口,需要注意的是:要求在nginx反向代理之前就實現共用端口,所以最簡單的方案就是採用spring-boot 路由來編碼實現代理,這裏只論證了技術點,實際項目改造需要進一步優化

要點:

  1. 正確的設置靜態文件目錄,這裏只是拋磚引玉,實際項目中請動態獲取,或者根據配置獲取
  2. 無論是html文件,還是靜態文件,都需要獲取到準確的minetype ,通過sdk提供的基本api是做不到的,所以我們採用了第三方庫Tika,只有準確的描述ContentType,瀏覽器才能正確的加載靜態資源
  3. 採用了持續輸出流的方式寫入響應結果,確保不會因爲文件過大導致的內存溢出問題

具體代碼如下:

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();
            }
        }
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章