HZYWX-技术交流-开发中的导入导出

1 背景

  1. 需求:
    项目需求,导出excel或word;
    批量数据导入;
  2. 导入导出插件(API):
    HZYWX-技术交流-开发中的导入导出_第1张图片

前端导出(jquery.wordexport.js、tableExport.js、Blob对象、xlsx等)
后端导出(poi、poi-tl、easypoi)

  1. 具体情况分析:
    简单导入导出、复杂(多数据)导入导出、带图片导入导出

2 前端导出

前提:只支持简单导出(内容少,不要求样式,只支持导出)

2.1 jquery.wordexport.js

引入js:

jquery.js
FileSaver.js    //处理图片
jquery.wordexport.js

使用

$("#showDIV").wordExport(FileName)

处理

function export() {
	var htmlstr = $("#page").html();//table所在div
	$('#printWord').html(htmlstr);
	$('#printWord div[data-role=pager]').remove();//把分页div删除
	$('#showDIV script').remove();//div引用的js代码删除
	$('#name').html(name);
	$("#showDIV").wordExport(FileName)
}
<div id="showDIV" style="display:none">
    <style>
        #printWord table {
            border: 1px solid #ddd;
            border-collapse: collapse;
            width: 95%;
            margin: auto;
        }
            #printWord table tr td {
                border: 1px solid #ddd;
            }

            #printWord table tr th {
                border: 1px solid #ddd;
                border-radius: 10px;
            }
    </style>
    <h2 style="text-align: center;">
        隐患等级数量统计
    </h2>
    <div style="text-align: right;margin-right: 50px; font-size: 16px;font-style: italic">
        <span style="color: blue;">标题</span><span id="name"></span>
    </div>
    <div id="printWord" />
</div>

博客:

html:https://www.cnblogs.com/wyl1924/p/9896448.html?ivk_sa=1024320u
vue:https://blog.csdn.net/MISS_CJL/article/details/89466710

2.2 tableExport.js

引入js:

jquery.js
FileSaver.js  //处理图片
tableExport.js
base64.js  //避免导出中文时乱码的js文件

使用

$("#btnExport").click(function(){
  $("table").tableExport({
        type: 'excel',
        ignoreRow: [1,2],//不导出的行:从0开始
        ignoreColumn: [5],//不导出的列:从0开始,忽略第5列 
        htmlContent: true,
        fileName: title,//文件名
        worksheetName: title,//sheet表的名字
        excelstyles: ['text-align', 'font-size', 'font-weight', 'line-height', 'border-collapse', 'height', 'overflow', 'white-space', 'text-overflow'],若table表格中使用了以下指定的样式属性,则将该样式同步到Excel中(可以保留表格原有的样式到Excel中)
    });
});

2.3 前端利用Blob实现文件导出

function daochu() {
    // 使用outerHTML属性获取整个table元素的HTML代码(包括标签),然后包装成一个完整的HTML文档,设置charset为urf-8以防止中文乱码var html =""+ document.getElementById("aaa").outerHTML +"";
    html = html.replace("display: none","");
    html = html.replace("table table-striped table-bordered table-condensed","");// 实例化一个Blob对象,其构造函数的第一个参数是包含文件内容的数组,第二个参数是包含文件类型属性的对象var blob =newBlob([html],{
        type:"application/vnd.ms-excel"});var a = document.getElementById("print-click");//var textName = document.getElementById("biaoti").innerHTML;var textName ="整改意见";// 利用URL.createObjectURL()方法为a元素生成blob URL
    a.href = URL.createObjectURL(blob);// 设置文件名,目前只有Chrome和FireFox支持此属性
    a.download = textName +".xls";
    a.click();}
<div style="display: none;">
	<a id="print-click">超链接_导出表格</a>
</div>

type有以下选择:

1、“application/msword” Word
2、“application/vnd.ms-excel” Excel

2.4 xlsx插件导出(vue项目)

2.4.1 安装依赖
$ npm install -S file-saver
$ npm install -S xlsx
2.4.2 引入
import FileSaver from "file-saver";
import XLSX from "xlsx";
2.4.3 使用
exportExcel () {
      this.getData(() => {
        this.$nextTick(() => {
          let wb = XLSX.utils.table_to_book(
            document.querySelector("#out-table")
          );
          let wbout = XLSX.write(wb, {
            bookType: "xlsx",
            bookSST: true,
            type: "array",
          });

          try {
            FileSaver.saveAs(
              new Blob([wbout], { type: "application/octet-stream" }),
              "水质监测报告.xlsx"
            );
          } catch (e) {
            if (typeof console !== "undefined") console.log(e, wbout);
          }

          return wbout;
        });
      });
    },

