本文简介

在java开发中文件的上传、下载、删除性能必定是很常见的,本文次要基于上传图片或文件到指定的地位开展,通过具体的代码和工具类,讲述java如何实现文件的上传、下载、删除。

后续我会集成更多的云存储空间上传,像阿里云、腾讯云、华为云、又拍云等等,本文后续会把这些相干的上传操作以链接的模式集成到本文中,到家能够先点个关注呦。

本文设计到的所有代码,均在文末的github开源我的项目里,感兴趣的敌人能够帮忙点个star

性能实现

话不多说,间接开整

首先,须要在yml配置文件外面配置文件上传的门路,这里构想的是图片一个目录,文件一个目录,次要是为了演示,大家能够依据本人的需要进行配置。

file:  local:    maxFileSize: 10485760    imageFilePath: D:/test/image/    docFilePath: D:/test/file/

接下来,让咱们一起看一下性能实现的外围代码。

这里只是为了展现性能实现,一些非相干的代码没有贴,能够在文末github源码外面查看更多。

这里是配置文件的一个配置类,这要为了方便使用yml配置文件外面的配置。

package com.maple.demo.config.bean;import lombok.Data;import org.springframework.beans.factory.annotation.Value;import org.springframework.context.annotation.Configuration;/** * @author 笑小枫 * @date 2022/7/22 * @see <a href="https://www.xiaoxiaofeng.com">https://www.xiaoxiaofeng.com</a> */@Data@Configurationpublic class FileProperties {    // ---------------本地文件配置 start------------------    /**     * 图片存储门路     */    @Value("${file.local.imageFilePath}")    private String imageFilePath;        /**     * 文档存储门路     */    @Value("${file.local.docFilePath}")    private String docFilePath;    /**     * 文件限度大小     */    @Value("${file.local.maxFileSize}")    private long maxFileSize;    // --------------本地文件配置 end-------------------    }

定义WebMvcConfig实现WebMvcConfigurer,指向咱们文件的寄存门路。

package com.maple.demo.config;import com.maple.demo.config.bean.FileProperties;import lombok.AllArgsConstructor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;/** * @author 笑小枫 * @date 2022/7/22 * @see <a href="https://www.xiaoxiaofeng.com">https://www.xiaoxiaofeng.com</a> */@Configuration@AllArgsConstructorpublic class WebMvcConfig implements WebMvcConfigurer {    private final FileProperties fileProperties;    @Override    public void addResourceHandlers(ResourceHandlerRegistry registry) {        //重写办法        //批改tomcat 虚构映射        //定义图片寄存门路 这里加/example是为了测试避开零碎的token校验,理论拜访地址依据本人需要来        registry.addResourceHandler("/example/images/**").                addResourceLocations("file:" + fileProperties.getImageFilePath());        //定义文档寄存门路        registry.addResourceHandler("/example/doc/**").                addResourceLocations("file:" + fileProperties.getDocFilePath());    }}

文件上传下载的外围工具类,想白嫖的,copy它就对了...

package com.maple.demo.util.file;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.bean.FileProperties;import com.maple.demo.config.exception.MapleCheckException;import lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang3.StringUtils;import org.springframework.stereotype.Component;import org.springframework.web.multipart.MultipartFile;import javax.servlet.ServletOutputStream;import javax.servlet.http.HttpServletResponse;import java.io.File;import java.io.FileInputStream;import java.io.IOException;import java.io.UnsupportedEncodingException;import java.net.URLDecoder;import java.nio.charset.StandardCharsets;import java.nio.file.Files;import java.text.SimpleDateFormat;import java.util.*;/** * @author 笑小枫 * @date 2022/7/22 * @see <a href="https://www.xiaoxiaofeng.com">https://www.xiaoxiaofeng.com</a> */@Slf4j@Component@AllArgsConstructorpublic class FileUtil {    private final FileProperties fileProperties;    private static final List<String> FILE_TYPE_LIST_IMAGE = Arrays.asList(            "image/png",            "image/jpg",            "image/jpeg",            "image/bmp");    public String uploadImage(MultipartFile file) {        // 查看图片类型        String contentType = file.getContentType();        if (!FILE_TYPE_LIST_IMAGE.contains(contentType)) {            throw new MapleCheckException(ErrorCode.COMMON_ERROR, "上传失败,不容许的文件类型");        }        int size = (int) file.getSize();        if (size > fileProperties.getMaxFileSize()) {            throw new MapleCheckException(ErrorCode.COMMON_ERROR, "文件过大");        }        String fileName = file.getOriginalFilename();        //获取文件后缀        String afterName = StringUtils.substringAfterLast(fileName, ".");        //获取文件前缀        String prefName = StringUtils.substringBeforeLast(fileName, ".");        //获取一个工夫毫秒值作为文件名        fileName = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + "_" + prefName + "." + afterName;        File filePath = new File(fileProperties.getImageFilePath(), fileName);        //判断文件是否曾经存在        if (filePath.exists()) {            throw new MapleCheckException(ErrorCode.COMMON_ERROR, "文件曾经存在");        }        //判断文件父目录是否存在        if (!filePath.getParentFile().exists()) {            filePath.getParentFile().mkdirs();        }        try {            file.transferTo(filePath);        } catch (IOException e) {            log.error("图片上传失败", e);            throw new MapleCheckException(ErrorCode.COMMON_ERROR, "图片上传失败");        }        return fileName;    }    public List<Map<String, Object>> uploadFiles(MultipartFile[] files) {        int size = 0;        for (MultipartFile file : files) {            size = (int) file.getSize() + size;        }        if (size > fileProperties.getMaxFileSize()) {            throw new MapleCheckException(ErrorCode.COMMON_ERROR, "文件过大");        }        List<Map<String, Object>> fileInfoList = new ArrayList<>();        for (int i = 0; i < files.length; i++) {            Map<String, Object> map = new HashMap<>();            String fileName = files[i].getOriginalFilename();            //获取文件后缀            String afterName = StringUtils.substringAfterLast(fileName, ".");            //获取文件前缀            String prefName = StringUtils.substringBeforeLast(fileName, ".");            String fileServiceName = new SimpleDateFormat("yyyyMMddHHmmss")                    .format(new Date()) + i + "_" + prefName + "." + afterName;            File filePath = new File(fileProperties.getDocFilePath(), fileServiceName);            // 判断文件父目录是否存在            if (!filePath.getParentFile().exists()) {                filePath.getParentFile().mkdirs();            }            try {                files[i].transferTo(filePath);            } catch (IOException e) {                log.error("文件上传失败", e);                throw new MapleCheckException(ErrorCode.COMMON_ERROR, "文件上传失败");            }            map.put("fileName", fileName);            map.put("filePath", filePath);            map.put("fileServiceName", fileServiceName);            fileInfoList.add(map);        }        return fileInfoList;    }    /**     * 批量删除文件     *     * @param fileNameArr 服务端保留的文件的名数组     */    public void deleteFile(String[] fileNameArr) {        for (String fileName : fileNameArr) {            String filePath = fileProperties.getDocFilePath() + fileName;            File file = new File(filePath);            if (file.exists()) {                try {                    Files.delete(file.toPath());                } catch (IOException e) {                    e.printStackTrace();                    log.warn("文件删除失败", e);                }            } else {                log.warn("文件: {} 删除失败,该文件不存在", fileName);            }        }    }    /**     * 下载文件     */    public void downLoadFile(HttpServletResponse response, String fileName) throws UnsupportedEncodingException {        String encodeFileName = URLDecoder.decode(fileName, "UTF-8");        File file = new File(fileProperties.getDocFilePath() + encodeFileName);        // 下载文件        if (!file.exists()) {            throw new MapleCheckException(ErrorCode.COMMON_ERROR, "文件不存在!");        }        try (FileInputStream inputStream = new FileInputStream(file);             ServletOutputStream outputStream = response.getOutputStream()) {            response.reset();            //设置响应类型    PDF文件为"application/pdf",WORD文件为:"application/msword", EXCEL文件为:"application/vnd.ms-excel"。            response.setContentType("application/octet-stream;charset=utf-8");            //设置响应的文件名称,并转换成中文编码            String afterName = StringUtils.substringAfterLast(fileName, "_");            //保留的文件名,必须和页面编码统一,否则乱码            afterName = response.encodeURL(new String(afterName.getBytes(), StandardCharsets.ISO_8859_1.displayName()));            response.setHeader("Content-type", "application-download");            //attachment作为附件下载;inline客户端机器有装置匹配程序,则间接关上;留神扭转配置,革除缓存,否则可能不能看到成果            response.addHeader("Content-Disposition", "attachment;filename=" + afterName);            response.addHeader("filename", afterName);            //将文件读入响应流            int length = 1024;            byte[] buf = new byte[1024];            int readLength = inputStream.read(buf, 0, length);            while (readLength != -1) {                outputStream.write(buf, 0, readLength);                readLength = inputStream.read(buf, 0, length);            }            outputStream.flush();        } catch (Exception e) {            e.printStackTrace();        }    }}

编写一个测试的controller吧

package com.maple.demo.controller;import com.maple.demo.config.bean.ErrorCode;import com.maple.demo.config.exception.MapleCheckException;import com.maple.demo.util.file.FileUtil;import io.swagger.annotations.Api;import io.swagger.annotations.ApiOperation;import lombok.AllArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.web.bind.annotation.*;import org.springframework.web.multipart.MultipartFile;import javax.servlet.http.HttpServletResponse;import java.util.List;import java.util.Map;/** * @author 笑小枫 * @date 2022/7/22 * @see <a href="https://www.xiaoxiaofeng.com">https://www.xiaoxiaofeng.com</a> */@Slf4j@RestController@AllArgsConstructor@Api(tags = "文件相干操作接口")@RequestMapping("/example")public class TestFileController {    private final FileUtil fileUtil;    @PostMapping("/uploadImage")    @ApiOperation("图片上传")    public String uploadImage(@RequestParam(value = "file") MultipartFile file) {        if (file.isEmpty()) {            throw new MapleCheckException(ErrorCode.COMMON_ERROR, "图片内容为空,上传失败!");        }        return fileUtil.uploadImage(file);    }    @PostMapping("/uploadFiles")    @ApiOperation("文件批量上传")    public List<Map<String, Object>> uploadFiles(@RequestParam(value = "file") MultipartFile[] files) {        return fileUtil.uploadFiles(files);    }    @PostMapping("/deleteFiles")    @ApiOperation("批量删除文件")    public void deleteFiles(@RequestParam(value = "files") String[] files) {        fileUtil.deleteFile(files);    }    @GetMapping(value = "/download/{fileName:.*}")    @ApiOperation("文件下载性能")    public void download(@PathVariable("fileName") String fileName, HttpServletResponse response) {        try {            fileUtil.downLoadFile(response, fileName);        } catch (Exception e) {            log.error("文件下载失败", e);        }    }}

功能测试✌

单张图片上传

应用postman申请接口:http://localhost:6666/example/uploadImage

上传胜利后能够在对应的文件夹上面看到咱们上传的文件,如下图所示:

拜访上传的图片

上个case咱们上传了一张图片,咱们应该怎么进行拜访呢?这个咱们在WebMvcConfig文件中配置的,地址在yml文件中配置。

发送申请:http://localhost:6666/example/images/20220916153101_29170841.jpg

多文件上传

file反对数组模式的上传,测试上传链接:http://localhost:6666/example/uploadFiles

删除文件

测试删除文件链接,前面跟文件名即可:http://localhost:6666/example/deleteFiles?files=2022091615352...

删除胜利后,能够看到咱们多文件上传的两张图片仅剩一张了。

云空间文件上传

《JAVA实现上传文件到又拍云》

《JAVA应用阿里云OSS云存储》

对于笑小枫

本章到这里完结了,喜爱的敌人关注一下我呦,大伙的反对,就是我保持写下去的能源。

微信公众号:笑小枫

笑小枫集体博客:https://www.xiaoxiaofeng.com

CSDN:https://zhangfz.blog.csdn.net

本文源码:https://github.com/hack-feng/maple-demo