最终效果图(简单案例,模拟的是上传到本地,本应该是上传到服务器的)
1、依赖及yml配置
<!--文件上传下载-->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
在yml文件中配置存储的路径
url:
F://train/ # 本地存储文件的路径
2、数据库,只需要id,文件名,还有文件url就可以,我这里因为是模拟上传到本地,所以url都是本地盘符下的
建表sql语句
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for my_file
-- ----------------------------
DROP TABLE IF EXISTS `my_file`;
CREATE TABLE `my_file` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`file_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`file_url` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;
SET FOREIGN_KEY_CHECKS = 1;
3、创建文件的实体类与数据库表中字段对应
import lombok.Data;
@Data
public class MyFile {
private int id;
private String fileName;
private String fileUrl;
}
4、Mapper层使用MybatisPlus继承了BaseMapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.limou.pojo.MyFile;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface MyFileMapper extends BaseMapper<MyFile> {
}
5、Service层接口提供了三个方法,上传下载以及展示所有
import com.limou.pojo.MyFile;
import org.springframework.http.ResponseEntity;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
public interface MyFileService {
// 上传
Map<String, Object> uploadFile(MultipartFile file);
// 下载
ResponseEntity<byte[]> downloadFile(String fileUrl, String fileName);
// 查询所有
List<MyFile> list();
}
其中Service实现类是实现上传下载的核心,业务处理我们一般都写在service层
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.limou.mapper.MyFileMapper;
import com.limou.pojo.MyFile;
import com.limou.service.MyFileService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.*;
@Service
@Slf4j
public class MyFileServiceImpl implements MyFileService {
@Value("${url}")
private String address;
@Autowired
private MyFileMapper mapper;
/**
* 上传文件
* @param file 文件对象
* @return
*/
@Override
public Map<String, Object> uploadFile(MultipartFile file) {
Map<String, Object> map = new HashMap<>();
String lastName = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1);
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
// 获取当前系统日期
String dateTime = simpleDateFormat.format(new Date());
// 随机数
String uuid = UUID.randomUUID() + "";
// 最后要文件上传的路径
String fileAddress = address + dateTime + "/" + uuid + "." + lastName;
// 创建文件对象
File uploadFile = new File(fileAddress);
if (!uploadFile.isDirectory()) {
// 创建文件
uploadFile.mkdirs();
}
try {
file.transferTo(uploadFile);
} catch (IOException exception) {
log.error(exception.getMessage());
map.put("msg", "上传失败");
return map;
}
MyFile myFile = new MyFile();
myFile.setFileName(file.getOriginalFilename());
myFile.setFileUrl(fileAddress);
mapper.insert(myFile);
map.put("myFile", myFile);
map.put("msg", "上传成功");
return map;
}
/**
* 下载文件
* @param fileUrl 文件路径
* @param fileName 文件名
* @return
*/
@Override
public ResponseEntity<byte[]> downloadFile(String fileUrl, String fileName) {
QueryWrapper<MyFile> wrapper = new QueryWrapper<>();
wrapper.eq("file_url", fileUrl);
List<MyFile> myFiles = mapper.selectList(wrapper);
if (myFiles != null && myFiles.size() == 1) {
// 创建文件夹对象
File file = new File(fileUrl);
// 通过浏览器响应下载文件
HttpHeaders httpHeaders = new HttpHeaders();
// 二进制方式输出
httpHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
try {
String fileName2 = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
httpHeaders.set("Content-Disposition", "attachment;filename=" + fileName2);
// 转换成字节码
byte[] bytes = FileUtils.readFileToByteArray(file);
return new ResponseEntity<byte[]>(bytes, httpHeaders, HttpStatus.OK);
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
return null;
}
@Override
public List<MyFile> list() {
return mapper.selectList(null);
}
}
6、controller层只需要调用service层接口,对外提供访问的url就可以
import com.limou.pojo.MyFile;
import com.limou.service.MyFileService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
import java.util.Map;
@RequestMapping("/file")
@Controller
public class MyFileController {
@Autowired
private MyFileService myFileService;
// 上传
@RequestMapping("/upload")
public String uploadFile(@RequestParam("file") MultipartFile multipartFile){
myFileService.uploadFile(multipartFile);
return "redirect:list";
}
// 下载
@RequestMapping("/download")
public ResponseEntity<byte[]> downloadFile(String fileUrl, String fileName){
System.out.println("fileUrl:------" + fileUrl);
System.out.println("fileName:-----" + fileName);
return myFileService.downloadFile(fileUrl, fileName);
}
// 展示列表
@RequestMapping("/list")
public String list(Model model){
List<MyFile> list = myFileService.list();
System.out.println(list);
model.addAttribute("list", list);
return "fileList";
}
}
7、html代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head></head>
<body>
<h1>文件上传</h1>
<form action="upload" method="post" enctype="multipart/form-data">
<input type="file" name="file">
<input type="submit" value="上传">
</form>
<hr>
<h1>文件下载</h1>
<table class="table table-hover text-center">
<tr>
<th style="text-align:left; padding-left:20px;" width="100">ID</th>
<th>文件名</th>
<th>文件路径</th>
<th width="310">操作</th>
</tr>
<tr th:each="file : ${list}">
<td th:text="${file.id}"></td>
<td th:text="${file.fileName}"></td>
<td th:text="${file.fileUrl}"></td>
<td>
<a th:href="@{download(fileName=${file.fileName},fileUrl=${file.fileUrl})}">下载</a>
</td>
</tr>
</table>
</body>
</html>
- 下边这里是实现勾选批量下载为zip的方法
效果展示如下
前端html代码
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type"/>
<meta content="IE=edge" http-equiv="X-UA-Compatible">
<meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" name="viewport"/>
<meta content="webkit" name="renderer">
<title></title>
<link href="../css/pintuer.css" rel="stylesheet">
<link href="../css/admin.css" rel="stylesheet">
<script src="../js/jquery.js"></script>
<script src="../js/pintuer.js"></script>
</head>
<body>
<h1>文件上传</h1>
<form action="upload" enctype="multipart/form-data" method="post">
<input name="file" type="file">
<input type="submit" value="上传">
</form>
<hr>
<h1>文件下载</h1>
<form action="downloads">
<table class="table table-hover text-center">
<tr>
<th style="text-align:left; padding-left:20px;" width="100">ID</th>
<th>文件名</th>
<th>文件路径</th>
<th width="310">操作</th>
</tr>
<tr th:each="file : ${list}">
<td>
<input name="ids" th:value="${file.id}" type="checkbox">
<span th:text="${file.id}"></span>
</td>
<td th:text="${file.fileName}"></td>
<td th:text="${file.fileUrl}"></td>
<td>
<a th:href="@{download(fileName=${file.fileName},fileUrl=${file.fileUrl})}">下载</a>
</td>
</tr>
</table>
<input type="submit" value="批量下载">
</form>
</body>
</html>
contoller层代码(仍然是去直接调用service层代码,但需要前端传递多个id的信息,以及httpServletResponse对象,获取输出流)
// 批量下载
@RequestMapping("/downloads")
public void downloadFiles(String ids, HttpServletResponse httpServletResponse){
// System.out.println(ids);
myFileService.downloadFiles(ids, httpServletResponse);
}
service层代码
接口
// 批量下载
void downloadFiles(String ids, HttpServletResponse response);
实现类(核心)
// 批量下载
@Override
public void downloadFiles(String ids, HttpServletResponse response) {
List<Map> fileList = new ArrayList<>();
// 拿到id的集合
List<String> idList = Arrays.asList(ids.split(","));
// url集合
List<String> urlList = new ArrayList<>();
for (String id : idList) {
// 添加到url集合
urlList.add(mapper.selectById(id).getFileUrl());
}
try {
for (int i = 0; i < urlList.size(); i++) {
// 创建文件对象
File file = new File(urlList.get(i));
// 转换成字节
byte[] bytes = FileUtils.readFileToByteArray(file);
// 存入Map
Map map = new HashMap();
String fileName = UUID.randomUUID() + "." + urlList.get(i).substring(urlList.get(i).lastIndexOf(".") + 1);
map.put("fileName", fileName);
map.put("outByte", bytes);
fileList.add(map);
}
} catch (IOException exception) {
exception.printStackTrace();
}
try (ZipOutputStream zipOutputStream = new ZipOutputStream(response.getOutputStream())) {
// 创建 ZipEntry 对象
for (Map mapNow : fileList) {
ZipEntry zipEntry = new ZipEntry((String) mapNow.get("fileName"));
zipOutputStream.putNextEntry(zipEntry);
zipOutputStream.write((byte[]) mapNow.get("outByte"));
}
} catch (IOException exception) {
exception.printStackTrace();
}
}
其余部分同上
综合我的上一篇博客关于Excel的导入与导出,大致可以做到如下效果