2.4 vue-json-excel导出(vue项目)

http://events.jianshu.io/p/f4195f2a23ee

3 后端导出——poi

3.1 依赖

<!-- poi office -->
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi</artifactId>
    <version>3.9</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml</artifactId>
    <version>3.9</version>
</dependency>
<dependency>
    <groupId>org.apache.poi</groupId>
    <artifactId>poi-ooxml-schemas</artifactId>
    <version>3.9</version>
</dependency>

3.2 官方API

https://poi.apache.org/

4 POI操作excel

4.1 POI操作excel常用API

获得文档对象(工作簿):
xls: Workbook workbook= new HSSFWorkbook();
大数据量excel对象:Workbook workbook= new SXSSFWorkbook();
xlsx: Workbook workbook= new XSSFWorkbook();(常用)
Workbook workbook= new XSSFWorkbook(new FileInputStream());

获取工作表对象:
Sheet sheet = workbook.createSheet(“工作表名”);
Sheet sheet = workbook.getSheet(“工作表名”);
Sheet sheet = workbook.getSheetAt(索引);

获取行对象:
Row row = sheet.createRow(索引);
Row row = sheet.getRow(索引);

获取有效行:(如果sheet中一行数据都没有则返回-1,只有第一行有数据则返回0,最后有数据的行是第n行则返回 n-1)
int rowcount = sheet.getLastRowNum();

获取单元格对象:
Cell cell = row.createCell(索引)
Cell cell = row.getCell((short) 索引)

取得一行的有效单元格个数:(如果row中一列数据都没有则返回-1,只有第一列有数据则返回1,最后有数据的列是第n列则返回 n)
row.getLastCellNum();

设置行样式、字体:
CellStyle cellStyle = workbook.createCellStyle();
Font font = workbook.createFont();
cellStyle .setFont(font);
row.setRowStyle(CellStyle);

workbook(文件)=> sheet (表格) => row(行) => cell (单元格)

4.2 POI导出excel——示例工具类

public class ExportExcelUtil {

    public static void ExportExcel(List<Person> list, String[] titles) {
        SXSSFWorkbook wb = new SXSSFWorkbook();
        Sheet sheet = wb.createSheet();
        Row row = sheet.createRow(0);
        //给单元格设置样式
        CellStyle cellStyle = wb.createCellStyle();
        Font font = wb.createFont();
        //设置字体大小
        font.setFontHeightInPoints((short) 12);
        //设置字体加粗
        font.setBold(true);
        //给字体设置样式
        cellStyle.setFont(font);
        //设置单元格背景颜色
        cellStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());
        //设置单元格填充样式(使用纯色背景颜色填充)
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        for (int i = 0; i < titles.length; i++) {
            Cell cell = row.createCell(i);
            cell.setCellValue(titles[i]);
            cell.setCellStyle(cellStyle);
            //设置列的宽度
            sheet.setColumnWidth(i, 200*50);
        }
        for (int j = 0; j < list.size(); j++) {
            Row rowData = sheet.createRow(j + 1);
            Person person = list.get(j);
            Cell cell = rowData.createCell(0);
            cell.setCellValue(person.getId());
        }
        String fileName = "D:/人员信息导出.xlsx";
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(fileName);
            wb.write(fileOutputStream);
            wb.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

合并单元格

//合并单元格,参数依次为起始行、结束行、起始列、结束列
CellRangeAddress cellRangeAddress = new CellRangeAddress(0, 5, 0, 5);
sheet.addMergedRegion(cellRangeAddress);

包含图片

File file = new File(url) ;
if (file.exists()){
  BufferedImage bufferedImage = ImageIO.read(file) ;
  ByteArrayOutputStream byteArrayOut = new ByteArrayOutputStream();
  ImageIO.write(bufferedImage, "jpg", byteArrayOut);
  //画图的顶级管理器,一个sheet只能获取一个(一定要注意这点)
  HSSFPatriarch patriarch = sheet1.createDrawingPatriarch();
  //anchor主要用于设置图片的属性(端锚)
  //HSSFClientAnchor(int dx1, int dy1, int dx2, int dy2, short col1, int row1, short col2, int row2)
  //dx1 dy1 起始单元格中的x,y坐标,dx2 dy2 结束单元格中的x,y坐标
  //col1,row1 指定起始的单元格,col2,row2 指定结束的单元格 
  XSSFClientAnchor anchor = new XSSFClientAnchor(10, 10, 990, 250, (short)0, 0, (short) 0, 0);
  drawingPatriarch.createPicture(anchor, workbook.addPicture(byteArrayOut.toByteArray(), XSSFWorkbook.PICTURE_TYPE_JPEG));
} else {
  cell.setCellType(XSSFCell.CELL_TYPE_STRING);
  cell.setCellValue("");
}

4.3 POI导出excel——基于自定义注解

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellStyle;
import org.apache.poi.ss.usermodel.Comment;
import org.apache.poi.ss.usermodel.Font;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.Lists;
import com.sunny.reverse.common.utils.Encodes;
import com.sunny.reverse.common.utils.Reflections;
import com.sunny.reverse.common.utils.excel.annotation.ExcelField;
import com.sunny.reverse.modules.sys.utils.DictUtils;

/**
 * 导出Excel文件(导出“XLSX”格式,支持大数据量导出   @see org.apache.poi.ss.SpreadsheetVersion)
 * @author ThinkGem
 * @version 2013-04-21
 */
public class ExportExcel {
	
