easyExcel导入导出

目录

EasyExcel工具类

pom导入依赖

1.相关代码

1.1 EasyExcel导出工具类

1.2CommonListener导入侦听器

1.3CustomMergeStrategy 合并策略(已改)

1.4 DownHandler 下拉处理(已解决大数据问题)

1.5 CustomMerge 合并单元格的注解

1.6 FieldDispose 导入自定义解析注解

1.7 DropDown 下拉注解

1.8 ExcelFieldType自定义数据解析常量

1.9 标题合并

2 .使用方法

2.1 导出导入实体--注解使用

2.2 Controller

2.3 service 调用

2.4 自定义批量方法 


EasyExcel工具类

       项目中常见的导出 一般使用 EasyExcel/POI,这里简单的列出了easyExcel 的用,easyExcel 使用简单方便,内存占用低,不会导致oom,不过导入导出要求多的话,写解析器也难受,哎本来写了很多的,结果好多找不到,然后暂时又没用到。在这里取出了常用的一些工具类,导出添加下拉框,单元格合并,多sheet导出等。导入则通过注解 解析字典值或校验唯一值,通过自定义的批量方法每500条插入一次

pom导入依赖

<!--excel导入导出-->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.6</version>
</dependency>

1.相关代码

1.1 EasyExcel导出工具类

/**
 * Excel相关处理
 * @author pw
 */
public class ExcelUtil {
	/**
	 *  单个sheet页导出
	 */
	public static void writeExcel(HttpServletResponse response, List<?> data, String fileName, String sheetName, Class<?> clazz) throws Exception {
		 EasyExcel.write(getOutputStream(fileName, response), clazz)
				.excelType(ExcelTypeEnum.XLSX).sheet(sheetName)
				.registerWriteHandler(getCellStyle()).doWrite(data);
	}

	/**
	 *  sheet页导出.设置下拉框
	 */
	public static void writeExcel(HttpServletResponse response, List<?> data, String fileName, String sheetName,Map<Integer,List<String>> dropDownMap, Class<?> clazz) throws Exception {
	 EasyExcel.write(getOutputStream(fileName, response), clazz)
				.excelType(ExcelTypeEnum.XLSX).sheet(sheetName)
			 	.registerWriteHandler(new DownHandler(dropDownMap))
				.registerWriteHandler(getCellStyle()).doWrite(data);
	}
	/**
	 *  合并导出
	 */
	public static void writeExcelCustomMerge(HttpServletResponse response, List<?> data, String fileName, String sheetName, Class<?> clazz) throws Exception {
		EasyExcel.write(getOutputStream(fileName, response), clazz).excelType(ExcelTypeEnum.XLSX).sheet(sheetName).registerWriteHandler(getCellStyle())
				.head(clazz)
				.registerWriteHandler(new CustomMergeStrategy(clazz))
				.doWrite(data);
	}
    /**
	 *  自定义屏蔽字段加自定义标题
	 */
    public static void downloadMergeTitle(OutputStream outputStream , String sheetName,Class<?> clazz, List<?> data, Set<String> set){
        EasyExcel.write(outputStream, clazz)
                .excludeColumnFiledNames(set)
                .relativeHeadRowIndex(1)
                .registerWriteHandler(new CustomTitleWriteHandler(clazz,sheetName,set))
                .registerWriteHandler(writeCenterStyleBorder())
                .autoCloseStream(Boolean.TRUE)
                .sheet(sheetName)
                .doWrite(data);
    }
	/**
	 *   多个sheet页导出
	 */
	public static void writeExcels(HttpServletResponse response,List<List<?>> data, String fileName, Class<?> clazz) throws Exception{
		ExcelWriter excelWriter = null;
		try{
			excelWriter = EasyExcel.write(getOutputStream(fileName, response), clazz).excelType(ExcelTypeEnum.XLSX).registerWriteHandler(getCellStyle()).build();
			for(int i=0;i<data.size();i++){
				WriteSheet writeSheet = EasyExcel.writerSheet(i, "sheet"+i).build();
				excelWriter.write(data.get(i), writeSheet);
			}
		} finally {
			if(excelWriter != null){
				excelWriter.finish();
			}
		}
	}
	/**
	 * 模板复制导出
	 * @param data 数据结构最外层为需要导出的sheet页个数,里层为多种数据格式的集合,一般为list和map组合成的混合list
	 * @param templateFile 模板本地路径
	 */
	public static void copyFillTemplate(HttpServletResponse response,List<List<?>> data, String fileName,String templateFile) throws Exception{
		//excel模板
		File file = new File(templateFile);
		ExcelWriter excelWriter = null;
		try (FileInputStream fileInputStream = new FileInputStream(file); ByteArrayOutputStream bos = new ByteArrayOutputStream()) {
			//通过poi复制出需要的sheet个数的模板
			XSSFWorkbook workbook = new XSSFWorkbook(fileInputStream);
			workbook.setSheetName(0, "sheet1");
			for (int i = 1; i < data.size();i++) {
				workbook.cloneSheet(0, "sheet"+(i+1));
			}
			workbook.write(bos);
			byte[] bArray = bos.toByteArray();
			InputStream is = new ByteArrayInputStream(bArray);
			//通过easyExcel塞入参数
			excelWriter = EasyExcel.write(getOutputStream(fileName, response)).withTemplate(is).build();
			fillTemplateData(excelWriter,data);
		} finally {
			if(excelWriter != null){
				excelWriter.finish();
			}
		}
	}

