EasyExcel导出带下拉框 通用模板

实体类

@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value="FireChemicalDto", description="危化品")
public class FireChemicalDto  extends BaseDto {
	@ExcelIgnore
   private static final long serialVersionUID = 1L;



    @ApiModelProperty(value = "casNo")
    @ExcelProperty(value = "casNo", index = 1)
    private String casNo;

    @ApiModelProperty(value = "国际危险号")
    @ExcelProperty(value = "国际危险号", index = 2)
    private String dangerId;

    @ApiModelProperty(value = "防护处理")
    @ExcelProperty(value = "防护处理", index = 3)
    private String defendWay;

    @ApiModelProperty(value = "处理措施")
    @ExcelProperty(value = "处理措施", index = 4)
    private String dispose;

    @ApiModelProperty(value = "英文名")
    @ExcelProperty(value = "英文名", index = 5)
    private String englishName;

    @ApiModelProperty(value = "分子式")
    @ExcelProperty(value = "分子式", index = 6)
    private String formula;

    @ApiModelProperty(value = "主要成分")
    @ExcelProperty(value = "主要成分", index = 7)
    private String ingredient;

    @ApiModelProperty(value = "泄漏处理")
    @ExcelProperty(value = "泄漏处理", index = 8)
    private String leakWay;
    @ExcelProperty(value = "中文名", index = 0)
    @ApiModelProperty(value = "中文名")
    private String name;

    @ApiModelProperty(value = "性状")
    @ExcelProperty(value = "性状", index = 9)
    private String property;

    @ApiModelProperty(value = "贮藏方法")
    @ExcelProperty(value = "贮藏方法", index = 10)
    private String store;

    @ApiModelProperty(value = "症状")
    @ExcelProperty(value = "症状", index = 11)
    private String symptom;

    @ApiModelProperty(value = "禁忌物/禁忌")
    @ExcelProperty(value = "禁忌物/禁忌", index = 12)
    private String tabu;
    @ExcelIgnore
    @ApiModelProperty(value = "类型code")
    private String typeCode;
    
    @ExplicitConstraint(type="CHEMICALTYPE",indexNum=13,sourceClass = RoleNameExplicitConstraint.class) //动态下拉内容
    @ApiModelProperty(value = "类型名称")
    @ExcelProperty(value = "类型名称", index = 13)
    private String type;
//    @ExplicitConstraint(indexNum=14,source = {"男","女"}) //固定下拉内容
    @ExcelProperty(value = "国标号", index = 14)
    @ApiModelProperty(value = "国标号")
    private String un;

    @ApiModelProperty(value = "化学品图片")
    @ExcelProperty(value = "化学品图片", index = 15)
    private String image;
    @ExcelIgnore
    @ApiModelProperty(value = "更新时间")
    private Date updateTime;
    @ExcelIgnore
    @ApiModelProperty(value = "操作人名称")
    private String recUserName;
    @ExcelIgnore
    public static final String bigTitle= "填写须知: \n" +
            "1.第1、2行为固定结构,不可更改;以下示例行,导入前请先删除\n" +
            "2.请严格按照填写规则输入数据,不合规的数据无法成功导入";
    /**
     * 每个模板的首行高度, 换行数目+2 乘以15
     */
    public   static int getHeadHeight(){
        return  (RedisKey.countStr(bigTitle,"\n")+2)*15;
    }
}

实体类数据注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface ExplicitConstraint {
    //定义固定下拉内容
    String[]source()default {};
    //定义动态下拉内容,
    Class[]sourceClass()default {};
    //列标号必须和字段下标一致
	int indexNum() default 0;
	//字典type
	String type() default "";
	
}

动态数据接口

public interface ExplicitInterface {
    /**
     * 动态下拉列表的内容数组
     * @return
     * type 字典类型
     */
    String[] source(String type,DataDictionaryMapper dataDictionaryMapper);
}

动态数据接口实现类

/***
 * 
 * 获取动态值
 * 
 * **/
public class RoleNameExplicitConstraint implements ExplicitInterface {
	
	@Override
	public String[] source(String type,DataDictionaryMapper dataDictionaryMapper) {
		    QueryWrapper<DataDictionary> queryWrapper = new QueryWrapper<>();
	        queryWrapper.eq("type", type);
	        queryWrapper.orderByAsc("sort_num");
	        List<DataDictionary> list= dataDictionaryMapper.selectList(queryWrapper);
	        List<String> names = list.stream().map(dataDictionary->{
	        	return dataDictionary.getName()+"@"+dataDictionary.getCode();
	        }
	        ).collect(Collectors.toList());
	        String[] str=names.toArray(new String[names.size()]);
		     return str;
	}
}

工具类

import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import com.yeejoin.amos.boot.module.jcs.api.mapper.DataDictionaryMapper;