	private static Logger log = LoggerFactory.getLogger(ExportExcel.class);
			
	/**
	 * 工作薄对象
	 */
	private SXSSFWorkbook wb;
	
	/**
	 * 工作表对象
	 */
	private Sheet sheet;
	
	/**
	 * 样式列表
	 */
	private Map<String, CellStyle> styles;
	
	/**
	 * 当前行号
	 */
	private int rownum;
	
	/**
	 * 注解列表(Object[]{ ExcelField, Field/Method })
	 */
	List<Object[]> annotationList = Lists.newArrayList();
	
	/**
	 * 构造函数
	 * @param title 表格标题,传“空值”,表示无标题
	 * @param cls 实体对象,通过annotation.ExportField获取标题
	 */
	public ExportExcel(String title, Class<?> cls){
		this(title, cls, 1);
	}
	
	/**
	 * 构造函数
	 * @param title 表格标题,传“空值”,表示无标题
	 * @param cls 实体对象,通过annotation.ExportField获取标题
	 * @param type 导出类型(1:导出数据;2:导出模板)
	 * @param groups 导入分组
	 */
	public ExportExcel(String title, Class<?> cls, int type, int... groups){
		// Get annotation field 
		Field[] fs = cls.getDeclaredFields();
		for (Field f : fs){
			ExcelField ef = f.getAnnotation(ExcelField.class);
			if (ef != null && (ef.type()==0 || ef.type()==type)){
				if (groups!=null && groups.length>0){
					boolean inGroup = false;
					for (int g : groups){
						if (inGroup){
							break;
						}
						for (int efg : ef.groups()){
							if (g == efg){
								inGroup = true;
								annotationList.add(new Object[]{ef, f});
								break;
							}
						}
					}
				}else{
					annotationList.add(new Object[]{ef, f});
				}
			}
		}
		// Get annotation method
		Method[] ms = cls.getDeclaredMethods();
		for (Method m : ms){
			ExcelField ef = m.getAnnotation(ExcelField.class);
			if (ef != null && (ef.type()==0 || ef.type()==type)){
				if (groups!=null && groups.length>0){
					boolean inGroup = false;
					for (int g : groups){
						if (inGroup){
							break;
						}
						for (int efg : ef.groups()){
							if (g == efg){
								inGroup = true;
								annotationList.add(new Object[]{ef, m});
								break;
							}
						}
					}
				}else{
					annotationList.add(new Object[]{ef, m});
				}
			}
		}
		// Field sorting
		Collections.sort(annotationList, new Comparator<Object[]>() {
			public int compare(Object[] o1, Object[] o2) {
				return new Integer(((ExcelField)o1[0]).sort()).compareTo(
						new Integer(((ExcelField)o2[0]).sort()));
			};
		});
		// Initialize
		List<String> headerList = Lists.newArrayList();
		for (Object[] os : annotationList){
			String t = ((ExcelField)os[0]).title();
			// 如果是导出,则去掉注释
			if (type==1){
				String[] ss = StringUtils.split(t, "**", 2);
				if (ss.length==2){
					t = ss[0];
				}
			}
			headerList.add(t);
		}
		initialize(title, headerList);
	}
	
	/**
	 * 构造函数
	 * @param title 表格标题,传“空值”,表示无标题
	 * @param headers 表头数组
	 */
	public ExportExcel(String title, String[] headers) {
		initialize(title, Lists.newArrayList(headers));
	}
	
	/**
	 * 构造函数
	 * @param title 表格标题,传“空值”,表示无标题
	 * @param headerList 表头列表
	 */
	public ExportExcel(String title, List<String> headerList) {
		initialize(title, headerList);
	}
	