	/**
	 * 模板导出
	 */
	public static void fillTemplate(HttpServletResponse response,List<List<?>> data, String fileName,String templateFile) throws Exception{
		ExcelWriter excelWriter = null;
		try  {
			excelWriter = EasyExcel.write(getOutputStream(fileName, response)).withTemplate(new File(templateFile) ).build();
			fillTemplateData(excelWriter,data);
		} finally {
			if(excelWriter != null){
				excelWriter.finish();
			}
		}
	}
	/**
	 * 填充模板数据
	 * @param data 数据结构最外层为需要导出的sheet页个数,里层为多种数据格式的集合,一般为list和map组合成的混合list
	 */
	private static void fillTemplateData(ExcelWriter excelWriter, List<List<?>> data){
		for (int i = 0; i < data.size(); i++) {
			WriteSheet writeSheet = EasyExcel.writerSheet(i).build();
			for(Object o:data.get(i)){
				excelWriter.fill(o, writeSheet);
			}
		}
	}

	/**
	 * 设置请求
	 */
	private static OutputStream getOutputStream(String fileName, HttpServletResponse response) throws Exception {
		fileName = URLEncoder.encode(fileName, "UTF-8");
		// 告诉浏览器用什么软件可以打开此文件
		response.setHeader("content-Type", "application/vnd.ms-excel");
		response.setCharacterEncoding("utf8");
        response.setHeader("Content-Disposition",  "attachment;filename*=utf-8'zh_cn'"+fileName+  +"."+ ExcelTypeEnum.XLSX);
		return response.getOutputStream();
	}
	/**
	 * 设置样式
	 */
	private static HorizontalCellStyleStrategy getCellStyle(){
		//表头样式
		WriteCellStyle headWriteCellStyle = new WriteCellStyle();
		//设置表头居中对齐
		headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
		//内容样式
		WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
		//设置内容靠左对齐
		contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);
		return new HorizontalCellStyleStrategy(headWriteCellStyle,contentWriteCellStyle);
	}
}

1.2CommonListener导入侦听器

插入方法已优化,使用的是1.8的consumer,传入自定义方法

import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.read.metadata.holder.ReadRowHolder;
import com.cloud.common.core.excel.annotation.FieldDispose;
import com.cloud.common.core.exception.CommonException;
import lombok.Getter;

import java.lang.reflect.Field;
import java.util.*;
import java.util.function.Consumer;

/**
 * 基于EasyExcel的导入工具类,插入使用批量插入,BATCH_COUNT=500
 * @author pw
 * @param <T> 中间接收类
 */