public class ExcelUtil {
	/**
     * 生成excel模板
     *
     * @param response
     * @param fileName    下载的文件名,
     * @param sheetName   sheet名
     * @param data        导出的数据
     * @param model       导出的头
     * @param heardHeight 头行高
     */
    public static void createTemplate(HttpServletResponse response, String fileName,
                                      String sheetName, List<? extends Object> data,
                                      Class<?> model, int heardHeight, DataDictionaryMapper dataDictionaryMapper)  {
 
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = setMyCellStyle();
        try {
         	//下拉列表集合
            Map<Integer, String[]> explicitListConstraintMap = new HashMap<>();
          //循环获取对应列得下拉列表信息
            Field[] declaredFields = model.getDeclaredFields();
            for (int i = 0; i < declaredFields.length; i++) {
                Field field = declaredFields[i];
                //解析注解信息
                ExplicitConstraint explicitConstraint = field.getAnnotation(ExplicitConstraint.class);
                 resolveExplicitConstraint(explicitListConstraintMap,explicitConstraint,dataDictionaryMapper);
            }         	
			EasyExcel.write(getOutputStream(fileName, response, ExcelTypeEnum.XLSX), model).
			        excelType(ExcelTypeEnum.XLSX).sheet(sheetName)
			        .registerWriteHandler(new TemplateCellWriteHandlerDate(heardHeight,explicitListConstraintMap))
			        .registerWriteHandler(new TemplateCellWriteHandler())
			        .registerWriteHandler(horizontalCellStyleStrategy)
			        .doWrite(data);			
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("系统异常!");
			
		}
    }
    
    
    /**
     * 解析注解内容 获取下列表信息
     * @param explicitConstraint
     * @return
     */
    public static Map<Integer, String[]> resolveExplicitConstraint(  Map<Integer, String[]> explicitListConstraintMap,ExplicitConstraint explicitConstraint, DataDictionaryMapper dataDictionaryMapper){
        if (explicitConstraint == null) {
            return null;
        }
        //固定下拉信息
        String[] source = explicitConstraint.source();
        if (source.length > 0) {
        	explicitListConstraintMap.put(explicitConstraint.indexNum(), source);
        }
        //动态下拉信息
        Class<? extends ExplicitInterface>[] classes = explicitConstraint.sourceClass();
        if (classes.length>0){
            ExplicitInterface explicitInterface = null;
            try {
                explicitInterface = classes[0].newInstance();
                String[] source1 = explicitInterface.source(explicitConstraint.type(),dataDictionaryMapper);
                if (source1.length>0){
                	explicitListConstraintMap.put(explicitConstraint.indexNum(), source1);
                }
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    
    
    
    /**
     * 导出文件时为Writer生成OutputStream
     */
    private static OutputStream getOutputStream(String fileName, HttpServletResponse response, ExcelTypeEnum excelTypeEnum) throws Exception {
        //创建本地文件
        String filePath = fileName + excelTypeEnum.getValue();
        try {
            fileName = new String(filePath.getBytes(), StandardCharsets.ISO_8859_1);
            response.setCharacterEncoding(StandardCharsets.UTF_8.name());
            response.setContentType("application/vnd.ms-excel");
            response.addHeader("Content-Disposition", "filename=" + fileName);
            return response.getOutputStream();
        } catch (IOException e) {
            throw new Exception("系统异常");
        }
    }
    
    /**
     * 创建我的cell  策略
     *
     * @return
     */
    public static HorizontalCellStyleStrategy setMyCellStyle() {
     
        // 头的策略
        WriteCellStyle headWriteCellStyle = new WriteCellStyle();
        // 设置表头居中对齐
        headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 颜色
        headWriteCellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontHeightInPoints((short) 10);
        // 字体
        headWriteCellStyle.setWriteFont(headWriteFont);
        headWriteCellStyle.setWrapped(true);    
        // 内容的策略
        WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
        // 设置内容靠中对齐
        contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
        // 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
        HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
        // 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭   
        return horizontalCellStyleStrategy;
    }
}

拦截器



import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.DataFormat;
import org.apache.poi.ss.usermodel.FillPatternType;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import org.apache.poi.ss.usermodel.Workbook;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;

/**
 * excel通用单元格格式类
 */
public class TemplateCellWriteHandler implements CellWriteHandler {
 
	@Override
	public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row,
			Head head, int relativeRowIndex, boolean isHead) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData,
			Cell cell, Head head, int relativeRowIndex, boolean isHead) {
		   Workbook workbooks = writeSheetHolder.getSheet().getWorkbook();
		   writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 20 * 256);
	        CellStyle cellStyle = workbooks.createCellStyle();
	        cellStyle.setVerticalAlignment(VerticalAlignment.CENTER);//居中
	        cellStyle.setAlignment(HorizontalAlignment.CENTER);
	        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//设置前景填充样式
	        cellStyle.setFillForegroundColor(IndexedColors.ROYAL_BLUE.getIndex());//前景填充色
	        Font font1 = workbooks.createFont();//设置字体
	        font1.setBold(true);
	        font1.setColor((short)1);
	        font1.setFontHeightInPoints((short)15);
	        cellStyle.setFont(font1);
	        cell.setCellStyle(cellStyle);
	        //其他列
	        if (!isHead){
	            CellStyle style = workbooks.createCellStyle();
	            DataFormat dataFormat = workbooks.createDataFormat();
	            style.setDataFormat(dataFormat.getFormat("@"));
	            style.setVerticalAlignment(VerticalAlignment.CENTER);
	            style.setAlignment(HorizontalAlignment.CENTER);
	            cell.setCellStyle(style);
	        }
	        //设置日期
	        if (!isHead && cell.getColumnIndex()==19 || !isHead && cell.getColumnIndex()==21|| !isHead && cell.getColumnIndex()==20){
	            CellStyle style = workbooks.createCellStyle();
	            DataFormat dataFormat = workbooks.createDataFormat();
	            style.setDataFormat(dataFormat.getFormat("yyyy/mm/dd hh:mm:ss"));
	            style.setVerticalAlignment(VerticalAlignment.CENTER);
	            style.setAlignment(HorizontalAlignment.CENTER);
	            cell.setCellStyle(style);
	        }
	        //设置金额
	        if (!isHead && cell.getColumnIndex()==15 ||!isHead && cell.getColumnIndex()==16||!isHead && cell.getColumnIndex()==22 ||!isHead && cell.getColumnIndex()==24||!isHead && cell.getColumnIndex()==25){
	            CellStyle style = workbooks.createCellStyle();
	            DataFormat dataFormat = workbooks.createDataFormat();
	            style.setDataFormat(dataFormat.getFormat("0.00"));
	            style.setVerticalAlignment(VerticalAlignment.CENTER);
	            style.setAlignment(HorizontalAlignment.CENTER);
	            cell.setCellStyle(style);
	        }	        
	}
		
	

}