	/**
	 * 初始化函数
	 * @param title 表格标题,传“空值”,表示无标题
	 * @param headerList 表头列表
	 */
	private void initialize(String title, List<String> headerList) {
		this.wb = new SXSSFWorkbook(500);
		this.sheet = wb.createSheet("Export");
		this.styles = createStyles(wb);
		// Create title
		if (StringUtils.isNotBlank(title)){
			Row titleRow = sheet.createRow(rownum++);
			titleRow.setHeightInPoints(30);
			Cell titleCell = titleRow.createCell(0);
			titleCell.setCellStyle(styles.get("title"));
			titleCell.setCellValue(title);
			sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(),
					titleRow.getRowNum(), titleRow.getRowNum(), headerList.size()-1));
		}
		// Create header
		if (headerList == null){
			throw new RuntimeException("headerList not null!");
		}
		Row headerRow = sheet.createRow(rownum++);
		headerRow.setHeightInPoints(16);
		for (int i = 0; i < headerList.size(); i++) {
			Cell cell = headerRow.createCell(i);
			cell.setCellStyle(styles.get("header"));
			String[] ss = StringUtils.split(headerList.get(i), "**", 2);
			if (ss.length==2){
				cell.setCellValue(ss[0]);
				Comment comment = this.sheet.createDrawingPatriarch().createCellComment(
						new XSSFClientAnchor(0, 0, 0, 0, (short) 3, 3, (short) 5, 6));
				comment.setString(new XSSFRichTextString(ss[1]));
				cell.setCellComment(comment);
			}else{
				cell.setCellValue(headerList.get(i));
			}
			sheet.autoSizeColumn(i);
		}
		for (int i = 0; i < headerList.size(); i++) {  
			int colWidth = sheet.getColumnWidth(i)*2;
	        sheet.setColumnWidth(i, colWidth < 3000 ? 3000 : colWidth);  
		}
		log.debug("Initialize success.");
	}
	
	/**
	 * 创建表格样式
	 * @param wb 工作薄对象
	 * @return 样式列表
	 */
	private Map<String, CellStyle> createStyles(Workbook wb) {
		Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
		
		CellStyle style = wb.createCellStyle();
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
		Font titleFont = wb.createFont();
		titleFont.setFontName("Arial");
		titleFont.setFontHeightInPoints((short) 16);
		titleFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
		style.setFont(titleFont);
		styles.put("title", style);

		style = wb.createCellStyle();
		style.setVerticalAlignment(CellStyle.VERTICAL_CENTER);
		style.setBorderRight(CellStyle.BORDER_THIN);
		style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
		style.setBorderLeft(CellStyle.BORDER_THIN);
		style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
		style.setBorderTop(CellStyle.BORDER_THIN);
		style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
		style.setBorderBottom(CellStyle.BORDER_THIN);
		style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
		Font dataFont = wb.createFont();
		dataFont.setFontName("Arial");
		dataFont.setFontHeightInPoints((short) 10);
		style.setFont(dataFont);
		styles.put("data", style);
		
		style = wb.createCellStyle();
		style.cloneStyleFrom(styles.get("data"));
		style.setAlignment(CellStyle.ALIGN_LEFT);
		styles.put("data1", style);

		style = wb.createCellStyle();
		style.cloneStyleFrom(styles.get("data"));
		style.setAlignment(CellStyle.ALIGN_CENTER);
		styles.put("data2", style);

		style = wb.createCellStyle();
		style.cloneStyleFrom(styles.get("data"));
		style.setAlignment(CellStyle.ALIGN_RIGHT);
		styles.put("data3", style);
		
		style = wb.createCellStyle();
		style.cloneStyleFrom(styles.get("data"));
//		style.setWrapText(true);
		style.setAlignment(CellStyle.ALIGN_CENTER);
		style.setFillForegroundColor(IndexedColors.GREY_50_PERCENT.getIndex());
		style.setFillPattern(CellStyle.SOLID_FOREGROUND);
		Font headerFont = wb.createFont();
		headerFont.setFontName("Arial");
		headerFont.setFontHeightInPoints((short) 10);
		headerFont.setBoldweight(Font.BOLDWEIGHT_BOLD);
		headerFont.setColor(IndexedColors.WHITE.getIndex());
		style.setFont(headerFont);
		styles.put("header", style);
		
		return styles;
	}

	/**
	 * 添加一行
	 * @return 行对象
	 */
	public Row addRow(){
		return sheet.createRow(rownum++);
	}
	

	/**
	 * 添加一个单元格
	 * @param row 添加的行
	 * @param column 添加列号
	 * @param val 添加值
	 * @return 单元格对象
	 */
	public Cell addCell(Row row, int column, Object val){
		return this.addCell(row, column, val, 0, Class.class);
	}
	
	/**
	 * 添加一个单元格
	 * @param row 添加的行
	 * @param column 添加列号
	 * @param val 添加值
	 * @param align 对齐方式(1:靠左;2:居中;3:靠右)
	 * @return 单元格对象
	 */
	public Cell addCell(Row row, int column, Object val, int align, Class<?> fieldType){
		Cell cell = row.createCell(column);
		String cellFormatString = "@";
		try {
			if(val == null){
				cell.setCellValue("");
			}else if(fieldType != Class.class){
				cell.setCellValue((String)fieldType.getMethod("setValue", Object.class).invoke(null, val));
			}else{
				if(val instanceof String) {
					cell.setCellValue((String) val);
				}else if(val instanceof Integer) {
					cell.setCellValue((Integer) val);
					cellFormatString = "0";
				}else if(val instanceof Long) {
					cell.setCellValue((Long) val);
					cellFormatString = "0";
				}else if(val instanceof Double) {
					cell.setCellValue((Double) val);
					cellFormatString = "0.00";
				}else if(val instanceof Float) {
					cell.setCellValue((Float) val);
					cellFormatString = "0.00";
				}else if(val instanceof Date) {
					cell.setCellValue((Date) val);
					cellFormatString = "yyyy-MM-dd HH:mm";
				}else {
					cell.setCellValue((String)Class.forName(this.getClass().getName().replaceAll(this.getClass().getSimpleName(), 
						"fieldtype."+val.getClass().getSimpleName()+"Type")).getMethod("setValue", Object.class).invoke(null, val));
				}
			}
			if (val != null){
				CellStyle style = styles.get("data_column_"+column);
				if (style == null){
					style = wb.createCellStyle();
					style.cloneStyleFrom(styles.get("data"+(align>=1&&align<=3?align:"")));
			        style.setDataFormat(wb.createDataFormat().getFormat(cellFormatString));
					styles.put("data_column_" + column, style);
				}
				cell.setCellStyle(style);
			}
		} catch (Exception ex) {
			log.info("Set cell value ["+row.getRowNum()+","+column+"] error: " + ex.toString());
			cell.setCellValue(val.toString());
		}
		return cell;
	}

	/**
	 * 添加数据(通过annotation.ExportField添加数据)
	 * @return list 数据列表
	 */
	public <E> ExportExcel setDataList(List<E> list){
		for (E e : list){
			int colunm = 0;
			Row row = this.addRow();
			StringBuilder sb = new StringBuilder();
			for (Object[] os : annotationList){
				ExcelField ef = (ExcelField)os[0];
				Object val = null;
				// Get entity value
				try{
					if (StringUtils.isNotBlank(ef.value())){
						val = Reflections.invokeGetter(e, ef.value());
					}else{
						if (os[1] instanceof Field){
							val = Reflections.invokeGetter(e, ((Field)os[1]).getName());
						}else if (os[1] instanceof Method){
							val = Reflections.invokeMethod(e, ((Method)os[1]).getName(), new Class[] {}, new Object[] {});
						}
					}
					// If is dict, get dict label
					if (StringUtils.isNotBlank(ef.dictType())){
						val = DictUtils.getDictLabel(val==null?"":val.toString(), ef.dictType(), "");
					}
				}catch(Exception ex) {
					// Failure to ignore
					log.info(ex.toString());
					val = "";
				}
				this.addCell(row, colunm++, val, ef.align(), ef.fieldType());
				sb.append(val + ", ");
			}
			log.debug("Write success: ["+row.getRowNum()+"] "+sb.toString());
		}
		return this;
	}
	
	/**
	 * 输出数据流
	 * @param os 输出数据流
	 */
	public ExportExcel write(OutputStream os) throws IOException{
		wb.write(os);
		return this;
	}
	
	/**
	 * 输出到客户端
	 * @param fileName 输出文件名
	 */
	public ExportExcel write(HttpServletResponse response, String fileName) throws IOException{
		response.reset();
        response.setContentType("application/octet-stream; charset=utf-8");
        response.setHeader("Content-Disposition", "attachment; filename="+Encodes.urlEncode(fileName));
		write(response.getOutputStream());
		return this;
	}
	
	/**
	 * 输出到文件
	 * @param fileName 输出文件名
	 */
	public ExportExcel writeFile(String name) throws FileNotFoundException, IOException{
		FileOutputStream os = new FileOutputStream(name);
		this.write(os);
		return this;
	}
	
	/**
	 * 清理临时文件
	 */
	public ExportExcel dispose(){
		wb.dispose();
		return this;
	}
}

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.FIELD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelField {

	/**
	 * 导出字段名(默认调用当前字段的“get”方法,如指定导出字段为对象,请填写“对象名.对象属性”,例:“area.name”、“office.name”)
	 */
	String value() default "";
	
	/**
	 * 导出字段标题(需要添加批注请用“**”分隔,标题**批注,仅对导出模板有效)
	 */
	String title();
	
	/**
	 * 字段类型(0:导出导入;1:仅导出;2:仅导入)
	 */
	int type() default 0;

	/**
	 * 导出字段对齐方式(0:自动;1:靠左;2:居中;3:靠右)
	 */
	int align() default 0;
	
	/**
	 * 导出字段字段排序(升序)
	 */
	int sort() default 0;

	/**
	 * 如果是字典类型,请设置字典的type值
	 */
	String dictType() default "";
	
	/**
	 * 反射类型
	 */
	Class<?> fieldType() default Class.class;
	
	/**
	 * 字段归属组(根据分组导出导入)
	 */
	int[] groups() default {};
}