@Getter
public class CommonListener<T> extends AnalysisEventListener<T> {
    /**
     *  执行的插入的service
     */
    private final Consumer<List<T>> p;
    /**
     * 字典
     */
    private final Map<String, Map<String,Object>> itemMap;
    /**
     * 中间类的字段
     */
    Field[] fields ;
    /**
     * 初始化参数,server 执行
     * @param itemMap 字典数据,从里面去对应的数据
     * @param p 执行方法
     */
    public CommonListener(Map<String,Map<String,Object>> itemMap,Class<T> tClass, Consumer<List<T>> p) {
        this.p = p;
        this.itemMap = itemMap;
        this.fields = tClass.getDeclaredFields();
    }
    /**
     * 批量插入数据的大小
     */
    private final int BATCH_COUNT = 500;
    /**
     * 存储数据的集合
     */
    private final List<T> rows = new ArrayList<>();
    /**
     * 存储数据的集合
     */
    private final Map<String, Set<String>> unique = new HashMap<>();
    /**
     * 存放失败的数据及原因
     */
    private final List<String> msgList = new ArrayList<>();

    @Override
    public void onException(Exception exception, AnalysisContext context) {
        if (exception instanceof ExcelDataConvertException) {
            ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;
            msgList.add(String.format("第%s行,第%s列解析异常,数据为:%s",excelDataConvertException.getRowIndex(),
                    excelDataConvertException.getColumnIndex(),excelDataConvertException.getCellData()));
        }
    }

    @Override
    public void invoke(T data, AnalysisContext context) {
        ReadRowHolder readRowHolder = context.readRowHolder();
        try {
            for ( Field field : fields )  {
                //得到属性值
                field.setAccessible(true);
                String value = (String) field.get(data);
                if(field.isAnnotationPresent(FieldDispose.class)){
                    //获取字段注解
                    FieldDispose annotation = field.getAnnotation(FieldDispose.class);
                    switch (annotation.type()){
                        //字典替换
                        case DICT:
                            if(!itemMap.get(annotation.value()).containsKey(value)){
                                msgList.add(String.format("第%s行异常,原因%s,数据为:%s",readRowHolder.getRowIndex()+1,annotation.errorMessage(),value));
                                return;
                            }
                            field.set(data, itemMap.get(annotation.value()).get(value));
                            break;
                        //唯一值判断
                        case UNIQUE:
                            if(unique.containsKey(annotation.value())){
                                if(unique.get(annotation.value()).contains(value)){
                                    msgList.add(String.format("第%s行异常,原因%s,数据为:%s",readRowHolder.getRowIndex()+1,annotation.errorMessage(),value));
                                    return;
                                }
                            }else {
                                Set<String> m = new HashSet<>();
                                m.add(value);
                                unique.put(annotation.value(),m);
                            }
                            break;
                        default:break;
                    }
                }
            }
            rows.add(data);
            if(rows.size()>=BATCH_COUNT){
                this.saveBatch();
            }
        }catch (Exception e){
            msgList.add(String.format("第%s行异常,原因:%s",readRowHolder.getRowIndex()+1,e.getMessage()));
        }
    }

    /**
     * 数据解析完成执行
     */
    @Override
    public void doAfterAllAnalysed(AnalysisContext context) {
        if(rows.size()>0){
            this.saveBatch();
        }
    }

    private void saveBatch(){
        try {
            p.accept(rows);
        }catch (CommonException e){
            rows.clear();
            msgList.add(e.getMessage());
        }
    }
}

1.3CustomMergeStrategy 合并策略(已改)

/**
 * 自定义单元格合并策略
 * @author pw
 */
public class CustomMergeStrategy implements RowWriteHandler {
    /**
     * 主键下标
     */
    private Integer pkIndex;

    /**
     * 需要合并的列的下标集合
     */
    private final List<Integer> needMergeColumnIndex = new ArrayList<>();

    /**
     * DTO数据类型
     */
    private final Class<?> elementType;

    public CustomMergeStrategy(Class<?> elementType) {
        this.elementType = elementType;
    }

