导出(若依框架)

您所在的位置:网站首页 access2007导入excel没反应 导出(若依框架)

导出(若依框架)

2023-11-16 13:33| 来源: 网络整理| 查看: 265

导出(若依框架)

分析用户界面,以用户列表的导出为例。

在这里插入图片描述

导出 前端代码

​ 点击导出按钮,触发函数handleExport,在该函数中调用exportUser,exportUser执行完毕后,再调用download方法下载。

exportUser执行完成后,后端会生成临时文件execl。再调用download下载该文件。

/** 导出按钮操作 */ handleExport() { const queryParams = this.queryParams; this.$confirm('是否确认导出所有用户数据项?', "警告", { confirmButtonText: "确定", cancelButtonText: "取消", type: "warning" }).then(function() { return exportUser(queryParams); }).then(response => { this.download(response.msg); }) }, // 导出用户 export function exportUser(query) { return request({ url: '/system/user/export', method: 'get', params: query }) } // 通用下载方法 export function download(fileName) { window.location.href = baseURL + "/common/download?fileName=" + encodeURI(fileName) + "&delete=" + true; } 后端代码

​ 完成导出共发起了两次请求。分别是生成文件和下载文件。

​ 技术:反射,注解

文件生成

主要分析以下几个方法。方法调用层级关系

在这里插入图片描述

export 导出的入口函数

调用userService.selectUserList方法查询需要导出的数据,再调用util.exportExcel生成execl文件。