使用

@ExcelField(title="名称", align=2, sort=3)
public String getName() {return name;}
new ExportExcel("数据", xxx.class).setDataList(list).write(response, fileName).dispose();

4.4 POI导入excel

public String import(MultipartFile file) {
	String fileName = file.getOriginalFilename();
	InputStream is = file.getInputStream();
	if(fileName.toLowerCase().endsWith("xls")){
        HSSFWorkbook hssfWorkbook = new HSSFWorkbook(is);
        sheet1 = hssfWorkbook.getSheetAt(0);
	}else if(fileName.toLowerCase().endsWith("xlsx")) {
        XSSFWorkbook xssfWorkbook = new XSSFWorkbook(is);
        sheet1 = xssfWorkbook.getSheetAt(0);
	}
	//getLastRowNum  如果sheet中一行数据都没有则返回-1,只有第一行有数据则返回0,最后有数据的行是第n行则返回 n-1;
	//getLastCellNum  如果row中一列数据都没有则返回-1,只有第一列有数据则返回1,最后有数据的列是第n列则返回 n;
	for (int i = 0; i <= sheet1.getLastRowNum(); i++) {
		Row row = sheet1.getRow(i);
		for (int j = 0; j < row.getLastCellNum(); j++){
			row.getCell((short) j).getStringCellValue();
		}
	}
	//合并单元格的值,就是合并单元格首行首列的值
}

