企业级-实现Nginx的静态文件服务器映射

作者:fyupeng

技术专栏:☞ https://github.com/fyupeng

项目地址:☞ https://github.com/fyupeng/distributed-blog-system-api


留给读者

开发人员往往会经常需要通过浏览器下载文件、图片或者PDF或者缩略图等,这时候我们可以根据自己的需求自定义设置,安全性就可以由自己来把握。

一、介绍

难点主要在于把文件路径当成参数传给后端,后端根据一定的规则处理,将结果写入响应返回给浏览器。

优点:

  • 使用懒加载方式,如果本地有,就不从OSS获取,本地没有先从OSS下载到本地,以便频繁下载文件时降低OSS的出入流量。
  • 待补充

二、代码

java 复制代码
/**
 * @Auther: fyp
 * @Date: 2024/7/26
 * @Description: 文件预览处理器
 * @Package: com.gwssi.common.web
 * @Version: 1.0
 */

@Controller
public class FilePreviewController {

    //本地测试可改为自己的路径
    //private static final String FILE_DIRECTORY = "D:/upload/";
    private static final String FILE_DIRECTORY = "/data/hqzr/";

    @ResponseBody
    @RequestMapping(value = "/file/{fileUrl}/**",  method = RequestMethod.GET)
    public void getFile(@PathVariable String fileUrl, HttpServletRequest req, HttpServletResponse resp) throws IOException {


        String path = req.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE).toString();
        String path2 = req.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE).toString();
        String args = new AntPathMatcher().extractPathWithinPattern(path2, path);

        args = args.replace(".do", "");

        fileUrl = fileUrl + "/" + args;

        File file = new File(FILE_DIRECTORY + fileUrl);

        byte[] bytes = null;

        // 添加安全检查,确保文件确实在预期的目录中
        if (!file.exists() || !file.isFile() || !file.getCanonicalPath().startsWith(new File(FILE_DIRECTORY).getCanonicalPath())) {
            // 处理非法访问,例如返回404
            File parentDir = file.getParentFile();
            if (!parentDir.exists()) {
                parentDir.mkdirs(); // 确保文件所在的目录存在
            }
            bytes = OssUtil.downloadByBytes(FILE_DIRECTORY + fileUrl);
            if (null != bytes) {
                FileOutputStream fos = new FileOutputStream(file);
                fos.write(bytes);
                fos.close();
                resp.reset(); // 非常重要
            } else {
                Map<String, String> map = new HashMap<String, String>();
                map.put("code", "-100");
                map.put("msg", "文件预览失败");
                ResponseUtil.returnFrontByJSON(map, resp);
            }
        }
        // 设置适当的响应头(纯下载方式)
        //resp.setContentType("application/octet-stream; charset=utf-8");
        //resp.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
        // 直接预览打开
        resp.setContentType("image/png"); // 设置返回的文件类型
        resp.addHeader("Content-Length", String.valueOf(file.length()));  //文件大小

        // 使用ServletOutputStream将图片数据写入响应
        try (ServletOutputStream outputStream = resp.getOutputStream();
             BufferedInputStream inputStream = new BufferedInputStream(new FileInputStream(file))) {

            // 从文件服务器获取
            if (null != bytes) {
                outputStream.write(bytes);
            } else {
                // 从本地获取
                byte[] buffer = new byte[4096];
                int bytesRead = -1;

                // 读取文件内容并写入响应
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
            }
            // 刷新输出流,确保所有数据都被发送
            outputStream.flush();
        }
    }


 private String getMimeType(File file) {
      // 这里可以根据文件扩展名返回相应的MIME类型
      // 这里只是一个简单的示例,实际应用中可能需要更复杂的逻辑
      String filename = file.getName().toLowerCase();
      if (filename.endsWith(".png")) {
          return MediaType.IMAGE_PNG_VALUE;
      } else if (filename.endsWith(".jpg") || filename.endsWith(".jpeg")) {
          return MediaType.IMAGE_JPEG_VALUE;
      }
      // 添加更多MIME类型判断...
      return MediaType.APPLICATION_OCTET_STREAM_VALUE; // 默认类型
    }
}

三、总结

简洁、高效、实用!

相关推荐
蛋蛋的就会顺顺的3 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
需要8264 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡4 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
伯恩bourne6 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
silvamux_6 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi
省钱兄--zs6 小时前
深圳24小时自助健身房软硬件解决方案实战指南与开发流程详解
java·数据仓库·spring boot·小程序·架构
顽疲7 小时前
Java vue 养老系统源码详解:月账单 care_month_bill 与 Quartz 扣费 Job 实践
java·开发语言·vue.js·vue养老·springboot养老·java养老
Wang's Blog7 小时前
Java 项目实战: 交友项目 - 安装开发工具与环境准备
java·开发语言·交友
用户21296835261687 小时前
开源了一个 Java 多智能体 LLM 框架 Baton:一个依赖,把 Agent 循环、工具调用、记忆、编排全配齐
java·llm
helmsail7 小时前
05 管理活动与选品
java