    @Override
    public void beforeRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Integer integer, Integer integer1, Boolean aBoolean) {

    }

    @Override
    public void afterRowCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterRowDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Integer relativeRowIndex, Boolean isHead) {
        // 如果是标题,则直接返回
        if (isHead) {
            return;
        }
        // 获取当前sheet
        Sheet sheet = writeSheetHolder.getSheet();
        if (null == pkIndex) {
            this.lazyInit(writeSheetHolder);
        }
        // 判断是否需要和上一行进行合并
        // 不能和标题合并,只能数据行之间合并
        int rowNum = row.getRowNum();
        if (rowNum <= 1) {
            return;
        }
        // 获取上一行数据
        Row lastRow = sheet.getRow(row.getRowNum() - 1);
        // 将本行和上一行是同一类型的数据(通过主键字段进行判断),则需要合并
        if (lastRow.getCell(pkIndex).getStringCellValue().equalsIgnoreCase(row.getCell(pkIndex).getStringCellValue())) {
            boolean isMerged = false;
            for (Integer needMerIndex : needMergeColumnIndex) {
                //获得合并的区域
                List<CellRangeAddress> mergeRegions = sheet.getMergedRegions();
                for (int i = 0; i < mergeRegions.size(); i++) {
                    CellRangeAddress cellRangeAddress = mergeRegions.get(i);
                    // 若上一个单元格已经被合并,则先移出原有的合并单元,再重新添加合并单元
                    if (cellRangeAddress.isInRange(rowNum - 1, needMerIndex)) {
                        sheet.removeMergedRegion(i);
                        cellRangeAddress.setLastRow(rowNum);
                        sheet.addMergedRegionUnsafe(cellRangeAddress);
                        isMerged = true;
                    }
                }
                if (!isMerged) {
                    CellRangeAddress cellRangeAddress = new CellRangeAddress(rowNum - 1, row.getRowNum(),
                            needMerIndex, needMerIndex);
                    sheet.addMergedRegionUnsafe(cellRangeAddress);
                }
            }
        }
    }
    /**
     * 初始化主键下标和需要合并字段的下标
     */
    private void lazyInit(WriteSheetHolder writeSheetHolder) {

        // 获取当前sheet
        Sheet sheet = writeSheetHolder.getSheet();

        // 获取标题行
        Row titleRow = sheet.getRow(0);

        // 获取DTO所有的属性
        Field[] fields = this.elementType.getDeclaredFields();

        // 遍历所有的字段,因为是基于DTO的字段来构建excel,所以字段数 >= excel的列数
        for (Field theField : fields) {
            // 获取@ExcelProperty注解,用于获取该字段对应在excel中的列的下标
            ExcelProperty easyExcelAnn = theField.getAnnotation(ExcelProperty.class);
            // 为空,则表示该字段不需要导入到excel,直接处理下一个字段
            if (null == easyExcelAnn) {
                continue;
            }
            // 获取自定义的注解,用于合并单元格
            CustomMerge customMerge = theField.getAnnotation(CustomMerge.class);

            // 没有@CustomMerge注解的默认不合并
            if (null == customMerge) {
                continue;
            }
            for (int index = 0; index < fields.length; index++) {
                Cell theCell = titleRow.getCell(index);
                // 当配置为不需要导出时,返回的为null,这里作一下判断,防止NPE
                if (null == theCell) {
                    continue;
                }
                // 将字段和excel的表头匹配上
                if (easyExcelAnn.value()[0].equalsIgnoreCase(theCell.getStringCellValue())) {
                    if (customMerge.isPk()) {
                        pkIndex = index;
                    }
                    if (customMerge.needMerge()) {
                        needMergeColumnIndex.add(index);
                    }
                }
            }
        }
        // 没有指定主键,则异常
        if (null == this.pkIndex) {
            throw new IllegalStateException("使用@CustomMerge注解必须指定主键");
        }

    }
}

1.4 DownHandler 下拉处理(已解决大数据问题)

import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.cloud.common.core.excel.annotation.DropDown;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;

import java.lang.reflect.Field;
import java.util.Map;

/**
 * @author admin
 * @date 2020/5/17
 * @desc
 */
public class DownHandler implements SheetWriteHandler {

    private final Map<Integer, String[]> dropDownMap;

    private int index;

    public DownHandler(Map<Integer, String[]> dropDownMap) {
        this.dropDownMap = dropDownMap;
        this.index = 0;
    }