5 POI操作word

5.1 POI操作word常用API

获取文件
HWPFDocument hwpfDocument = new HWPFDocument(); --doc 不建议使用
XWPFDocument xwpfDocument = new XWPFDocument(); --docx
XWPFDocument xwpfDocument = new XWPFDocument(new FileInputStream()); --docx

操作段落 document(文件)=> paragraph(段落) => run
XWPFParagraph paragraph = document.createParagraph();
XWPFRun run=paragraph.createRun();
List paragraphs = document.getParagraphs();
List xwpfRuns = paragraphs .getRuns();
XWPFRun run = xwpfRuns.get(index);

操作表格 document(文件)=> table(段落) => row(行) => cell(单元格)
XWPFTable table = document.createTable();
XWPFTableRow row = table.createRow();
XWPFTableCell cell = row.createCell();
Lis tables = document.getTables();
List rows = table.getRows();
List tableCells = row.getTableCells();

建议大家使用 office word 来创建文档。(wps 和 word 结构有些不一样)
XWPFComment -------------------评论
XWPFFooter -------------------页脚
XWPFFootnotes -------------------脚注
XWPFHeader -------------------页眉
XWPFHyperlink -------------------超链接
XWPFNumbering -------------------编号
XWPFParagraph -------------------段落
XWPFPictureData -------------------图片
XWPFStyles -------------------样式(设置多级标题的时候用)
XWPFTable -------------------表格

5.2 POI导出word——直接导出示例

