数据库Excel导出操作代码过于冗长惨不忍睹,无法复用。【推荐使用阿里巴巴组件:关于Easyexcel | Easy Excel】
目录
依赖:
cn.afterturn
easypoi-base
4.1.2
cn.afterturn
easypoi-web
4.1.2
cn.afterturn
easypoi-annotation
4.1.2
注解配合工具类做了个小工具如下:
第一步:自定义注解:(读者请直接复制)
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; / * 自定义导出Excel数据注解 * * @author sunziwen * @version 1.0 * @date 2018-12-29 15:00 / @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Excel { / * 导出到Excel中的名字. */ public String name(); / * 日期格式, 如: yyyy-MM-dd */ public String dateFormat() default ""; / * 读取内容转表达式 (如: 0=男,1=女,2=未知) */ public String readConverterExp() default ""; / * 导出时在excel中每个列的高度 单位为字符 */ public double height() default 14; / * 导出时在excel中每个列的宽 单位为字符 */ public double width() default 20; / * 文字后缀,如% 90 变成90% */ public String suffix() default ""; / * 当值为空时,字段的默认值 */ public String defaultValue() default ""; / * 提示信息 */ public String prompt() default ""; / * 设置只能选择不能输入的列内容. */ public String[] combo() default {}; / * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写. */ public boolean isExport() default true; }
第二步:实体类:(为每个需要的字段打上@Excel注解)
import java.time.LocalDateTime; import com.ciih.authcenter.client.util.excel.Excel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.EqualsAndHashCode; / * (User)表实体类 * * @author suzniwen * @since 2021-04-13 16:11:55 */ @SuppressWarnings("serial") @EqualsAndHashCode(callSuper = true) @Data public class User { @Excel(name = "编号") @ApiModelProperty(value = "主键") private String id; @Excel(name = "账号") @ApiModelProperty(value = "账号") private String loginName; @Excel(name = "用户名") @ApiModelProperty(value = "用户名") private String userName; @ApiModelProperty(value = "用户名拼音") private String namePinyin; @Excel(name = "性别", readConverterExp = "1=男,0=女") @ApiModelProperty(value = "性别") private String gender; @Excel(name = "证件类型",readConverterExp="1=居民身份证,2=香港居民来往内地通行证,3=澳门居民来往内地通行证,4=台湾居民来往大陆通行证,6=护照") @ApiModelProperty(value = "证件类型") private String credType; @Excel(name = "证件号码") @ApiModelProperty(value = "证件号码") private String credNum; @ApiModelProperty(value = "机构id") private String orgId; @Excel(name = "机构名称") @ApiModelProperty(value = "机构名称") private String orgName; @Excel(name = "电话") @ApiModelProperty(value = "电话") private String phone; @Excel(name = "邮箱") @ApiModelProperty(value = "邮箱") private String email; @Excel(name = "人员类型",readConverterExp = "student=学生,teacher=教师,parent=家长,system=系统人员,developers=开发者,manager=管理员") @ApiModelProperty(value = "人员类型") private String personType; @Excel(name = "应用系统角色编码") @ApiModelProperty(value = "应用系统角色编码") private String appRoleCode; @ApiModelProperty(value = "创建时间") private LocalDateTime createTime; @ApiModelProperty(value = "更新时间") private LocalDateTime updateTime; }
第三步:解析工具类:(读者请直接复制)
import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Field; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletResponse; import org.apache.commons.lang3.StringUtils; import org.apache.poi.hssf.usermodel.DVConstraint; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFDataValidation; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellType; import org.apache.poi.ss.usermodel.HorizontalAlignment; import org.apache.poi.ss.usermodel.Row; import org.apache.poi.ss.usermodel.Sheet; import org.apache.poi.ss.usermodel.VerticalAlignment; import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.WorkbookFactory; import org.apache.poi.ss.util.CellRangeAddressList; import org.slf4j.Logger; import org.slf4j.LoggerFactory; / * Excel相关操作 * * @author sunziwen * @version 1.0 * @date 2022-03-25 15:20 / public class ExcelUtil
{ private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class); private Class
clazz; public ExcelUtil(Class
clazz) { this.clazz = clazz; } / * 对excel表单默认第一个索引名转换成list * * @param input 输入流 * @return 转换后集合 */ public List
importExcel(InputStream input) throws Exception { return importExcel(StringUtils.EMPTY, input); } / * 对excel表单指定表格索引名转换成list * * @param sheetName 表格索引名 * @param input 输入流 * @return 转换后集合 */ public List
importExcel(String sheetName, InputStream input) throws Exception { List
list = new ArrayList
(); Workbook workbook = WorkbookFactory.create(input); Sheet sheet = null; if (StringUtils.isNotEmpty(sheetName)) { // 如果指定sheet名,则取指定sheet中的内容. sheet = workbook.getSheet(sheetName); } else { // 如果传入的sheet名不存在则默认指向第1个sheet. sheet = workbook.getSheetAt(0); } if (sheet == null) { throw new IOException("文件sheet不存在"); } int rows = sheet.getPhysicalNumberOfRows(); if (rows > 0) { // 默认序号 // int serialNum = 0; // 有数据时才处理 得到类的所有field. Field[] allFields = clazz.getDeclaredFields(); / * 这里是要将实体类的属性与excel表的列序号对应上,有两种方式: * 1.按照先后顺序进行一一对应。 * 2.按照注解的name值与表头对应起来 */ // 定义一个map用于存放列的序号和field. Map
fieldsMap = new HashMap
(); //定义一个name到Excel表的index的映射Map HashMap
name2index = new HashMap<>(); //默认第一行是表头 Row r = sheet.getRow(0); for (int i = 0; i < allFields.length; i++) { Cell cell = r.getCell(i); if (cell == null) { continue; } else { // 先设置Cell的类型,然后就可以把纯数字作为String类型读进来了 r.getCell(i).setCellType(CellType.STRING); cell = r.getCell(i); String c = cell.getStringCellValue(); if (StringUtils.isEmpty(c)) { continue; } name2index.put(c, i); } } for (int col = 0; col < allFields.length; col++) { Field field = allFields[col]; // 将有注解的field存放到map中. if (field.isAnnotationPresent(Excel.class)) { Excel excel = field.getAnnotation(Excel.class); String name = excel.name(); Integer index = name2index.get(name); if (index != null) { field.setAccessible(true); fieldsMap.put(index, field); } } } //下面这个是按序号一一对应的。不太友好,还是按照表头名称来对应 // for (int col = 0; col < allFields.length; col++) { // Field field = allFields[col]; // // 将有注解的field存放到map中. // if (field.isAnnotationPresent(Excel.class)) { // // 设置类的私有字段属性可访问. // field.setAccessible(true); // fieldsMap.put(++serialNum, field); // } // } for (int i = 1; i < rows; i++) { // 从第2行开始取数据,默认第一行是表头. Row row = sheet.getRow(i); int cellNum = allFields.length; T entity = null; for (int j = 0; j < cellNum; j++) { Cell cell = row.getCell(j); if (cell == null) { continue; } else { // 先设置Cell的类型,然后就可以把纯数字作为String类型读进来了 row.getCell(j).setCellType(CellType.STRING); cell = row.getCell(j); } String c = cell.getStringCellValue(); if (StringUtils.isEmpty(c)) { continue; } // 如果不存在实例则新建. entity = (entity == null ? clazz.newInstance() : entity); // 从map中得到对应列的field. Field field = fieldsMap.get(j); // 取得类型,并根据对象类型设置值. Class
fieldType = field.getType(); if (String.class == fieldType) { field.set(entity, String.valueOf(c)); } else if ((Integer.TYPE == fieldType) || (Integer.class == fieldType)) { field.set(entity, Integer.parseInt(c)); } else if ((Long.TYPE == fieldType) || (Long.class == fieldType)) { field.set(entity, Long.valueOf(c)); } else if ((Float.TYPE == fieldType) || (Float.class == fieldType)) { field.set(entity, Float.valueOf(c)); } else if ((Short.TYPE == fieldType) || (Short.class == fieldType)) { field.set(entity, Short.valueOf(c)); } else if ((Double.TYPE == fieldType) || (Double.class == fieldType)) { field.set(entity, Double.valueOf(c)); } else if (Character.TYPE == fieldType) { if ((c != null) && (c.length() > 0)) { field.set(entity, Character.valueOf(c.charAt(0))); } } else if (Date.class == fieldType) { //对字符串解析成日期 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); String s = cell.getStringCellValue() .replaceAll("/", "-") .replaceAll("上午", "") .replaceAll("下午", "") .replaceAll(" ", " "); System.out.println("----------------------------:" + s); Date parse = sdf.parse(s); field.set(entity, parse); // if (cell.getCellTypeEnum() == CellType.NUMERIC) { // SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); // cell.setCellValue(sdf.format(cell.getNumericCellValue())); // c = sdf.format(cell.getNumericCellValue()); // } else { // c = cell.getStringCellValue(); // } } else if (java.math.BigDecimal.class == fieldType) { c = cell.getStringCellValue(); } } if (entity != null) { list.add(entity); } } } return list; } / * 对list数据源将其里面的数据导入到excel表单 * 针对List
第四步:无论导入导出,Excel表格的第一行都是跟实体类上@Excel注解的name属性进行映射对应的。
以下是示例:导出Excel表(该方法最好是返回void或者返回null),否则后台会报错(不影响运行)。
@PostMapping("/export") @ResponseBody public void export() { ExcelUtil
excelUtil = new ExcelUtil<>(User.class); //要导出的数据集 List
list = getList(); excelUtil.exportExcel(list, "userInformation.xlsx", ServletUtils.getResponse()); }
附件:前端代码:
exportExcel() { let link = document.createElement('a'); link.style.display = 'none' axios({ url: 'http://test.cih.net/user/pageExport', methods: "get", data: {}, headers: { token: 'eyJ0eXB1234bklkIjoie1wiZWnm7jwkJtbvdcnqo' } }).then((res) => { let blob = new Blob([res.data], { type: "application/vnd.ms-excel" }); // 2.获取请求返回的response对象中的blob 设置文件类型,这里以excel为例 let url = window.URL.createObjectURL(blob); // 3.创建一个临时的url指向blob对象 // 4.创建url之后可以模拟对此文件对象的一系列操作,例如:预览、下载 let a = document.createElement("a"); a.href = url; a.download = "导出表格.xlsx"; a.click(); // 5.释放这个临时的对象url window.URL.revokeObjectURL(url); }) }
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/204298.html原文链接:https://javaforall.net