    @Override
    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
        Sheet sheet = writeSheetHolder.getSheet();
        ///开始设置下拉框 HSSFWorkbook
        DataValidationHelper helper = sheet.getDataValidationHelper();
        Field[] fields = writeWorkbookHolder.getClazz().getDeclaredFields();
        int length = fields.length;
        for (int i = 0; i < length; i++) {
           if(fields[i].isAnnotationPresent(DropDown.class)){
               dropDown(helper, sheet, i, fields[i].getDeclaredAnnotation(DropDown.class).value());
           }
        }
        if (dropDownMap == null) {
            return;
        }
        Workbook workbook = writeWorkbookHolder.getWorkbook();
        dropDownMap.forEach((celIndex, value) -> {
            if(value.length>20){
                dropDownBigData( helper, workbook ,sheet,celIndex, value);
            }else {
                dropDown(helper, sheet,celIndex, value);
            }
        });
    }

    private void dropDown(DataValidationHelper helper, Sheet sheet, Integer celIndex, String[] value) {
        if(null== value || value.length<=0){
            return;
        }
        this.dropDown(helper, sheet,celIndex, helper.createExplicitListConstraint(value));
    }

    private void dropDownBigData(DataValidationHelper helper,Workbook workbook,Sheet sheet, Integer celIndex, String[] v) {
        // 定义sheet的名称
        String sheetName = "sheet" + celIndex;
        // 1.创建一个隐藏的sheet 名称为 proviceSheet
        Sheet sheet1 = workbook.createSheet(sheetName);
        // 从第二个工作簿开始隐藏
        this.index++;
        // 设置隐藏
        workbook.setSheetHidden(this.index, true);
        // 2.循环赋值
        for (int i = 0, length = v.length; i < length; i++) {
            // i:表示你开始的行数 0表示你开始的列数
            sheet1.createRow(i).createCell(0).setCellValue(v[i]);
        }
        Name name = workbook.createName();
        name.setNameName(sheetName);
        //代表 以A列1行开始获取N行下拉数据
        name.setRefersToFormula(sheetName + "!$A$1:$A$" + (v.length));
        // 设置下拉
        this.dropDown(helper, sheet,celIndex,  helper.createFormulaListConstraint(sheetName));
    }

    private void dropDown(DataValidationHelper helper, Sheet sheet, Integer celIndex, DataValidationConstraint constraint) {
        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
        CellRangeAddressList addressList = new CellRangeAddressList(1, 100, celIndex, celIndex);
        // 数据有效性对象
        DataValidation dataValidation = helper.createValidation(constraint, addressList);
        // 处理Excel兼容性问题
        if (dataValidation instanceof XSSFDataValidation) {
            //数据校验
            dataValidation.setSuppressDropDownArrow(true);
            //错误提示
            dataValidation.setErrorStyle(DataValidation.ErrorStyle.STOP);
            dataValidation.createErrorBox("提示", "此值与单元格定义数据不一致");
            dataValidation.setShowErrorBox(true);
            //选定提示
            dataValidation.createPromptBox("填写说明:","填写内容只能为下拉中数据,其他数据将导致导入失败");
            dataValidation.setShowPromptBox(true);
            sheet.addValidationData(dataValidation);
        } else {
            dataValidation.setSuppressDropDownArrow(false);
        }
        sheet.addValidationData(dataValidation);
    }
}

1.5 CustomMerge 合并单元格的注解

/**
 * 自定义注解,用于判断是否需要合并以及合并的主键
 * @author pw
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface CustomMerge {

    /**
     * 是否需要合并单元格
     */
    boolean needMerge() default false;

    /**
     * 是否是主键,即该字段相同的行合并
     */
    boolean isPk() default false;
}

1.6 FieldDispose 导入自定义解析注解

/**
 * 数据来源解析
 * @author pw
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.FIELD})
@Documented
public @interface FieldDispose {
    /**
     * 解析类型
     */
    AnalyticalType type() default AnalyticalType.DICT;
    /**
     *绑定的数据,类型dict对应字典(传入的map),其他类型对应实体类字段
     */
    String[] value();
    /**
     * 错误提示
     */
    String errorMessage() default "";
    /**
     *仅拼接下使用,拼接间隔符,数组第几位即代表第几位后添加
     */
    String[] mark() default {};
}

1.7 DropDown 下拉注解

/**
 * @author pw
 * @date 2022/11/17
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface DropDown {
    String[] value();
}

1.8 ExcelFieldType自定义数据解析常量

/**
 * @author pw
 */

public enum ExcelFieldType{
    /**
     * 字典
     */
    DICT ,
/**
     * 唯一值
     */
    UNIQUE
}

1.9 标题合并

import com.alibaba.excel.annotation.ExcelIgnore;
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.var;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;

import java.lang.reflect.Field;
import java.util.Set;

/**
 * @description: 表格标题处理
 * @author: pw
 * @date: 2023/3/2 17:00
 **/
public class CustomTitleWriteHandler implements SheetWriteHandler {

    /**
     * 标题
     */
    private final String fileName;

    /**
     * DTO数据类型
     */
    private final Class<?> elementType;

    /**
     * 过滤的字段
     */
    private final Set<String> set;
    public CustomTitleWriteHandler(Class<?> elementType, String fileName, Set<String> set) {
        this.fileName = fileName;
        this.elementType = elementType;
        this.set = set;
    }

    @Override
    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

        Workbook workbook = writeWorkbookHolder.getWorkbook();
        Sheet sheet = workbook.getSheetAt(0);
        Row row1 = sheet.createRow(0);
        row1.setHeight((short) 800);
        Cell cell = row1.createCell(0);
        //设置标题
        cell.setCellValue(fileName);
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        cellStyle.setAlignment(HorizontalAlignment.CENTER);
        Font font = workbook.createFont();
        font.setBold(true);
        font.setFontHeight((short) 400);
        font.setFontName("宋体");
        cellStyle.setFont(font);
        cell.setCellStyle(cellStyle);
        // 获取clazz所有的属性
        Field[] fields = this.elementType.getDeclaredFields();
        //计算合并的长度
        int mergeLength = fields.length - 1 - (null != set ? set.size() : 0);
        //过滤注解屏蔽字段
        for(Field f:fields){
            if(f.isAnnotationPresent(ExcelIgnore.class)){
                mergeLength--;
            }
        }
        sheet.addMergedRegionUnsafe(new CellRangeAddress(0, 0, 0, mergeLength));
    }
}

2 .使用方法

2.1 导出导入实体--注解使用

/**
 * @author pw
 */
@Data
@ApiModel(value = "用户信息")
@ColumnWidth(20)
public class UserModel implements Serializable {

	@ApiModelProperty(value = "登录账号")
	@ExcelProperty(value = "登录账号",index=0)
	@FieldDispose(type = ExcelFieldType.UNIQUE,value = "username",errorMessage = "登录账号不允许重复" )
	private String username;

	@ApiModelProperty(value = "姓名")
	@ExcelProperty(value = "姓名",index=1)
	@FieldDispose(type = ExcelFieldType.UNIQUE,value ="nickName",errorMessage = "姓名不允许重复" )
	private String nickName;

	@ApiModelProperty(value = "性别")
	@ExcelProperty(value = "性别",index=2)
	@FieldDispose(value = DictCodeConstants.SEX,errorMessage = "该性别标识不存在" )
	private String sex;

	@ApiModelProperty(value = "手机号")
	@ExcelProperty(value = "手机号",index=3)
	private String phone;

	@ApiModelProperty(value = "密码")
	@ExcelProperty(value = "初始密码",index = 4)
	private String password;

	@ApiModelProperty(value = "职务")
	@ExcelProperty(value = "职务",index = 5)
	@FieldDispose(value = DictCodeConstants.USER_POST,errorMessage = "该职务标识不存在")
	private String post;

	@ApiModelProperty(value = "角色")
	@ExcelProperty(value ="角色",index = 6)
	@FieldDispose(value = "role",errorMessage = "该角色标识不存在")
	private String role;

	@ApiModelProperty("状态标识")
	@ExcelProperty(value = "状态标识",index = 7)
	@FieldDispose(value = DictCodeConstants.F_STATE,errorMessage = "该状态标识不存在")
	private String fstate;

	@ApiModelProperty("备注")
	@ExcelProperty(value = "备注",index = 8)
	private String remarks;
}