public void exportWord() {
	XWPFDocument document = new XWPFDocument();//文件
	XWPFParagraph paragraph;
	XWPFRun run;

	//建立段落
	paragraph = document.createParagraph();    //新建一个标题段落对象(就是一段文字)
	paragraph.setAlignment(ParagraphAlignment.CENTER);//样式居中
	run = paragraph.createRun();    //创建文本对象
	run.setBold(true); //加粗
	run.setColor("000000");//设置颜色
	run.setFontSize(25);    //字体大小
	run.setFontFamily("");//设置字体
	run.addBreak();    //换行
	run.setText("111");   //设置内容
	
	//建立表格
	XWPFTable table  = document.createTable(8,4);
	XWPFTableRow row;
	XWPFTableCell cell;
	CTTcPr cellPr;//单元格属性
	for(int j=0;j<8;j++){
		row = table.getRow(j);
		row.setHeight(600);
		for(int i=0;i<4;i++){//第一行
			cell = row.getCell(i);//建立单元格
			cell.setText("111");   //设置内容
			cellPr = cell.getCTTc().addNewTcPr();//单元格属性
			cellPr.addNewTcW().setW(BigInteger.valueOf(5000));//设置宽度
			cellPr.addNewVAlign().setVal(STVerticalJc.CENTER);//垂直居中
		}
	}
}

5.3 POI导出word——模板导出示例

public void exportWord(String templatePath) {
	Map<String, String> dataMap = new HashMap<>(); //替换模板数据的map
	//模板文件流
	InputStream is = new FileInputStream(templatePath);
	XWPFDocument doc = new XWPFDocument(is);
	//遍历模板表格替换字段
	if (doc.getTables() != null){
		for (int a = 0; a < doc.getTables().size(); a++) { //循环表格
			XWPFTable table = doc.getTables().get(a);
			for (int i = 0; i < table.getNumberOfRows(); i++) {  //循环行
				XWPFTableRow row = table.getRow(i);
				List<XWPFTableCell> cells = row.getTableCells();
				for (XWPFTableCell cell : cells) {  //循环单元格
					//遍历集合进行替换
					for (String key : dataMap.keySet()) {  //循环替换数据
						if (cell.getText().equals(key)) {
							cell.removeParagraph(0);
							cell.setText(dataMap.get(key));
							//设置样式
							CTTcPr tcpr = cell.getCTTc().addNewTcPr();
							CTVerticalJc va = tcpr.addNewVAlign();
							va.setVal(STVerticalJc.CENTER);
							cell.getCTTc().getPList().get(0).addNewPPr().addNewJc().setVal(STJc.CENTER);
						}
					}
				}
			}
		}
	}
}

5.4 POI导出word——包含图片

推荐使用poi-tl

5.5 POI导入word

段落内容

InputStream is;
XWPFDocument doc = new XWPFDocument(is);
List<XWPFParagraph> paragraphs = doc.getParagraphs();
String text = paragraphs.get(0).getText();

表格内容

public void exportWord(String templatePath) {
	Map<String, String> dataMap = new HashMap<>(); //替换模板数据的map
	//模板文件流
	InputStream is = new FileInputStream(templatePath);
	XWPFDocument doc = new XWPFDocument(is);
	//遍历模板表格替换字段
	if (doc.getTables() != null){
		for (int a = 0; a < doc.getTables().size(); a++) { //循环表格
			XWPFTable table = doc.getTables().get(a);
			for (int i = 0; i < table.getNumberOfRows(); i++) {  //循环行
				XWPFTableRow row = table.getRow(i);
				List<XWPFTableCell> cells = row.getTableCells();
				for (XWPFTableCell cell : cells) {  //循环单元格
					cell.getText();
				}
			}
		}
	}
}

图片(未测试)

List<XWPFPictureData> allPictures = doc.getAllPictures();
for (XWPFPictureData picture : allPictures) {
	byte[] data = picture.getData();
	FileOutputStream out;
	out.write(data);
	out.close();
}

6.poi-tl(word模板)

6.1官网

http://deepoove.com/poi-tl/

