目录
标签:上传.下载.Excel.导入.导出;
一、简介
在项目中,文件管理是常见的复杂功能;
首先文件的类型比较多样,处理起来比较复杂,其次文件涉及大量的IO操作,容易引发内存溢出;
不同的文件类型有不同的应用场景;
比如:图片常用于头像和证明材料;Excel偏向业务数据导入导出;CSV偏向技术层面数据搬运;PDF和Word用于文档类的材料保存等;
下面的案例只围绕普通文件和Excel两种类型进行代码实现;
二、工程搭建
1、工程结构

2、依赖管理
普通文件的上传下载,依赖spring-boot框架即可,而Excel类型选择easyexcel组件,该组件内部依赖了apache-poi组件的4.1.2版本;- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <version>${spring-boot.version}</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>easyexcel</artifactId>
- <version>${easyexcel.version}</version>
- <exclusions>
- <exclusion>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </exclusion>
- </exclusions>
- </dependency>
复制代码 三、上传下载
1、配置管理
在配置文件中,添加max-file-size单个文件大小限制和max-request-size请求最大限制两个核心参数;
需要说明的一点是:如何设定参数值的大小,与业务场景和服务器的处理能力都有关系,在测试的过程中优化即可;- spring:
- # 文件配置
- servlet:
- multipart:
- enabled: true
- # 文件单个限制
- max-file-size: 10MB
- # 请求最大限制
- max-request-size: 20MB
复制代码 2、上传下载
这里提供一个文件批量上传接口和一个文件下载接口,把文件管理在工程中的resources/file目录下,下载接口中需要指定该目录下的文件名称;- @RestController
- public class FileWeb {
- private static final Logger logger = LoggerFactory.getLogger(FileWeb.class);
- @Resource
- private FileService fileService ;
- /**
- * 文件上传
- */
- @PostMapping("/file/upload")
- public String upload (HttpServletRequest request,
- @RequestParam("file") MultipartFile[] fileList) throws Exception {
- String uploadUser = request.getParameter("uploadUser");
- if (uploadUser.isEmpty()){
- return "upload-user is empty";
- }
- logger.info("upload-user:{}",uploadUser);
- for (MultipartFile multipartFile : fileList) {
- // 解析文件信息和保存
- fileService.dealFile(multipartFile);
- }
- return "success" ;
- }
- /**
- * 文件下载
- */
- @GetMapping("/file/download")
- public void upload (@RequestParam("fileName") String fileName,
- HttpServletResponse response) throws Exception {
- if (!fileName.isBlank()){
- String filePath = ResourceUtils.getURL("m1-04-boot-file/src/main/resources/file").getPath();
- File file = new File(filePath,fileName) ;
- response.setHeader("Content-Disposition",
- "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8));
- response.setContentType("application/octet-stream");
- Files.copy(Paths.get(file.getPath()), response.getOutputStream());
- }
- }
- }
- /**
- * 文件服务类
- */
- @Service
- public class FileService {
- private static final Logger logger = LoggerFactory.getLogger(FileService.class);
- public void dealFile (MultipartFile multipartFile) throws Exception {
- logger.info("Name >> {}",multipartFile.getName());
- logger.info("OriginalFilename >> {}",multipartFile.getOriginalFilename());
- logger.info("ContentType >> {}",multipartFile.getContentType());
- logger.info("Size >> {}",multipartFile.getSize());
- // 文件输出地址
- String filePath = ResourceUtils.getURL("m1-04-boot-file/src/main/resources/file").getPath();
- File writeFile = new File(filePath, multipartFile.getOriginalFilename());
- multipartFile.transferTo(writeFile);
- }
- }
复制代码 使用Postman测试文件批量上传接口:

四、Excel文件
1、Excel创建
基于easyexcel组件中封装的EasyExcel工具类,继承自EasyExcelFactory工厂类,实现Excel单个或多个Sheet的创建,并且在单个Sheet中写多个Table数据表;- @Service
- public class ExcelService {
- /**
- * Excel-写单个Sheet
- */
- public static void writeSheet () throws Exception {
- // 文件处理
- String basePath = getAbsolutePath();
- File file = new File(basePath+"/easy-excel-01.xlsx") ;
- checkOrCreateFile(file);
- // 执行写操作
- EasyExcel.write(file).head(DataVO.class)
- .sheet(0,"用户信息").doWrite(DataVO.getSheet1List());
- }
- /**
- * Excel-写多个Sheet
- */
- public static void writeSheets () throws Exception {
- // 文件处理
- String basePath = getAbsolutePath();
- File file = new File(basePath+"/easy-excel-02.xlsx") ;
- checkOrCreateFile(file);
- ExcelWriter excelWriter = null;
- try {
- excelWriter = EasyExcel.write(file).build();
- // Excel-Sheet1
- WriteSheet writeSheet1 = EasyExcel.writerSheet(0,"分页1").head(DataVO.class).build();
- // Excel-Sheet2
- WriteSheet writeSheet2 = EasyExcel.writerSheet(1,"分页2").head(DataVO.class).build();
- // Excel-Sheet3,写两个Table
- WriteSheet writeSheet3 = EasyExcel.writerSheet(2,"分页3").build();
- WriteTable dataTable = EasyExcel.writerTable(0).head(DataVO.class).build();
- WriteTable dataExtTable = EasyExcel.writerTable(1).head(DataExtVO.class).build();
- // 执行写操作
- excelWriter.write(DataVO.getSheet1List(), writeSheet1);
- excelWriter.write(DataVO.getSheet2List(), writeSheet2);
- excelWriter.write(DataVO.getSheet1List(),writeSheet3,dataTable) ;
- excelWriter.write(DataExtVO.getSheetList(),writeSheet3,dataExtTable) ;
- } catch (Exception e){
- e.printStackTrace();
- } finally {
- if (excelWriter != null){
- excelWriter.close();
- }
- }
- }
- }
- /**
- * 实体类,这里的注解会解析为Excel中的表头
- */
- public class DataVO {
- @ExcelProperty("编号")
- private Integer id ;
- @ExcelProperty("名称")
- private String name ;
- @ExcelProperty("手机号")
- private String phone ;
- @ExcelProperty("城市")
- private String cityName ;
- @ExcelProperty("日期")
- private Date date ;
- }
复制代码 文件效果:

2、Excel读取
对于读取Excel文件来说,则需要根据具体的样式来定了,在easyexcel组件中还可以添加读取过程的监听器;- @Service
- public class ExcelService {
- /**
- * Excel-读取数据
- */
- public static void readExcel () throws Exception {
- // 文件处理
- String basePath = getAbsolutePath();
- File file = new File(basePath+"/easy-excel-01.xlsx") ;
- if (!file.exists()){
- return ;
- }
- // 读取数据
- List<DataVO> dataList = EasyExcel.read(file).head(DataVO.class)
- .sheet(0).headRowNumber(1).doReadSync();
- dataList.forEach(System.out::println);
- }
- /**
- * Excel-读取数据使用解析监听器
- */
- public static void readExcelListener () throws Exception {
- // 文件处理
- String basePath = getAbsolutePath();
- File file = new File(basePath+"/easy-excel-01.xlsx") ;
- if (!file.exists()){
- return ;
- }
- // 读取数据,并且使用解析监听器
- DataListener dataListener = new DataListener() ;
- List<DataVO> dataSheetList = EasyExcel.read(file,dataListener).head(DataVO.class)
- .sheet(0).headRowNumber(1).doReadSync();
- dataSheetList.forEach(System.out::println);
- }
- }
复制代码 3、解析监听
继承AnalysisEventListener类,并重写其中的方法,可以监听Excel的解析过程,或者添加一些自定义的处理逻辑;- public class DataListener extends AnalysisEventListener<DataVO> {
- /**
- * 接收解析的数据块
- */
- @Override
- public void invoke(DataVO data, AnalysisContext context) {
- System.out.println("DataListener:"+data);
- }
- /**
- * 接收解析的表头
- */
- @Override
- public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
- System.out.println("DataListener:"+headMap);
- }
- @Override
- public void doAfterAllAnalysed(AnalysisContext context) {
- System.out.println("DataListener:after...all...analysed");
- }
- }
复制代码 4、导入导出
实际上Excel文件的导入导出,原理与文件的上传下载类似,只不过这里使用easyexcel组件中的API来直接处理Excel的写和读;- @RestController
- public class ExcelWeb {
- @GetMapping("excel/download")
- public void download(HttpServletResponse response) throws IOException {
- response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
- response.setCharacterEncoding("utf-8");
- String fileName = URLEncoder.encode("Excel数据", StandardCharsets.UTF_8).replaceAll("\\+", "%20");
- response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
- EasyExcel.write(response.getOutputStream(), DataVO.class).sheet("用户").doWrite(DataVO.getSheet1List());
- }
- @ResponseBody
- @PostMapping("excel/upload")
- public String upload(@RequestParam("file") MultipartFile file) throws IOException {
- List<DataVO> dataList = EasyExcel
- .read(file.getInputStream(), DataVO.class, new DataListener()).sheet().doReadSync();
- dataList.forEach(System.out::println);
- return "success";
- }
- }
复制代码 使用Postman测试单个Excel上传接口:

五、参考源码
- 文档仓库:
- https://gitee.com/cicadasmile/butte-java-note
- 源码仓库:
- https://gitee.com/cicadasmile/butte-spring-parent
复制代码 免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |