实体类
@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
6070

被折叠的 条评论
为什么被折叠?