6.2 依赖(必须有poi依赖,且注意版本对应

<dependency>
	<groupId>com.deepoove</groupId>
	<artifactId>poi-tl</artifactId>
	<version>1.8.2</version>
</dependency>

HZYWX-技术交流-开发中的导入导出_第2张图片

6.3 介绍

Word模板支持DOCX格式,所有的标签都是以 {{ 开头,以 }} 结尾
HZYWX-技术交流-开发中的导入导出_第3张图片

6.4 使用

new ExportWord().export(new Object(), templatePath+"//wordTemplate//wordTemplate.docx",response);
public class ExportWord{
    public void export(Object object, String templatePath, HttpServletResponse response) throws IOException {
        Map<String, Object> mapData = getMapData(saveYearTaskVo);
        XWPFTemplate template = XWPFTemplate.compile(templatePath)
                .render(mapData);
        this.write(template,"xxx.docx");
    }

	private static Map<String, Object> getMapData(Object object){
        Map<String, Object> data = new HashMap<>();
        data.put("name", object.getName());
        return data;
    }

    private void write(XWPFTemplate template,HttpServletResponse response, String fileName) throws IOException {
        String fileNameURL = URLEncoder.encode(fileName, "UTF-8");
        response.setCharacterEncoding("UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + fileNameURL + ";" + "filename*=utf-8''" + fileNameURL);
        response.setContentType("application/octet-stream");
        //刷新缓冲
        response.flushBuffer();
        OutputStream ouputStream = response.getOutputStream();
        //doc将word写入到response的输出流中,供页面下载该word文件
        template.write(ouputStream);
        ouputStream.flush();
        ouputStream.close();
    }
}

6.5 图片模板

// 本地图片
put("localPicture", new PictureRenderData(120, 120, "./sayi.png"));

// 图片流文件
put("localBytePicture", new PictureRenderData(100, 120, ".png", new FileInputStream("./logo.png")));

// 网络图片
put("urlPicture", new PictureRenderData(100, 100, ".png", BytePictureUtils.getUrlBufferedImage("https://avatars3.githubusercontent.com/u/1394854")));

// java 图片
put("bufferImagePicture", new PictureRenderData(100, 120, ".png", bufferImage)));

6.6 表格模板

RowRenderData header = RowRenderData.build(new TextRenderData("FFFFFF", "姓名"), new TextRenderData("FFFFFF", "学历"));

RowRenderData row0 = RowRenderData.build("张三", "研究生");
RowRenderData row1 = RowRenderData.build("李四", "博士");
RowRenderData row2 = RowRenderData.build("王五", "博士后");

put("table", new MiniTableRenderData(header, Arrays.asList(row0, row1, row2)));

7.easypoi

7.1 官网

https://gitee.com/lemur/easypoi
http://doc.wupaas.com/docs/easypoi/easypoi-1c0u4mo8p4ro8

7.2 使用

7.2.1 特点

1.设计精巧,使用简单
2.接口丰富,扩展简单
3.默认值多,write less do more
4.spring mvc支持,web导出可以简单明了

7.2.2 依赖
 <dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-base</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-web</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>cn.afterturn</groupId>
    <artifactId>easypoi-annotation</artifactId>
    <version>3.2.0</version>
</dependency>
7.2.3 Excel导入导出

Excel的导入导出是Easypoi的核心功能,前期基本也是围绕这个打造的,主要分为三种方式的处理,其中模板和Html目前只支持导出,因为支持Map.class其实导入应该是怎样都支持的

  • 注解方式,注解变种方式
  • 模板方式
  • Html方式
7.2.4 注解方式导出示例
@ExcelTarget("teacherEntity")
public class TeacherEntity implements java.io.Serializable {
    /** name */
    @Excel(name = "主讲老师")
    private String name;
}
Workbook workbook = ExcelExportUtil.exportExcel(new ExportParams("计算机一班学生","学生"),
            StudentEntity .class, list);
  • @Excel 作用到filed上面,是对Excel一列的一个描述
  • @ExcelCollection 表示一个集合,主要针对一对多的导出,比如一个老师对应多个科目,科目就可以用集合表示
  • @ExcelEntity 表示一个继续深入导出的实体,但他没有太多的实际意义,只是告诉系统这个对象里面同样有导出的字段
  • @ExcelIgnore 和名字一样表示这个字段被忽略跳过这个导导出
  • @ExcelTarget 这个是作用于最外层的对象,描述这个对象的id,以便支持一个对象可以针对不同导出做出不同处理

8.Hutool

https://www.hutool.cn/
https://www.hutool.cn/docs/#/poi/Excel%E7%94%9F%E6%88%90-ExcelWriter?id=%e8%87%aa%e5%ae%9a%e4%b9%89excel

9.总结

HZYWX-技术交流-开发中的导入导出_第4张图片

注意:

  • poi-tl需要依赖poi,注意版本的对应
  • easypoi的依赖内部依赖原生的poi

8.1 优劣对比

8.1.1 前端导出
  • 优点:操作简单
  • 缺点:无法处理复杂样式、复杂数据
8.1.2 poi导入导出
  • 优点:能够处理几乎所有的导入导出功能
  • 缺点:导入导出的开发流程相对繁琐
8.1.3 poi-tl导出
  • 优点:操作简单,能够处理复杂的word导出
  • 缺点:只支持word导出
8.1.4 easypoi导入导出
  • 优点:操作简单
  • 缺点:

8.2 如何选择(个人理解)

  • 优先选择前端导出
  • 简单导出使用poi(基础)
  • 复杂导出使用poi-tl(word)或easypoi
  • 无法使用poi-tl或easypoi,回归poi

你可能感兴趣的:(java)