赞
踩
#因为项目中需要导入一些信息,但是这些信息比较不常见,且在项目字典数据中维护有这些数据,所以在导出模板的时候,把这些数据一并导出,可以减少用户的编写,避免在导入的时候因为数据错误,发生一些业务问题
直接开始
- <!--easyexcel依赖-->
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>easyexcel</artifactId>
- <version>2.2.10</version>
- </dependency>
-
-
- import java.lang.annotation.*;
-
- /**
- * 标注导出的列为下拉框类型,并为下拉框设置内容
- */
- @Documented
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.FIELD)
- public @interface ExcelSelected {
- /**
- * 固定下拉内容
- */
- String[] source() default {};
-
- /**
- * 动态下拉内容
- */
- Class<? extends ExcelDynamicSelect>[] sourceClass() default {};
-
- /**
- * 设置下拉框的起始行,默认为第二行
- */
- int firstRow() default 1;
-
- /**
- * 设置下拉框的结束行,默认为最后一行
- */
- int lastRow() default 0x10000;
- }
-
- public interface ExcelDynamicSelect {
- /**
- * 获取动态生成的下拉框可选数据
- * @return 动态生成的下拉框可选数据
- */
- String[] getSource();
- }
- import com.alibaba.excel.annotation.ExcelProperty;
- import com.alibaba.excel.annotation.write.style.ColumnWidth;
- import com.alibaba.excel.annotation.write.style.ContentRowHeight;
- import com.alibaba.excel.annotation.write.style.HeadRowHeight;
- import lombok.Data;
- import org.springblade.basicdata.service.impl.DeptTemplateServiceImpl;
- import org.springblade.basicdata.service.impl.SchoolTemplateServiceImpl;
- import org.springblade.basicdata.service.impl.StationlateServiceImpl;
- import org.springblade.basicdata.service.impl.ZgTypeslateServiceImpl;
-
- import java.io.Serializable;
-
-
- @Data
- @HeadRowHeight(20)
- @ContentRowHeight(18)
- public class TeacherExcel implements Serializable {
-
- private static final long serialVersionUID = 1L;
-
- /**
- * 职工编号
- */
- @ExcelProperty(index = 0, value = "职工编号")
- @ColumnWidth(20)
- private String no;
- /**
- * 姓名
- */
- @ExcelProperty(index = 1, value = "姓名")
- @ColumnWidth(30)
- private String name;
- /**
- * 身份证
- */
- @ExcelProperty(index = 2, value = "身份证号")
- @ColumnWidth(25)
- private String idCard;
-
- /**
- * 电话
- */
- @ExcelProperty(index = 3, value = "联系电话")
- @ColumnWidth(15)
- private String phone;
- /**
- * 学校id
- */
- //需要自定义实现 SchoolTemplateServiceImpl,下面有具体的实现方式
- @ExcelSelected(sourceClass = SchoolTemplateServiceImpl.class)
- @ExcelProperty(index = 4, value = "校区")
- @ColumnWidth(45)
- private String schoolName;
- /**
- * 部门
- */
- //需要自定义实现 DeptTemplateServiceImpl,下面有具体的实现方式
- @ExcelSelected(sourceClass = DeptTemplateServiceImpl.class)
- @ExcelProperty(index = 5, value = "部门")
- @ColumnWidth(45)
- private String bumenName;
- /**
- * 岗位类别
- */
- //需要自定义实现 StationlateServiceImpl,下面有具体的实现方式
- @ExcelSelected(sourceClass = StationlateServiceImpl.class)
- @ExcelProperty(index = 6, value = "岗位类别")
- @ColumnWidth(15)
- private String station;
- /**
- * 职工类型
- */
- //需要自定义实现 ZgTypeslateServiceImpl,下面有具体的实现方式
- @ExcelSelected(sourceClass = ZgTypeslateServiceImpl.class)
- @ExcelProperty(index = 7, value = "职工类型")
- @ColumnWidth(15)
- private String zhigongleibie;
- /**
- * 备注
- */
- @ExcelProperty(index = 8, value = "备注")
- @ColumnWidth(15)
- private String remarks;
-
-
- }
创建StationlateServiceImpl实现类,实现方法 为我自己的业务需求,你们可以根据你们的情况去修改,这边返回给注解的是一个字符串的数组,也就是需要导出的下拉选数据
-
- import java.util.List;
- import java.util.stream.Collectors;
-
- /**
- * 岗位类别下拉选数据实现类
- */
- public class StationlateServiceImpl implements ExcelDynamicSelect {
-
- private static IDictClient dictClient;
-
-
- static {
- dictClient = SpringUtil.getBean(IDictClient.class);
- }
-
-
-
- @Override
- public String[] getSource() {
- R<List<Dict>> dictClientList =
- dictClient.getList(DictEnum.POST_TYPE.getName());
- if(Func.isNotEmpty(dictClientList) && dictClientList.getCode() == 200){
- if(Func.isNotEmpty(dictClientList.getData())){
- return Func.toStrArray(dictClientList.getData().stream().map(Dict::getDictValue).collect(Collectors.joining(",")));
- }
- }
- return new String[0];
- }
- }
Func.toStrArray方法就是讲给定的逗号拼接的字符串转为字符串数组,这个百度一下,一大堆
- import com.alibaba.excel.EasyExcel;
- import com.alibaba.excel.annotation.ExcelProperty;
- import com.alibaba.excel.write.metadata.WriteSheet;
- import lombok.extern.slf4j.Slf4j;
- import org.apache.commons.lang3.StringUtils;
-
- import java.lang.reflect.Field;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.regex.Matcher;
- import java.util.regex.Pattern;
-
-
- @Slf4j
- public class EasyExcelUtil {
-
- /**
- * 创建即将导出的sheet页(sheet页中含有带下拉框的列)
- * @param head 导出的表头信息和配置
- * @param sheetNo sheet索引
- * @param sheetName sheet名称
- * @param <T> 泛型
- * @return sheet页
- */
- public static <T> WriteSheet writeSelectedSheet(Class<T> head, Integer sheetNo, String sheetName) {
- Map<Integer, ExcelSelectedResolve> selectedMap = resolveSelectedAnnotation(head);
-
- return EasyExcel.writerSheet(sheetNo, sheetName)
- .head(head)
- .registerWriteHandler(new SelectedSheetWriteHandler(selectedMap))
- .build();
- }
-
- /**
- * 解析表头类中的下拉注解
- * @param head 表头类
- * @param <T> 泛型
- * @return Map<下拉框列索引, 下拉框内容> map
- */
- private static <T> Map<Integer, ExcelSelectedResolve> resolveSelectedAnnotation(Class<T> head) {
- Map<Integer, ExcelSelectedResolve> selectedMap = new HashMap<>();
-
- // getDeclaredFields(): 返回全部声明的属性;getFields(): 返回public类型的属性
- Field[] fields = head.getDeclaredFields();
- for (int i = 0; i < fields.length; i++){
- Field field = fields[i];
- // 解析注解信息
- ExcelSelected selected = field.getAnnotation(ExcelSelected.class);
- ExcelProperty property = field.getAnnotation(ExcelProperty.class);
- if (selected != null) {
- ExcelSelectedResolve excelSelectedResolve = new ExcelSelectedResolve();
- String[] source = excelSelectedResolve.resolveSelectedSource(selected);
- if (source != null && source.length > 0){
- excelSelectedResolve.setSource(source);
- excelSelectedResolve.setFirstRow(selected.firstRow());
- excelSelectedResolve.setLastRow(selected.lastRow());
- if (property != null && property.index() >= 0){
- selectedMap.put(property.index(), excelSelectedResolve);
- } else {
- selectedMap.put(i, excelSelectedResolve);
- }
- }
- }
- }
- return selectedMap;
- }
-
- public static boolean isIDNumber(String IDNumber) {
- if (IDNumber == null || "".equals(IDNumber)) {
- return false;
- }
- // 定义判别用户身份证号的正则表达式(15位或者18位,最后一位可以为字母)
- String regularExpression = "(^[1-9]\\d{5}(18|19|20)\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}[0-9Xx]$)|" +
- "(^[1-9]\\d{5}\\d{2}((0[1-9])|(10|11|12))(([0-2][1-9])|10|20|30|31)\\d{3}$)";
- //假设18位身份证号码:41000119910101123X 410001 19910101 123X
- //^开头
- //[1-9] 第一位1-9中的一个 4
- //\\d{5} 五位数字 10001(前六位省市县地区)
- //(18|19|20) 19(现阶段可能取值范围18xx-20xx年)
- //\\d{2} 91(年份)
- //((0[1-9])|(10|11|12)) 01(月份)
- //(([0-2][1-9])|10|20|30|31)01(日期)
- //\\d{3} 三位数字 123(第十七位奇数代表男,偶数代表女)
- //[0-9Xx] 0123456789Xx其中的一个 X(第十八位为校验值)
- //$结尾
-
- //假设15位身份证号码:410001910101123 410001 910101 123
- //^开头
- //[1-9] 第一位1-9中的一个 4
- //\\d{5} 五位数字 10001(前六位省市县地区)
- //\\d{2} 91(年份)
- //((0[1-9])|(10|11|12)) 01(月份)
- //(([0-2][1-9])|10|20|30|31)01(日期)
- //\\d{3} 三位数字 123(第十五位奇数代表男,偶数代表女),15位身份证不含X
- //$结尾
- boolean matches = IDNumber.matches(regularExpression);
-
- //判断第18位校验值
- if (matches) {
-
- if (IDNumber.length() == 18) {
- try {
- char[] charArray = IDNumber.toCharArray();
- //前十七位加权因子
- int[] idCardWi = {7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2};
- //这是除以11后,可能产生的11位余数对应的验证码
- String[] idCardY = {"1", "0", "X", "9", "8", "7", "6", "5", "4", "3", "2"};
- int sum = 0;
- for (int i = 0; i < idCardWi.length; i++) {
- int current = Integer.parseInt(String.valueOf(charArray[i]));
- int count = current * idCardWi[i];
- sum += count;
- }
- char idCardLast = charArray[17];
- int idCardMod = sum % 11;
- if (idCardY[idCardMod].toUpperCase().equals(String.valueOf(idCardLast).toUpperCase())) {
- return true;
- } else {
- return false;
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- return false;
- }
- return matches;
- }
-
-
- public static boolean isMobile(String phone){
- Pattern p = null;
- Matcher m = null;
- boolean b = false;
- // 验证手机号
- String s2="^[1](([3|5|6|7|8|9][\\d])|([4][4,5,6,7,8,9])|([6][2,5,6,7])|([7][^9])|([9][1,8,9]))[\\d]{8}$";
- if(StringUtils.isNotBlank(phone)){
- p = Pattern.compile(s2);
- m = p.matcher(phone);
- b = m.matches();
- }
- return b;
- }
-
- }
-
- import com.alibaba.excel.write.handler.SheetWriteHandler;
- import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
- import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import org.apache.poi.ss.usermodel.DataValidation;
- import org.apache.poi.ss.usermodel.DataValidationConstraint;
- import org.apache.poi.ss.usermodel.DataValidationHelper;
- import org.apache.poi.ss.usermodel.Sheet;
- import org.apache.poi.ss.util.CellRangeAddressList;
-
- import java.util.Map;
-
- @Data
- @AllArgsConstructor
- public class SelectedSheetWriteHandler implements SheetWriteHandler {
-
- private final Map<Integer, ExcelSelectedResolve> selectedMap;
-
- /**
- * 设置阈值,避免生成的导入模板下拉值获取不到,可自行设置数量大小
- */
- private static final Integer LIMIT_NUMBER = 25;
-
- /**
- * Called before create the sheet
- */
- @Override
- public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
-
- }
-
- /**
- * Called after the sheet is created
- */
- @Override
- public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
- // 这里可以对cell进行任何操作
- Sheet sheet = writeSheetHolder.getSheet();
- DataValidationHelper helper = sheet.getDataValidationHelper();
- selectedMap.forEach((k, v) -> {
- // 设置下拉列表的行: 首行,末行,首列,末列
- CellRangeAddressList rangeList = new CellRangeAddressList(v.getFirstRow(), v.getLastRow(), k, k);
- // 如果下拉值总数大于25,则使用一个新sheet存储,避免生成的导入模板下拉值获取不到
- if (v.getSource().length > LIMIT_NUMBER) {
- //定义sheet的名称
- //1.创建一个隐藏的sheet 名称为 hidden + k
- String sheetName = "hidden" + k;
- Workbook workbook = writeWorkbookHolder.getWorkbook();
- Sheet hiddenSheet = workbook.createSheet(sheetName);
- for (int i = 0, length = v.getSource().length; i < length; i++) {
- // 开始的行数i,列数k
- hiddenSheet.createRow(i).createCell(k).setCellValue(v.getSource()[i]);
- }
- Name category1Name = workbook.createName();
- category1Name.setNameName(sheetName);
- String excelLine = getExcelLine(k);
- // =hidden!$H:$1:$H$50 sheet为hidden的 H1列开始H50行数据获取下拉数组
- String refers = "=" + sheetName + "!$" + excelLine + "$1:$" + excelLine + "$" + (v.getSource().length + 1);
- // 将刚才设置的sheet引用到你的下拉列表中
- DataValidationConstraint constraint = helper.createFormulaListConstraint(refers);
- DataValidation dataValidation = helper.createValidation(constraint, rangeList);
- writeSheetHolder.getSheet().addValidationData(dataValidation);
- // 设置存储下拉列值得sheet为隐藏
- int hiddenIndex = workbook.getSheetIndex(sheetName);
- if (!workbook.isSheetHidden(hiddenIndex)) {
- workbook.setSheetHidden(hiddenIndex, true);
- }
- }
- // 设置下拉列表的值
- DataValidationConstraint constraint = helper.createExplicitListConstraint(v.getSource());
- // 设置约束
- DataValidation validation = helper.createValidation(constraint, rangeList);
- // 阻止输入非下拉选项的值
- validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
- validation.setShowErrorBox(true);
- // validation.setSuppressDropDownArrow(true);
- validation.createErrorBox("提示", "请输入下拉选项中的内容");
- sheet.addValidationData(validation);
- });
- }
-
-
- /**
- * 返回excel列标A-Z-AA-ZZ
- *
- * @param num 列数
- * @return java.lang.String
- */
- private String getExcelLine(int num) {
- String line = "";
- int first = num / 26;
- int second = num % 26;
- if (first > 0) {
- line = (char) ('A' + first - 1) + "";
- }
- line += (char) ('A' + second) + "";
- return line;
- }
- }
- public interface ExcelDynamicSelect {
- /**
- * 获取动态生成的下拉框可选数据
- * @return 动态生成的下拉框可选数据
- */
- String[] getSource();
- }
- @Data
- @Slf4j
- public class ExcelSelectedResolve {
- /**
- * 下拉内容
- */
- private String[] source;
-
- /**
- * 设置下拉框的起始行,默认为第二行
- */
- private int firstRow;
-
- /**
- * 设置下拉框的结束行,默认为最后一行
- */
- private int lastRow;
-
- public String[] resolveSelectedSource(ExcelSelected excelSelected) {
- if (excelSelected == null) {
- return null;
- }
-
- // 获取固定下拉框的内容
- String[] source = excelSelected.source();
- if (source.length > 0) {
- return source;
- }
-
- // 获取动态下拉框的内容
- Class<? extends ExcelDynamicSelect>[] classes = excelSelected.sourceClass();
- if (classes.length > 0) {
- try {
- ExcelDynamicSelect excelDynamicSelect = classes[0].newInstance();
- String[] dynamicSelectSource = excelDynamicSelect.getSource();
- if (dynamicSelectSource != null && dynamicSelectSource.length > 0) {
- return dynamicSelectSource;
- }
- } catch (InstantiationException | IllegalAccessException e) {
- log.error("解析动态下拉框数据异常", e);
- }
- }
- return null;
- }
-
- }
- /** 教师入职Excel模板导出 */
- @ApiLog("教师入职Excel模板导出")
- @GetMapping("export-template")
- @ApiOperationSupport(order = 7)
- @ApiOperation(value = "教师入职Excel模板导出")
- public void exportTeacher(HttpServletResponse response, HttpServletRequest request) {
- String filename = "教师入职信息导入模板";
- try {
- String userAgent = request.getHeader("User-Agent");
- if (userAgent.contains("MSIE") || userAgent.contains("Trident")) {
- // 针对IE或者以IE为内核的浏览器:
- filename = java.net.URLEncoder.encode(filename, "UTF-8");
- } else {
- // 非IE浏览器的处理:
- filename = new String(filename.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
- }
- response.setContentType("application/vnd.ms-excel");
- response.setHeader("Content-disposition", String.format("attachment; filename=\"%s\"", filename + Func.formatDateTime(new Date()) + ".xlsx"));
- response.setHeader("Cache-Control", "no-cache");
- response.setHeader("Pragma", "no-cache");
- response.setDateHeader("Expires", -1);
- response.setCharacterEncoding("UTF-8");
-
- ExcelWriter excelWriter = EasyExcel.write(response.getOutputStream()).build();
- WriteSheet writeSheet = EasyExcelUtil.writeSelectedSheet(TeacherExcel.class, 0, "教师入职信息数据表");
- excelWriter.write(new ArrayList<String>(), writeSheet);
- excelWriter.finish();
- } catch (UnsupportedEncodingException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。