EasyExcel导入导出excel 复杂表头 表头校验 数据校验

目录

EasyExcel特点

一.导入excel案例

二.读取excel的相关技术点

1.读取excel的方式

2.读取sheet数量

3.指定从第几行开始读数据

三.导出excel

1.前端发起请求

2.controller控制层

3.service层

4.实体类:复杂表头的情况,给@ExcelProperty的value赋值时,需要具备所有行的表头;使用注解@ExcelIgnore忽略导出的字段是否包含

5.设置导出excel的表头高宽:加在类上或者字段上


EasyExcel特点

 Java领域解析,生成Excel比较有名的框架有Apache poi,jxl等,但他们都存在一个严重的问题就是非常的耗内存,如果你的系统并发量不大的话可能还行,但是一旦并发上来后一定会OOM或者JVM频繁的full gc.

EasyExcel是阿里巴巴开源的一个excel处理框架,以使用简单,节省内存著称,EasyExcel能大大减少占用内存的主要原因是在解析Excel时没有将文件数据一次性全部加载到内存中,而是从磁盘上一行行读取数据,逐个解析。

EasyExcel采用一行一行的解析模式,并将一行的解析结果以观察者的模式通知处理(AnalysisEventListener)

如果在项目中已经使用了POI,再引入easyexcel可能会存在冲突,要注意对应的版本

		
		
			org.apache.poi
			poi
			3.17
		
		
			org.apache.poi
			poi-ooxml
			3.17
		
		
			org.apache.poi
			poi-scratchpad
			3.17
		
		
		
        
            com.alibaba
            easyexcel
            2.1.1
        

一.导入excel案例

需求:校验导入excel表头是否正确,excel行转成实体对象出错时,获取错误信息

1.前端:使用bootstrap的fileinput控件,设置上传的链接及上传结束后的提示信息

$("#file").fileinput({            
		language : 'zh',         
		uploadUrl :basePath+"roadData/uploadExcelFileNew",                     
		maxFileCount : 10,//表示允许同时上传的最大文件个数
		showCaption : true,//是否显示标题
		browseClass : "btn btn-primary", //按钮样式
		showPreview:true,       
	    allowedFileExtensions: ["xls", "xlsx"], 
		uploadAsync:true,                  
		msgFilesTooLess:'您必须至少选择{n}个文件才能上传,请点击“浏览”选择您需要上传的文件!',
		msgFilesTooMany:'超过了单次上传最大文件数{m}个,请分批次上传!',
		previewFileIcon: '',
		browseLabel : "浏览",
		msgSelected:'添加了{n}个文件',   
		dropZoneTitle:'拖拽文件到这里 …
最多支持10个文件上传
', uploadExtraData:function (previewId, index) { var data = { "isClearFlag": mini.get("isClearFlag").getValue() }; return data; }, previewFileIconSettings: { 'doc': '', 'xls': '', 'ppt': '', 'jpg': '', 'pdf': '', 'zip': '', 'htm': '', 'txt': '', 'mov': '', 'mp3': '', }, layoutTemplates:{ //是否显示预览下的上传按钮 actionUpload:'' }, previewFileExtSettings: { 'doc': function(ext) { return ext.match(/(doc|docx)$/i); }, 'xls': function(ext) { return ext.match(/(xls|xlsx)$/i); }, 'ppt': function(ext) { return ext.match(/(ppt|pptx)$/i); }, 'zip': function(ext) { return ext.match(/(zip|rar|tar|gzip|gz|7z)$/i); }, 'htm': function(ext) { return ext.match(/(php|js|css|htm|html)$/i); }, 'txt': function(ext) { return ext.match(/(txt|ini|md)$/i); }, 'mov': function(ext) { return ext.match(/(avi|mpg|mkv|mov|mp4|3gp|webm|wmv)$/i); }, 'mp3': function(ext) { return ext.match(/(mp3|wav)$/i); }, } }); $("#file").on('fileuploaded', function(event, data, previewId, index) { var message = mini.decode(data); if(message.response.type == 200){ showMsg("文件上传成功","success",1800,"center","center",closeWindow()); }else{ showMsg(message.response.msg,"danger",3000,"center","center"); } }); function closeWindow(action) { if (window.CloseOwnerWindow) return window.CloseOwnerWindow(action); else window.close(); }

2.controller控制层:文件上传调用的方法

 /**
     * @Description 上传文件--使用easyexcel方式解析
     * @author qingyun
     * @Date 2021年5月19日 上午10:26:03
     */
    @RequestMapping("/uploadExcelFileNew")  
	public String uploadExcelFileNew(@RequestParam("file") MultipartFile file, HttpServletRequest request,HttpServletResponse response) {
		return roadDataService.uploadExcelFileNew(file,request,response);  
	}

3.serice层:处理文件上传逻辑,这里定义一个工具类EasyExcelUtils进行处理,对处理结果根据Message标识判断是否解析正常,正常则设置其他字段值,把数据入库,不正常,则把message返回给前端

 /**
     * @Description 上传文件--使用easyexcel方式解析
     * @author qingyun
     * @Date 2021年5月19日 上午10:26:03
     */
	public String uploadExcelFileNew(MultipartFile file, HttpServletRequest request, HttpServletResponse response) {
		Message message = new Message();
		EasyExcelUtils easyExcelUtils = new EasyExcelUtils(RoadData.class);  //创建工具类时传递class,用于后面比对表头使用
		try {
			request.setCharacterEncoding("utf-8");
			response.setCharacterEncoding("utf-8");
			InputStream fileInput = file.getInputStream(); // 输入流
			EasyExcel.read(fileInput,RoadData.class,easyExcelUtils).sheet().doRead();
			message = easyExcelUtils.getMessage();
			if(Message.OK == message.getType()) {   //解析完成没有错误
				List list = easyExcelUtils.getList();   //使用Object类型存放集合
				if (null != list && list.size() > 0) {
					List areaList = getGjArea();  //获取到所有的政区集合
					Date nowDate = new Date();
				    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				    String nowDateStr = sdf.format(nowDate);
				    List roadDataList = new ArrayList();
					for (int i = 0;i < list.size();i++) { //设置其他非excel字段的值
						RoadData roadData = (RoadData) list.get(i);
						roadData.setId(this.getUUID());
						roadData.setCreateTime(nowDate);
						roadData.setCreateUserCode(this.getUserCode());
						roadData.setCreateUserName(this.getUserEntity().getName());
						roadData.setUnit(formatUnit(roadData.getUnit(),areaList));
						roadData.setPci_score(RoadImportUtils.getPCIScore(roadData.getRoadGradeName(), String.valueOf(roadData.getPci()), String.valueOf(roadData.getPciAfter()),String.valueOf(roadData.getRepYear()),roadData.getRectificaFlag()));
						roadData.setRqi_score(RoadImportUtils.getRQIScore(roadData.getPaveTypeName(), String.valueOf(roadData.getRqi()), String.valueOf(roadData.getRqiAfter()),String.valueOf(roadData.getRepYear()),roadData.getRectificaFlag()));
						roadData.setRdi_score(RoadImportUtils.getRDIScore(roadData.getRoadGradeName(), roadData.getPaveTypeName(),String.valueOf(roadData.getRdi()), String.valueOf(roadData.getRdiAfter()),String.valueOf(roadData.getRepYear()),roadData.getRectificaFlag()));
						roadDataList.add(roadData);
					}
					String isClearFlag = request.getParameter("isClearFlag");
					if("true".equals(isClearFlag)) {   //先清除数据再插入,只清楚在这次之前添加的数据
						String hql = "delete FROM score.road_data WHERE  DATE_FORMAT(create_time, '%Y-%m-%d %H:%i:%s' ) < '"+nowDateStr+"' ";
						this.getDao().saveOrUpdateBySql(hql, null);
					}
					roadDataRepository.save(roadDataList);
					message.setType(Message.OK);
					message.setMsg("文件上传解析成功");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			Message messageListener = easyExcelUtils.getMessage();
			if(null == messageListener || null == messageListener.getType()) {
				message.setType(Message.ERROR);
				message.setMsg("上传解析文件错误");
			}else {
				message = messageListener;
			}
		}
		return message.toJson();
	} 
  

4.EasyExcelUtils类:使用@Component注解修饰,使类加载进spring容器中进行管理;数据的类型使用Object进行定义,定义一个Mesage类用于记录解析和验证表头是否与模板一致的信息;创建EasyExcelUtils时,传递一个接收解析excel类的class对象,使用注解ExcelProperty获取到类的字段,并与excel中的进行比对,验证导入的excel是否符合要求。

/**
 * @Description 使用easyexcel方式解析数据的工具类
 * @author qingyun
 * @Date 2021年5月19日 上午10:35:58
 */
@Component
public class EasyExcelUtils extends AnalysisEventListener {

	List list = new ArrayList();
	
	Message message = new Message();
	
	Class clazz;
	
	
	
	public EasyExcelUtils() {
		super();
		// TODO Auto-generated constructor stub
	}

	public EasyExcelUtils(Class clazz) {
		super();
		this.clazz = clazz;
	}

	/**
	 * @Description invoke方法为一行一行读取excel内容
	 * @author qingyun
	 * @Date 2021年5月19日 上午10:43:17
	 */
	@Override
	public void invoke(Object data, AnalysisContext context) {
		list.add(data); 
	}
	
	/**
	 * @Description invokeHeadMap读取excel表头,校验表头是否正确
	 * @author qingyun
	 * @Date 2021年5月19日 上午10:44:43
	 */
	@Override
    public void invokeHeadMap(Map headMap, AnalysisContext context) {
        Map head = new HashMap<>();
		try {
			head = getIndexNameMap(clazz);   //通过class获取到使用@ExcelProperty注解配置的字段
		} catch (NoSuchFieldException e) {
			e.printStackTrace();
		}
        Set keySet = head.keySet();  //解析到的excel表头和实体配置的进行比对
        for (Integer key : keySet) {
            if (StringUtils.isEmpty(headMap.get(key))) {
            	message.setType(Message.ERROR);
            	message.setMsg("表头第"+key+1+"列为空,请参照模板填写");
                throw new ExcelAnalysisException("解析excel出错,请传入正确格式的excel");
            }
            if (!headMap.get(key).equals(head.get(key))) {
            	message.setType(Message.ERROR);
            	message.setMsg("表头第"+key+1+"列【"+headMap.get(key)+"】与模板【"+head.get(key)+"】不一致,请参照模板填写");
                throw new ExcelAnalysisException("解析excel出错,请传入正确格式的excel");
            }
        }
    }
	
    /**
     * @Description 读取完成之后进行的处理
     * @author qingyun
     * @Date 2021年5月19日 上午10:45:13
     */
	@Override
	public void doAfterAllAnalysed(AnalysisContext context) {
		if (null == message || message.getType() == null) {
			message.setMsg("数据解析完成");
			message.setType(Message.OK);
		}
	}

	/**
	 * @Description 通过class获取类字段信息
	 * @author qingyun
	 * @Date 2021年5月19日 下午1:41:47
	 */
	public Map getIndexNameMap(Class clazz) throws NoSuchFieldException {
	     Map result = new HashMap<>();
	     Field field;
	     Field[] fields = clazz.getDeclaredFields();     //获取类中所有的属性
	     for (int i = 0; i < fields.length; i++) {
	         field = clazz.getDeclaredField(fields[i].getName());
	         field.setAccessible(true);
	         ExcelProperty excelProperty = field.getAnnotation(ExcelProperty.class);//获取根据注解的方式获取ExcelProperty修饰的字段
	         if (excelProperty != null) {
	             int index = excelProperty.index();         //索引值
	             String[] values = excelProperty.value();   //字段值
	             StringBuilder value = new StringBuilder();
	             for (String v : values) {
	                 value.append(v);
	             }
	             result.put(index, value.toString());
	         }
	     }
	     return result;
	 }
	
	/**
	 * @Description 在转换异常 获取其他异常下会调用本接口。抛出异常则停止读取。如果这里不抛出异常则 继续读取下一行。
	 * @author qingyun
	 * @Date 2021年5月19日 下午3:02:49
	 */
	@Override
	public void onException(Exception exception, AnalysisContext context) {
	    // 如果是某一个单元格的转换异常 能获取到具体行号
	    // 如果要获取头的信息 配合invokeHeadMap使用
	    if (exception instanceof ExcelDataConvertException) {
	        ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException)exception;
	    	message.setType(Message.ERROR);
        	message.setMsg("第"+(excelDataConvertException.getRowIndex()+1)+"行,第"+(excelDataConvertException.getColumnIndex()+1)+"列解析异常,请参照模板填写");
	    }
	}

	public List getList() {
		return list;
	}

	public void setList(List list) {
		this.list = list;
	}

	public Message getMessage() {
		return message;
	}

	public void setMessage(Message message) {
		this.message = message;
	}
	
	
	
	
} 
  

5.RoadData实体类:使用@ExcelProperty注解标识字段,指定index和value,用于接收excel的值,以及进行表头的比对

public class RoadData implements Serializable {
	private static final long serialVersionUID = 1L;
    private String id;         //id
    @ExcelProperty(value = "年份",index = 0)
    private String repYear;         //年份
    
    @ExcelProperty(value = "养管单位",index = 1)
    private String unit;         //养管单位
    
    @ExcelProperty(value = "路线",index = 2)
    private String roadCode;         //路线编码
    
    @ExcelProperty(value = "上下行",index = 3)
    private String roadDirectName;         //行车方向
    
    @ExcelProperty(value = "路段起点",index = 4)
    private BigDecimal startStake;         //起点桩号
    
    @ExcelProperty(value = "路段终点",index = 5)
    private BigDecimal endStake;         //终点桩号
    
    @ExcelProperty(value = "长度km",index = 6)
    private BigDecimal roadLength;         //长度
    
    @ExcelProperty(value = "技术等级",index = 7)
    private String roadGradeName;         //技术等级
    
    @ExcelProperty(value = "路面类型",index = 8)
    private String paveTypeName;         //路面类型
    
    @ExcelProperty(value = "PQI",index = 9)
    private BigDecimal pqi;         //PQI
    
    @ExcelProperty(value = "PCI",index = 10)
    private BigDecimal pci;         //PCI
    
    @ExcelProperty(value = "RQI",index = 11)
    private BigDecimal rqi;         //rqi
    
    @ExcelProperty(value = "RDI",index = 12)
    private BigDecimal rdi;         //rdi
    
    @ExcelProperty(value = "DR",index = 13)
    private BigDecimal dr;         //dr
    
    @ExcelProperty(value = "IRI",index = 14)
    private BigDecimal iri;         //iri
    
    @ExcelProperty(value = "RD",index = 15)
    private BigDecimal rd;         //rd
    
    private BigDecimal pci_score;         //PCI得分
    
    private BigDecimal rqi_score;         //rqi得分
    
    private BigDecimal rdi_score;         //rdi得分
    

    @ExcelProperty(value = "PQI分级",index = 16)
    private String pqiGrade;         //PQI分级
    
    @ExcelProperty(value = "PCI分级",index = 17)
    private String pciGrade;         //PCI分级
    
    @ExcelProperty(value = "RQI分级",index = 18)
    private String rqiGrade;         //RQI分级
    
    @ExcelProperty(value = "RDI分级",index = 19)
    private String rdiGrade;         //RDI分级
    
    @ExcelProperty(value = "区域",index = 20)
    private String theAreaName;         //区域
    
    @ExcelProperty(value = "抽检性质",index = 21)
    private String randomNature;         //抽检性质
    
    @ExcelProperty(value = "PCI整改后得分",index = 22)
    private BigDecimal pciAfter;         //PCI整改后得分
    
    @ExcelProperty(value = "RQI整改后得分",index = 23)
    private BigDecimal rqiAfter;         //RQI整改后得分
    
    @ExcelProperty(value = "RDI整改后得分",index = 24)
    private BigDecimal rdiAfter;         //RDI整改后得分
    
    @ExcelProperty(value = "整改标识",index = 25)
    private String rectificaFlag;         //整改标识(未完成/已完成)
    
	private String createUserCode;
	private String createUserName;
	private Date createTime;
}

二.读取excel的相关技术点

1.读取excel的方式

(1)源码按路径path的方式

  public static ExcelReaderBuilder read(String pathName, Class head, ReadListener readListener) {
        ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
        excelReaderBuilder.file(pathName);
        if (head != null) {
            excelReaderBuilder.head(head);
        }
        if (readListener != null) {
            excelReaderBuilder.registerReadListener(readListener);
        }
        return excelReaderBuilder;
    }

(2)按文件输入流的方式读

  public static ExcelReaderBuilder read(InputStream inputStream, Class head, ReadListener readListener) {
        ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
        excelReaderBuilder.file(inputStream);
        if (head != null) {
            excelReaderBuilder.head(head);
        }
        if (readListener != null) {
            excelReaderBuilder.registerReadListener(readListener);
        }
        return excelReaderBuilder;
    }

(3)按file读取

 public static ExcelReaderBuilder read(File file, Class head, ReadListener readListener) {
        ExcelReaderBuilder excelReaderBuilder = new ExcelReaderBuilder();
        excelReaderBuilder.file(file);
        if (head != null) {
            excelReaderBuilder.head(head);
        }
        if (readListener != null) {
            excelReaderBuilder.registerReadListener(readListener);
        }
        return excelReaderBuilder;
    }

2.读取sheet数量

(1)只能读取到最前面的一个sheet

EasyExcel.read(fileInput,RoadData.class,easyExcelUtils).sheet().doRead()

(2)读取所有的sheet:

EasyExcel.read(fileInput,RoadData.class,easyExcelUtils).doReadAll()

(3)读取指定的sheet:

	ExcelReader excelReader = EasyExcel.read(fileInput).build();
		    // 这里为了简单 所以注册了 同样的head 和Listener 自己使用功能必须不同的Listener
		    ReadSheet readSheet1 =
		        EasyExcel.readSheet(0).head(RoadData.class).registerReadListener(easyExcelUtils).build();
		    ReadSheet readSheet2 =
		        EasyExcel.readSheet(1).head(RoadData.class).registerReadListener(easyExcelUtils).build();
		    // 这里注意 一定要把sheet1 sheet2 一起传进去,不然有个问题就是03版的excel 会读取多次,浪费性能
		    excelReader.read(readSheet1, readSheet2);
		    // 这里千万别忘记关闭,读的时候会创建临时文件,到时磁盘会崩的
		    excelReader.finish();

3.指定从第几行开始读数据

EasyExcel.read(fileInput,RoadData.class,easyExcelUtils).headRowNumber(1).doReadAll();
			

三.导出excel

1.前端发起请求

	function download(){  //导出报表
		var zqCode = "";
		var year = ""; 
		var params = {"zqCode":zqCode,"year":year};
    	var url = basePath + "roadData/download";
		downloadFile(url, params);    //组织和发送下载请求  
	}
	
	//组织和发送下载请求 
	function downloadFile(path, params) {
		$("#downloadform").remove();
		var form = $("
"); //定义一个form表单 form.attr("id", "downloadform"); form.attr("style", "display:none"); form.attr("target", ""); form.attr("method", "post"); form.attr("action", path); for(var key in params) { var input1 = $(""); input1.attr("type", "hidden"); input1.attr("name", key); input1.attr("value", params[key]); form.append(input1); } $("body").append(form); //将表单放置在web中 form.submit(); //表单提交() }

2.controller控制层

 @RequestMapping(value = { "/download" }, produces = { "text/html;charset=UTF-8" })
	@ResponseBody
	public void download(HttpServletRequest request, HttpServletResponse response) {
		response.setCharacterEncoding("UTF-8");
		//String id = request.getParameter("id");
		roadDataService.download(response);
	}

3.service层

	public void download(HttpServletResponse response) {
        String fileName;
		try {
			fileName = "文件名称.xlsx";
	        fileName = new String(URLEncoder.encode(fileName, "UTF-8").getBytes(), "ISO-8859-1");
			response.addHeader("Content-Disposition", " attachment;filename=" + fileName);
			response.setContentType("application/octet-stream");
			
	        ServletOutputStream out = response.getOutputStream();
			EasyExcel.write(out,RoadDataNew.class).sheet("学生列表").doWrite(getData());
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		
	}

4.实体类:复杂表头的情况,给@ExcelProperty的value赋值时,需要具备所有行的表头;使用注解@ExcelIgnore忽略导出的字段是否包含

/**
 * @Description 添加此类是处理复杂表头的情况
 * @author qingyun
 * @Date 2021年5月19日 下午4:51:26
 */
public class RoadDataNew implements Serializable {
	private static final long serialVersionUID = 1L;
	@ExcelIgnore
    private String id;         //id
    @ExcelProperty(value = {"年份","年份"},index = 0)
    private String repYear;         //年份
    
    @ExcelProperty(value = {"养管单位","养管单位"},index = 1)
    private String unit;         //养管单位
    
    @ExcelProperty(value = {"路线情况","路线"},index = 2)
    private String roadCode;         //路线编码
    
    @ExcelProperty(value = {"路线情况","上下行"},index = 3)
    private String roadDirectName;         //行车方向
    
    @ExcelProperty(value = {"路段起点","路段起点"},index = 4)
    private BigDecimal startStake;         //起点桩号
    
    @ExcelProperty(value = {"路段终点","路段终点"},index = 5)
    private BigDecimal endStake;         //终点桩号
    
    @ExcelProperty(value = {"长度km","长度km"},index = 6)
    private BigDecimal roadLength;         //长度
    
    @ExcelProperty(value = {"路面情况","技术等级"},index = 7)
    private String roadGradeName;         //技术等级
    
    @ExcelProperty(value = {"路面情况","路面类型"},index = 8)
    private String paveTypeName;         //路面类型
    
    @ExcelProperty(value = {"PQI","PQI"},index = 9)
    private BigDecimal pqi;         //PQI
    
    @ExcelProperty(value = {"PCI","PCI"},index = 10)
    private BigDecimal pci;         //PCI
    
    @ExcelProperty(value = {"RQI","RQI"},index = 11)
    private BigDecimal rqi;         //rqi
    
    @ExcelProperty(value = {"RDI","RDI"},index = 12)
    private BigDecimal rdi;         //rdi
    
    @ExcelProperty(value = {"DR","DR"},index = 13)
    private BigDecimal dr;         //dr
    
    @ExcelProperty(value = {"IRI","IRI"},index = 14)
    private BigDecimal iri;         //iri
    
    @ExcelProperty(value = {"RD","RD"},index = 15)
    private BigDecimal rd;         //rd
    
    @ExcelIgnore
    private BigDecimal pci_score;         //PCI得分
    
    @ExcelIgnore
    private BigDecimal rqi_score;         //rqi得分
    
    @ExcelIgnore
    private BigDecimal rdi_score;         //rdi得分
    

    @ExcelProperty(value = {"PQI分级","PQI分级"},index = 16)
    private String pqiGrade;         //PQI分级
    
    @ExcelProperty(value = {"PCI分级","PCI分级"},index = 17)
    private String pciGrade;         //PCI分级
    
    @ExcelProperty(value = {"RQI分级","RQI分级"},index = 18)
    private String rqiGrade;         //RQI分级
    
    @ExcelProperty(value = {"RDI分级","RDI分级"},index = 19)
    private String rdiGrade;         //RDI分级
    
    @ExcelProperty(value = {"区域","区域"},index = 20)
    private String theAreaName;         //区域
    
    @ExcelProperty(value = {"抽检性质","抽检性质"},index = 21)
    private String randomNature;         //抽检性质
    
    @ExcelProperty(value = {"PCI整改后得分","PCI整改后得分"},index = 22)
    private BigDecimal pciAfter;         //PCI整改后得分
    
    @ExcelProperty(value = {"RQI整改后得分","RQI整改后得分"},index = 23)
    private BigDecimal rqiAfter;         //RQI整改后得分
    
    @ExcelProperty(value = {"RDI整改后得分","RDI整改后得分"},index = 24)
    private BigDecimal rdiAfter;         //RDI整改后得分
    
    @ExcelProperty(value = {"整改标识","整改标识"},index = 25)
    private String rectificaFlag;         //整改标识(未完成/已完成)
    
    @ExcelIgnore
	private String createUserCode;
    
    @ExcelIgnore
	private String createUserName;
    
    @ExcelIgnore
	private Date createTime;
}

导出截图

EasyExcel导入导出excel 复杂表头 表头校验 数据校验_第1张图片

5.设置导出excel的表头高宽:加在类上或者字段上

@HeadRowHeight(40)   //设置投行高
@ContentRowHeight(20)//设置文本行高
@ColumnWidth(10)     //设置列宽

你可能感兴趣的:(easyexcel,poi,excel)