下拉数据多显示空白 处理

import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Name;
import org.apache.poi.ss.usermodel.Workbook;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
import java.util.HashMap;
import java.util.Map;

/**
 * excel通用单元格格式类下拉框赋值
 */
public class TemplateCellWriteHandlerDate implements SheetWriteHandler {
 
    /**
     * 模板的首行行高 ,通过构造器注入
     */
    private  int height;
    private Map<Integer, String[]> explicitListConstraintMap = new HashMap<>();
    public TemplateCellWriteHandlerDate(int height,Map<Integer, String[]> explicitListConstraintMap) {
        this.height = height;
        this.explicitListConstraintMap = explicitListConstraintMap;
    }
    /**
     * 设置阈值,避免生成的导入模板下拉值获取不到
     */
    private static final Integer LIMIT_NUMBER = 50;
   

		
	/**
     * 返回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;
    }

	@Override
	public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
		 // 这里可以对cell进行任何操作
        Sheet sheet = writeSheetHolder.getSheet();
        DataValidationHelper helper = sheet.getDataValidationHelper();

        // k 为存在下拉数据集的单元格下表 v为下拉数据集
        explicitListConstraintMap.forEach((k, v) -> {
            // 设置下拉单元格的首行 末行 首列 末列
            CellRangeAddressList rangeList = new CellRangeAddressList(1, 65536, k, k);
            // 如果下拉值总数大于100,则使用一个新sheet存储,避免生成的导入模板下拉值获取不到
            if (v.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.length; i < length; i++) {
                    // 开始的行数i,列数k
                    hiddenSheet.createRow(i).createCell(k).setCellValue(v[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.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);
            // 设置约束
            DataValidation validation = helper.createValidation(constraint, rangeList);
            // 阻止输入非下拉选项的值
            validation.setErrorStyle(DataValidation.ErrorStyle.STOP);
            validation.setShowErrorBox(true);
            validation.setSuppressDropDownArrow(true);
            validation.createErrorBox("提示", "此值与单元格定义格式不一致");
            // validation.createPromptBox("填写说明:","填写内容只能为下拉数据集中的单位,其他单位将会导致无法入仓");
            sheet.addValidationData(validation);
        });
		
	}

}

测试调用

@RestController
@Api(tags = "导出")
@RequestMapping(value = "/excel")
public class ExcelController extends BaseController {

	
	 @Autowired
	 DataDictionaryMapper dataDictionaryMapper;
	
	
	
	 @TycloudOperation(needAuth = false,ApiLevel = UserType.AGENCY)
	@ApiOperation(value = "下载模板")
	@GetMapping("/template")
	public void template2(HttpServletResponse response) {
	    String fileName = "导入模板";
	    String sheetName = "模板";
	    try {
	
	    	ExcelUtil.createTemplate(response, fileName, sheetName, null,
	    		   FireChemicalDto.class, FireChemicalDto.getHeadHeight(),dataDictionaryMapper);
	 
	    } catch (Exception e) {
	        e.printStackTrace();
	 
	    }
	}
   
}

参考多个博客,   https://blog.youkuaiyun.com/qq_32495261/article/details/108482413

https://blog.youkuaiyun.com/qq_38404386/article/details/103976220

评论 5
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值