2.2 Controller

	@ApiOperation(value = "导入数据")
	@PostMapping("/importData")
	public R<Object> importData(@RequestParam("file") MultipartFile file) throws IOException {
		return userService.importData(file);
	}

	@ApiOperation(value = "模板下载和导出数据")
	@GetMapping("/exportData")
	public void exportData(HttpServletResponse response, UserDTO dto, @RequestParam("type") int type) throws Exception {
		userService.exportData(response,dto,type);
	}

2.3 service 调用

    @Override
    public R<Object> importData(MultipartFile file) throws IOException {
        //填充对应词典
        Map<String,Map<String,Object>> map = new HashMap<>();
        map.put(DictCodeConstants.SEX,this.getDictItemKey(DictCodeConstants.SEX));
        map.put(DictCodeConstants.USER_POST,this.getDictItemKey(DictCodeConstants.USER_POST));
        map.put(DictCodeConstants.USER_CLASSIFY,this.getDictItemKey(DictCodeConstants.USER_CLASSIFY));
        map.put(DictCodeConstants.F_STATE,this.getDictItemKey(DictCodeConstants.F_STATE));
        map.put("role",sysRoleService.getRoleNameMap());
        //解析器
        CommonListener<UserModel> commonListener = new CommonListener<>(map, UserModel.class,this::excelBatch);
        EasyExcel.read(file.getInputStream()).head(UserModel.class).registerReadListener(commonListener).sheet().doRead();
        List<String> msgList = commonListener.getMsgList();
        if(msgList.size()>0){
            return R.failed(StringUtils.join(msgList,","));
        }
        return R.ok();
    }

    @Override
    public void exportData(HttpServletResponse response, UserDTO dto, int type) throws Exception {
        List<UserModel> list = new ArrayList<>();
        Map<Integer,String[]> dropDownMap = new HashMap<>(4);
        if(type == 1) {
            //查询需导出数据
            list = this.baseMapper.getExcelList(dto);
        }else {
            //填充下拉框
            dropDownMap.put(2,this.getDictItem(DictCodeConstants.SEX));
            dropDownMap.put(5,this.getDictItem(DictCodeConstants.USER_POST));
            dropDownMap.put(6,sysRoleService.getRoleName());
            dropDownMap.put(7,this.getDictItem(DictCodeConstants.USER_CLASSIFY));
            dropDownMap.put(8,this.getDictItem(DictCodeConstants.F_STATE));
        }
        ExcelUtil.writeExcel(response,list, String.valueOf(System.currentTimeMillis()), "科室人员", dropDownMap, UserModel.class);
    }
   /**
     * 获取下拉框字典
     * @param type 字典code
     * @return  String[]
     */
    private String[] getDictItem(String type){
  List<SysDictItem> dictByType = DictUtil.getDictItemList(type);
      //  List<SysDictItem> dictByType = dictItemService.getDictByType(type);
        if(null!=dictByType){
           return dictByType.stream().map(SysDictItem::getDictItemName).toArray(String[]::new);
        }
        return null;
    }
    
    /**
     * 获取字典 -name,key
     * @param type 字典code
     * @return  List<String>
     */
    private Map<String,Object> getDictItemKey(String type){
//优化后的接口 DictUtil 字典工具类,其它文章里https://blog.csdn.net/weixin_42653892/article/details/126827174
  return DictUtil.getDictItemNameMap(type);
      //  List<SysDictItem> dictByType = dictItemService.getDictByType(type);
      //  if(null!=dictByType){
         //  return //dictByType.stream().collect(Collectors.toMap(SysDictItem::getDictItemName, SysDictItem::getDictItemCode));
  //      }
  //      return new HashMap<>(4);
    }

2.4 自定义批量方法 

  @Override
    public boolean excelBatch(Collection<UserModel> userList) {
         //数据处理及批量添加
        //返回提示
        String  returnMsg= "";
        if(b.length()>0){
            b.append("表格存在重复数据:");
            returnMsg=b.toString();
        }
        if(repeatData.size()>0){
            returnMsg+="数据库已存在数据:";
            returnMsg+=StringUtils.join(repeatData,",");
        }
        if(returnMsg.length()>0){
            throw new CommonException(returnMsg);
        }
        return true;
    }
  • 1
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值