Java文件上传与下载

122 阅读2分钟

在项目开发中,我们经常要用到文件上传和下载,本章主要介绍简单文件上传下载功能的实现。

文件上传

因为项目很多地方要用到上传功能,所以抽取出来一个公共的Controller,需要使用文件上传下载的控制器继承BaseController就好了。返回文件名是为了在前端回显,JsonResult封装了响应结果信息。

注意:项目中配置了额外的静态资源目录,返回的是相对路径(相对于静态资源目录的路径),如/role/a.png表示的是D:/uploads/mhxysy/role/a.png或者项目resources目录下META-INF/resources、public、resources、static下的/role/a.jpg。

application.properties的部分内容:

文件上传路径

uploads.path=D:/uploads/mhxysy
**

配置静态资源文件夹,默认是static文件夹

**
spring.web.resources.static->locations=file:${uploads.path},classpath:static

JsonResult代码:

@Data
public class JsonResult<T> {
    /**
     * 响应状态码
     * 200, 400, 401, 403, 404, 406, 409, 500
     */
    private Integer code;
    /**
     * 响应提示信息
     */
    private String message;
    /**
     * 响应数据
     */
    private T data;
 
    // 省略的其他代码...
 
    public static <T> JsonResult<T> success(String message, T data) {
        JsonResult<T> jsonResult = new JsonResult<>();
 
        jsonResult.setCode(ResponseCode.SUCCESS.getValue());
        jsonResult.setMessage(message);
        jsonResult.setData(data);
 
        return jsonResult;
    }
 
    // 省略的其他代码...
 
}

BaseController代码:

public class BaseController {
    /**
     * 文件上传根路径
     */
    @Value("${uploads.path}")
    protected String root;
 
    // 省略的其他代码...
 
    /**
     * 图片上传
     * @param file MultipartFile对象
     * @param directory 文件上传目录
     * @return JsonResult<String>
     */
    public JsonResult<String> upload(MultipartFile file, String directory) throws IOException {
        // 获取文件名
        String fileName = StringUtils.getFileName(file);
        // 创建目标对象
        File targetFile = new File(root + directory, fileName);
 
        // 保存文件
        file.transferTo(targetFile);
 
        return JsonResult.success(null, directory + "/" + fileName);
    }
 
}

StringUtils工具类代码:获取当前时间生成uuid,作为保存文件名

/**
 * String工具类
 */
public class StringUtils {
    // 省略的其他代码...
 
    /**
     * 根据当前时间生成UUID
     * @return String
     */
    public static String uuid() {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss");
 
        return format.format(date);
    }
 
    /**
     * 通过文件名获取文件类型
     * @param fileName 文件名
     */
    public static String getFileType(String fileName) {
        // 得到文件名中最后一次出现"."的位置
        int index = fileName.lastIndexOf('.');
 
        return fileName.substring(index);
    }
 
    /**
     * 获取文件名
     * @param file MultipartFile对象
     * @return String 由当前时间生成的新文件名
     */
    public static String getFileName(MultipartFile file) {
        // 得到上传文件的原始文件名
        String filename = file.getOriginalFilename();
 
        // 判断文件名是否为空
        if (isNullOrEmpty(filename)) {
            throw new RuntimeException("获取文件名失败!");
        }
 
        // 返回uuid.文件类型
        // 例如:20220618131456.jpg
        return uuid() + getFileType(filename);
    }
 
}

文件下载

@Slf4j
@RestController
@RequestMapping(path = "/song", produces="application/json; charset=utf-8")
public class SongController extends BaseController {
    /**
     * 下载歌曲
     * @param id 歌曲id
     * @param url 歌曲文件URL
     * @param response HttpServletResponse对象
     * @throws IOException read()和write()方法抛出的异常
     */
    @RequestMapping(value = "/download", method = RequestMethod.GET)
    public void download(String id, String url, HttpServletResponse response) throws IOException {
        FileInputStream fis = null;
        OutputStream os = null;
        Song song = service.selectById(id);
 
        // 下载的歌曲文件名
        String name = song.getSinger() + " - " + song.getName() + StringUtils.getFileType(url);
 
        try {
            // 创建File对象
            File file = new File(root, url);
 
            log.debug("下载文件名:{}", file);
 
            if (file.isFile()) {
                // 设置内容类型
                response.setContentType("application/octet-stream");
                // 支持中文名称文件,需要对header进行单独设置,不然下载的文件名会出现乱码或者无法显示的情况
                String fileName = new String(name.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
                // 设置响应头,控制浏览器下载该文件
                response.setHeader("Content-Disposition", "attachement;filename=" + fileName);
 
                fis = new FileInputStream(file); // 读取文件
                os = response.getOutputStream(); // 创建文件输出流对象
 
                int len;
                byte[] buf = new byte[1024];
 
                while ((len = fis.read(buf)) != -1) {
                    os.write(buf, 0, len);
                }
            } else {
               log.debug("文件不存在,下载失败···");
            }
        } finally {
            if (fis != null) {
                fis.close();
            }
            if (os != null) {
                os.close();
            }
        }
    }
}