response.setHeader("Content-Disposition", "attachment; filename=" + new String("标准化物资".getBytes("UTF-8"), "ISO-8859-1") + ".xlsx");
只是swagger文件名称乱码可以尝试浏览器直接下载,我的文件乱码只存在有swagger接口下载中。
本来就是个很简单的导出xlsx文件到浏览器页面,但是中间写的时候还是遇到了一些问题的。
1、由于导出xlsx文件需要用到HSSFWorkbook,所以需要导入POI依赖
<!-- 导入、导出Excel --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.16</version> </dependency>
2、写个util类,封装生成excel的方法,这样的话以后需要导出其他excel文件时也可以直接使用。
首先要了解的是,生成excel必要的几个要素是:
HSSFWorkbook:excel的工作簿
HSSFSheet:excel的工作表
HSSFRow:excel的行
HSSFCell:excel的单元格
所以在封装方法时,设置了相应的入参对象:
dto: 字段用处有描述
package com.cmf.demo.model; import java.util.List; import lombok.Getter; import lombok.Setter; import lombok.ToString; @Getter @Setter @ToString public class ExcelInfo { /** * 数据所在的集合 */ private List list; /** * sheet表的标题 - 放在文件内第一行 */ private String[] title; /** * 对象的属性名,方便标题跟数据对齐 -- 根据反射可以获取对象中的值赋值 */ private String[] keys; /** * sheet表的名称 */ private String SheetName; /** * excel的名称 -- 如果导出excel到指定的目录需要加上名称 */ private String excelName; /** * excel表格保存的路径 -- 如果导出excel到指定的目录需要做为入参 */ private String path; }
util抽象方法: 该方法中也可以在最后加上导出excel到指定目录的方法,因为我只想展示下载到浏览器的效果,所以注释了导出到指定目录的代码
package com.cmf.demo.util; import com.cmf.demo.model.ExcelInfo; import java.io.IOException; import java.lang.reflect.Field; import java.util.List; import lombok.extern.slf4j.Slf4j; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.springframework.util.StringUtils; @Slf4j public class ExcelUtil { public static HSSFWorkbook createExcel(ExcelInfo excel)throws IOException, IllegalAccessException { //创建一个工作簿 HSSFWorkbook hssfWorkbook =new HSSFWorkbook(); //创建一个工作表(参数是sheet表的名称) HSSFSheet hssfSheet = hssfWorkbook.createSheet(excel.getSheetName()); //创建第一行sheet表中的内容,索引是从0开始,第一行是sheet表的标题栏 HSSFRow hssfRowHeader = hssfSheet.createRow(0); //标题数组 String[] title = excel.getTitle(); //创建单元格对象 HSSFCell cell =null; //遍历生成标题栏里面的标题单元格 for (int i =0; i < title.length; i++) { //遍历生成索引是0行的每一个标题单元格对象 cell = hssfRowHeader.createCell(i); //添加数据 cell.setCellValue(title[i]); } //内容集合 List list = excel.getList(); //属性名的数组,判断到底要在excel呈现出多少数据 String[] keys = excel.getKeys(); //导出内容 //集合的长度就是sheet表中内容的条数,比如(长度为3,内容就有三条,索引从1开始) for (int i =0; i < list.size(); i++) { HSSFRow hssfRowContext = hssfSheet.createRow(i +1); //利用反射将对象属性变成一个数组 Field[] listArray = list.get(i).getClass().getDeclaredFields(); for (int j =0; j < listArray.length; j++) { System.out.println(); //设置是否允许访问,而不是修改原来的访问权限修饰词。 listArray[j].setAccessible(true); for (int k =0; k < keys.length; k++) { if (StringUtils.hasText(keys[k])&&keys[k].equals(listArray[j].getName())) { cell = hssfRowContext.createCell(k); log.info("listArray[j]:"+listArray[j]+";list.get(i):"+list.get(i)); cell.setCellValue(listArray[j].get(list.get(i)).toString()); } } } } // String fileName = excel.getPath() + File.separator + excel.getExcelName() +".xls"; // try{ // File file = new File(fileName); // File parentFile = file.getParentFile(); // if (!parentFile.exists()){ // parentFile.mkdir(); // } // }catch (Exception e){ // log.info("目标文件不存在,新建失败"); // } // FileOutputStream fos =new FileOutputStream(fileName); // hssfWorkbook.write(fos); // fos.close(); return hssfWorkbook; } }
3、编写具体的用户信息导出逻辑
service:
public HSSFWorkbook excel(){ Condition condition = new Condition(UserEntity.class); condition.createCriteria().andEqualTo("userId","20030001"); // 通用mapper使用 List<UserEntity> entity= testMapper.selectByCondition(condition); ExcelInfo excel = new ExcelInfo(); excel.setList(entity); //标题数组 String[] title = new String[]{"用户号","用户名","用户状态"}; //对象字段名,根据字段名赋值 String[] keys = new String[]{"userId","userName","userStatus"}; excel.setTitle(title); excel.setKeys(keys); excel.setExcelName("测试导出用户信息"); excel.setSheetName("测试导出用户信息"); HSSFWorkbook hssfWorkbook = new HSSFWorkbook(); try { hssfWorkbook = ExcelUtil.createExcel(excel); } catch (IOException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } return hssfWorkbook; }
controller:
@PostMapping("/excel") @ApiOperation(notes = "测试导出信息",value = "测试导出用信息",httpMethod = "POST") public void getUser(HttpServletResponse response){ HSSFWorkbook hssfWorkbook = testService.excel(); BufferedOutputStream fos = null; try { response.setContentType("application/x-msdownload"); response.setCharacterEncoding("UTF-8"); response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder .encode("测试导出用户信息", "UTF-8")+".xlsx"); //设置文件名编码格式 fos = new BufferedOutputStream(response.getOutputStream()); hssfWorkbook.write(fos); fos.close(); }catch (Exception e) { log.error("excel生成报错", e); } }
4、代码一直到这里运行使用都很正常,但是我说的出现的问题是,我使用swagger调用这个接口后,可以正常的下载但是文件名一直是乱码的
这里我百度说是可能是编码格式设置有问题,不同的浏览器解码不一样,于是换了很多种方式但还是没用,后面考虑可能是我浏览器问题,就让同事连我的ip调了下还是不行,最后只能看看是否是swagger测试工具的编码问题了,我把post方法改成get请求调用,直接在浏览器url调用,就可以正常导出文件,且文件名不会乱码了(前端页面调用接口也是可以的)。至于swagger为什么一直乱码这个问题我还没搞清楚,后面知道了再更新吧!!知道的大佬希望留个言,谢了!
@GetMapping("/excel")
@ApiOperation(notes = "测试导出信息",value = "测试导出用信息",httpMethod = "GET")
参考文章:
1.https://blog.csdn.net/qq_39766167/article/details/106633658
2.https://blog.csdn.net/weixin_43779185/article/details/115125426