@Log(title = "用户管理", businessType = BusinessType.EXPORT) @PreAuthorize("@ss.hasPermi('system:user:export')") @GetMapping("/export") public AjaxResult export(SysUser user) { List list = userService.selectUserList(user); // 创建 ExcelUtil对象,入参为 SysUser.class。 ExcelUtil util = new ExcelUtil(SysUser.class); return util.exportExcel(list, "用户数据"); } exportExcel

在exportExcel方法中调用了init方法和exportExcel方法

public AjaxResult exportExcel(List list, String sheetName) { this.init(list, sheetName, Type.EXPORT); return exportExcel(); } init

在init中调用了createExcelField方法,主要完成对ExcelUtil类中的fields属性赋值。

public void init(List list, String sheetName, Type type) { if (list == null) { list = new ArrayList(); } this.list = list; // 需要导出的数据交给list this.sheetName = sheetName; // 生成execl的sheet名称 this.type = type; // 类型(0:导出导入;1:仅导出;2:仅导入) createExcelField(); // 主要完成对 List fields 属性的赋值。 createWorkbook(); // 创建 Workbook对象 Workbook wb = new SXSSFWorkbook(500) } createExcelField

该方法执行完成后,完成了对ExcelUtil对象中的LIst fields属性的赋值。fields存放了导出的信息。

在object[]数组,object[0]存放了java.lang.reflect.Field对象, object[1]存放了注解com.ruoyi.common.annotation.Excel对象。

从object[0]可以获取到字段名称等信息。 从object[1]中可以获取到导出到execl中的名称以及对该字段的值作何处理(如格式化)等信息。

private void createExcelField() { this.fields = new ArrayList(); List tempFields = new ArrayList(); // clazz属性是创建ExcelUtil对象时,完成了对该属性的赋值。以用户导出为例,class=SysUser.class。 // 获取该类和其父类的属性字段,存入到tempFields集合中。 tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields())); tempFields.addAll(Arrays.asList(clazz.getDeclaredFields())); // 遍历字段,过滤出符合规律的字段。 // 规律:1. 如果该字段有注解@Excel,则将字段对象,和注解对象封装到object[]数组中,并add到fields集合中。 // 规律:2. 如果该字段有@Excels注解,则从该注解对象中获取Excel[]数组进行遍历。并将字段对象和Excel对象封装后,add到 // fields集合中。 for (Field field : tempFields) { // 单注解 if (field.isAnnotationPresent(Excel.class)) { // this.fields.add(new Object[] { field, attr }); putToField(field, field.getAnnotation(Excel.class)); } // 多注解 if (field.isAnnotationPresent(Excels.class)) { Excels attrs = field.getAnnotation(Excels.class); Excel[] excels = attrs.value(); for (Excel excel : excels) { putToField(field, excel); } } } this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList()); this.maxHeight = getRowHeight(); } exportExcel 完成execl文件的生成 /** * 对list数据源将其里面的数据导入到excel表单 * * @return 结果 */ public AjaxResult exportExcel() { OutputStream out = null; try { // 算出一共有多少个sheet. // list.size 需要导出的数据条数。 sheetSize = 65536 double sheetNo = Math.ceil(list.size() / sheetSize); for (int index = 0; index Excel excel = (Excel) os[1]; // 创建单元格,并赋值,完成表头的创建 this.createCell(excel, row, column++); } // 如果为导出类型,调用fillExcelData方法填充excel数据。 if (Type.EXPORT.equals(type)) { // 填充数据 fillExcelData(index, row); addStatisticsRow(); } } // 生成文件名称 String filename = encodingFilename(sheetName); // 生成的文件路径在application.yml配置 ( profile: D:/ruoyi/uploadPath) out = new FileOutputStream(getAbsoluteFile(filename)); // 生成execl文件,此时生成的文件在服务端。 wb.write(out); // 将生成的文件名称封装到AjaxResult对象中 return AjaxResult.success(filename); } catch (Exception e) { log.error("导出Excel异常{}", e.getMessage()); throw new CustomException("导出Excel失败,请联系网站管理员!"); } finally { // 省略 } } fillExcelData 完成execl数据填充 /** * 填充excel数据 * * @param index 序号 * @param row 单元格行 */ public void fillExcelData(int index, Row row) { // 以第一个sheet页为例 index = 0, 常量sheetSize=65536 // startNo是数据开始下标 int startNo = index * sheetSize; // endNo-1是数据结束下标 int endNo = Math.min(startNo + sheetSize, list.size()); for (int i = startNo; i Field field = (Field) os[0]; Excel excel = (Excel) os[1]; // 设置实体类私有属性可访问 field.setAccessible(true); // 将导出信息 和 数据对象 execl的行对象 交由 addCell处理。 this.addCell(excel, row, vo, field, column++); } } } addCell 完成对行记录的填充。

创建单元格,填充单元格内容。

/** * 添加单元格 */ public Cell addCell(Excel attr, Row row, T vo, Field field, int column) { Cell cell = null; try { // 设置行高 row.setHeight(maxHeight); // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列. if (attr.isExport()) { // 创建cell cell = row.createCell(column); int align = attr.align().value(); cell.setCellStyle(styles.get("data" + (align >= 1 && align cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator)); } else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value)) { cell.setCellValue(convertDictByExp(Convert.toStr(value), dictType, separator)); } else if (value instanceof BigDecimal && -1 != attr.scale()) { cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).toString()); } else { // 设置列类型 setCellVo(value, attr, cell); } addStatisticsData(column, Convert.toStr(value), attr); } } catch (Exception e) { log.error("导出Excel失败{}", e); } return cell; } getTargetValue 获取bean中的属性值 /** * 获取bean中的属性值 * * @param vo 实体对象 * @param field 字段 * @param excel 注解 * @return 最终的属性值 * @throws Exception */ private Object getTargetValue(T vo, Field field, Excel excel) throws Exception { // 通过反射获取字段的值。该值有可能是其他类的对象。 Object o = field.get(vo); // 如果 excel.targetAttr()不为空,则说明o是其他类中的一个对象。 if (StringUtils.isNotEmpty(excel.targetAttr())) { // 获取注解 targetAttr属性(另一个类中的属性名称,支持多级获取,以小数点隔开) String target = excel.targetAttr(); if (target.indexOf(".") > -1) { // 如果该属性有小数点,分割为数组遍历。 // 多级获取逻辑 // 举例说明:A类中持有B类的对象,B类中持有C类的对象。 导出A类数据时,需要导出C类的一个属性值 // 可以使用.隔开。 String[] targets = target.split("[.]"); for (String name : targets) { o = getValue(o, name); } } else { // 如果不包含小数点,(o, target) o为其他类对象,target为该类中的字段名称值。 // getValue 是通过o.getClass获取class对象,通过target字段名称从class中获取到Filed对象。进而得到filed字段值 // 例子:SysUser#dept字段。 o = getValue(o, target); } } return o; } /** * 以类的属性的get方法方法形式获取值 * * @param o * @param name * @return value * @throws Exception */ private Object getValue(Object o, String name) throws Exception { if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name)) { Class clazz = o.getClass(); Field field = clazz.getDeclaredField(name); field.setAccessible(true); o = field.get(o); } return o; } 小结

自定义注解,描述Bean字段在Execl的表现形式。(比如,字段的值否需要格式化,字段对应到表格中的列名称等等)

使用List 存入类的Filed对象和注解对象。(比如导出的字段有10个,则该集合大小为10)

导出执行的大致逻辑:

根据注解信息完成List集合的赋值。

根据导出的数据量,计算需要导出的sheet页。针对每一个sheet页进行处理

创建表头:遍历List集合,通过object[1]得到字段的注解信息,创建sheet页表头。

填充数据: 根据sheet页数,计算对应的数据范围,循环创建行对象,根据循环下标,在数据集合中获取改行对应的数据对象。行中创建单元格对象,接着遍历List集合,通过object[0]获取数据对象中属性值,通过object[1]>获取对该值的处理策略。处理完毕后,将值填充到单元格中。

文件下载

文件生成后,将生成的文件名称返回到前端,客户端在调用download方法,向后端发起下载请求。

fileDownload下载入口方法 /** * 通用下载请求 * * @param fileName 文件名称 * @param delete 是否删除 */ @GetMapping("common/download") public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) { try { if (!FileUtils.checkAllowDownload(fileName)) { throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName)); } String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1); // 获取下载路劲 String filePath = RuoYiConfig.getDownloadPath() + fileName; // 设置ContentTyp="application/octet-stream" 通用Mime类型 response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE); // 设置Content-disposition FileUtils.setAttachmentResponseHeader(response, realFileName); FileUtils.writeBytes(filePath, response.getOutputStream()); // 下载后是否删除该文件 if (delete) { FileUtils.deleteFile(filePath); } } catch (Exception e) { log.error("下载文件失败", e); } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3