在项目开发中,我们经常要用到文件上传和下载,本章主要介绍简单文件上传下载功能的实现。
文件上传
因为项目很多地方要用到上传功能,所以抽取出来一个公共的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();
}
}
}
}