Java Web 图片上传解决方案:解决 Tomcat 重新部署导致图片丢失问题

目录

裴先生
裴先生
发布于 2020-12-03 / 0 阅读
0
0
原创

在 Java Web 开发过程中,不免会遇到图片上传的场景。本文提供了一套完整的解决方案,解决 Tomcat 重新部署时图片资源丢失的问题。

问题描述

第一个问题:虚拟路径问题

在 Tomcat 上部署的项目获取到的是 webapps 下面的路径:

// 上传后的临时存储的路径
String filePath = request.getSession().getServletContext().getRealPath("blogImages");

第二个问题:重新部署导致资源丢失

Tomcat 在项目重新部署时会先将 webapps 下面全部清空,然后解压 war 包重新启动,此时之前的图片资源就会丢失。

  • 重新部署之前:图片资源文件夹 blogImages 存在

D457A83B-DDFF-4301-A57C-0CEB023371E4.png

  • 重新部署之后:图片资源文件夹 blogImages 不存在了

DFF3227F-D610-4657-A190-D8DE8A4F6A93.png

解决方案

第一步:双重存储策略

在图片上传时,同时保存到两个位置:临时路径和服务器本地磁盘路径。

完整的上传代码:

@PostMapping("/fileUpload")
public List<Map<String, String>> fileUpload(@RequestParam(value = "file") MultipartFile file, HttpServletRequest request) {
    // 原始文件名
    String fileName = file.getOriginalFilename();
    assert fileName != null;
    // 获取后缀名
    String suffixName = fileName.substring(fileName.lastIndexOf("."));
    // 上传后的临时存储的路径
    String filePath = request.getSession().getServletContext().getRealPath("blogImages");
    // 生成一个新文件名
    fileName = UUID.randomUUID() + suffixName;
    // 每一天生成生成日期目录,方便管理
    String fileAdd = new SimpleDateFormat("yyyyMMdd").format(new Date());
    //获取文件夹路径
    filePath = filePath + File.separator + fileAdd + File.separator;
    log.info("path:{}", filePath);
    File dest = new File(filePath + "/" + fileName);
    // 先判断文件是否存在
    if (!dest.getParentFile().exists()) {
        boolean mkdirs = dest.getParentFile().mkdirs();
    }
    String src = dest.getAbsolutePath();
    //根据自己系统的resource 目录所在位置进行自行配置 F:\IdeaProjects\blog\src\main\resources\static\images\blogImages
    String destDir = System.getProperty("user.dir") + File.separator + "src" + File.separator + "main" + File.separator + "resources" + File.separator + "static" + File.separator + "images" + File.separator + "blogImages" + File.separator + fileAdd + File.separator;
    File destFile = new File(destDir + fileName);
    try {
        file.transferTo(dest);
        if (!destFile.getParentFile().exists()) {
            boolean mkdirs = dest.getParentFile().mkdirs();
        }
        copyFile(src, destDir, fileName);
    } catch (IOException e) {
        e.printStackTrace();
    }
    String imageSrc = "/static/blogImages/" + fileAdd + "/" + fileName;
    log.info("imageSrc:{}", imageSrc);
    List<Map<String, String>> result = new ArrayList<>();
    Map<String, String> map = new HashMap<>();
    map.put("imageSrcValue", prefixRequestUrl + imageSrc);
    map.put("imageSrc", prefixRequestUrl + imageSrc);
    result.add(map);
    return result;
}

文件复制方法:

/**
 * 文件复制
 *
 * @param src
 * @param destDir
 * @param fileName
 * @throws IOException
 */
public void copyFile(String src, String destDir, String fileName) throws IOException {
    FileInputStream in = new FileInputStream(src);
    File fileDir = new File(destDir);
    if (!fileDir.isDirectory()) {
        fileDir.mkdirs();
    }
    File file = new File(fileDir, fileName);

    if (!file.exists()) {
        file.createNewFile();
    }
    FileOutputStream out = new FileOutputStream(file);
    int c;
    byte buffer[] = new byte[1024];
    while ((c = in.read(buffer)) != -1) {
        for (int i = 0; i < c; i++) {
            out.write(buffer[i]);
        }
    }
    in.close();
    out.close();
}

这样会在服务器本地磁盘路径上保留一份图片副本:

/usr/local/tomcat/src/main/resources/static/images/blogImages

第二步:配置 Tomcat Context

  1. 找到 Tomcat 配置目录
cd /usr/local/tomcat/conf/
  1. 修改 server.xml 文件
vim server.xml
  1. <Host> 标签内添加 <Context> 配置
<Host name="localhost"  appBase="webapps"
      unpackWARs="true" autoDeploy="true">
    <!-- 配置外部静态资源映射 -->
    <Context docBase="/usr/local/tomcat/src/main/resources/static/images/blogImages" 
             path="/myBlog/static/blogImages" 
             reloadable="true"/>
    
    <!-- Access log processes all example.
         Documentation at: /docs/config/valve.html
         Note: The pattern used is equivalent to using pattern="common" -->
    <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
           prefix="localhost_access_log" suffix=".txt"
           pattern="%h %l %u %t &quot;%r&quot; %s %b" />
</Host>

总结

通过以上两步操作:

  1. 将上传的图片同时保存到临时路径和服务器本地路径
  2. 配置 Tomcat 的 Context 映射外部静态资源

重启 Tomcat 后,即使重新部署应用,图片资源也不会丢失,因为它们存储在 Tomcat 外部的固定路径中。

原创

版权声明:本博客原创文章,由 裴先生 2020年12月03日 发表。
转载说明:除特殊说明外本站文章皆由 CC BY-NC-SA 4.0 协议发布,转载须注明出处。


评论