前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Excel文件导入导出操作

Excel文件导入导出操作

作者头像
沁溪源
发布2020-10-13 23:07:23
1.2K0
发布2020-10-13 23:07:23
举报
文章被收录于专栏:沁溪源沁溪源

日常开发工作中对于文件的相关操作大家多少都会涉及:上传解析、数据导出等。此篇内容主要分享一下工作中常用的Excel文件的解析和导出工作类实现。

实践

1.maven依赖

首先引入POI包依赖

代码语言:javascript
复制
<dependency>
   <groupId>org.apache.poi</groupId>
   <artifactId>poi</artifactId>
   <version>4.1.2</version>
</dependency>

<dependency>
   <groupId>org.apache.poi</groupId>
   <artifactId>poi-ooxml</artifactId>
   <version>4.1.2</version>
</dependency>

2.API

大家需要了解一下相关的API类,便于后面理解代码逻辑和排查问题,重写相关逻辑实现自己的业务需求。

代码语言:javascript
复制
  1.import org.apache.poi.ss.usermodel.Workbook,对应Excel文档;
  2.import org.apache.poi.hssf.usermodel.HSSFWorkbook,对应xls格式的Excel文档;
  3.import org.apache.poi.xssf.usermodel.XSSFWorkbook,对应xlsx格式的Excel文档;
  4.import org.apache.poi.ss.usermodel.Sheet,对应Excel文档中的一个sheet;
  5.import org.apache.poi.ss.usermodel.Row,对应一个sheet中的一行;
  6.import org.apache.poi.ss.usermodel.Cell,对应一个单元格。

3.导入

代码语言:javascript
复制
public class ImportExcelUtil {

    private static final String EXCEL_XLS_SUFFIX = ".xls";

    private static final String EXCEL_XLSX_SUFFIX = ".xlsx";
 /**
     * 读取Excel数据内容
     *
     * @param rowIndex    指定行号
     * @param columnIndex 指定列号
     * @return Map 包含单元格数据内容的Map对象
     */
    public static List<Map<Integer, Object>> readExcelContent(String filepath, Integer rowIndex, Integer columnIndex) throws Exception {
        List<Map<Integer, Object>> returnList = new LinkedList<>();
        Workbook wb = null;
        Sheet sheet;
        Row row;
        try {
            InputStream is = new FileInputStream(filepath);
            if (filepath.endsWith(EXCEL_XLS_SUFFIX)) {
                wb = new HSSFWorkbook(is);
            } else if (filepath.endsWith(EXCEL_XLSX_SUFFIX)) {
                wb = new XSSFWorkbook(is);
            }

            if (wb == null) {
                throw new Exception("Workbook对象为空!");
            }

            sheet = wb.getSheetAt(0);
            //解析文件总行数、总列数
            int rowNum = rowIndex != null ? rowIndex : sheet.getLastRowNum();
            row = sheet.getRow(0);
            int colNum = columnIndex != null ? columnIndex : row.getLastCellNum();

            //循环列
            for (int colIndex = colNum; colIndex > 0; colIndex--) {
                Cell cell = row.getCell(colIndex);
                if (cell != null && !"".equals(cell.toString())) {
                    colNum = colIndex;
                    break;
                }
            }
            logger.info("have data col:{}", colNum);

            // 正文内容应该从第二行开始,第一行为表头的标题
            for (int i = 0; i <= rowNum; i++) {
                row = sheet.getRow(i);
                int j = 0;

                int size = (int) (colNum / .75f) + 1;
                //存储单元格数据
                Map<Integer, Object> cellValue = new LinkedHashMap<>(size);

                if (row == null) {
                    continue;
                }

                while (j <= colNum) {
                    Cell cell = row.getCell(j);
                    String value = "";
                    //日期单元格需格式化日期
                    if (cell != null) {
                        if (cell.getCellType() == CellType.NUMERIC) {
                            if (HSSFDateUtil.isCellDateFormatted(cell)) {
                                Date d = cell.getDateCellValue();
                                SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
                                value = formatter.format(d);
                            } else if (cell.toString().contains("E")) {
                                DecimalFormat nf = new DecimalFormat("0");
                                value = nf.format(cell.getNumericCellValue());
                            } else {
                                value = cell.toString().endsWith(".0") ? cell.toString().replace(".0", "") : cell.toString().trim();
                            }
                        } else if (cell.getCellType() == CellType.FORMULA) {
                            value = String.valueOf(cell.getNumericCellValue());
                        } else {
                            value = cell.toString().trim();
                        }
                    }
                    cellValue.put(j, value);
                    j++;
                }
              returnList.add(cellValueMap);
            }
            wb.close();
        } catch (FileNotFoundException e) {
            logger.error("FileNotFoundException", e);
        } catch (IOException e) {
            logger.error("IOException", e);
        } finally {
            if (wb != null) {
                wb.close();
            }
        }
        return returnList;
    }

}

** 解释: ** 此处方法只是提供一个思路,后期大家可以根据自己的业务需求改写,比如指定sheet,行号,列号等等。着重说明一下返回值数据结构List,主要存储结构为Map,key=列号,value=单元格内容;这种操作便于后期验证必须列是否缺失、以及可以动态设计上传文件的列结构不必固定列位置等等。

4.导出

代码语言:javascript
复制
public class ExportExcelUtil {
	/**
	 * 导出excel文件,表头为一维数组表示不用合并单元格
	 * @param sheetName
	 * @param excelTitle
	 * @param dataCollection
	 * @param <T>
	 * @return
	 */
	public static<T> HSSFWorkbook exportExcel(String sheetName, String[] excelTitle, Collection<T> dataCollection) {
		//创建一个Excel文件
		HSSFWorkbook workbook = new HSSFWorkbook();
		//创建一个Sheet表格工作空间
		HSSFSheet sheet = workbook.createSheet(sheetName);
		HSSFCellStyle style = workbook.createCellStyle();
		//设置表格默认宽度
		sheet.setDefaultColumnWidth(20);
		//设置表格的表头
		HSSFCell cellHeader;
		HSSFRow row = sheet.createRow(0);
		for (int i = 0; i < excelTitle.length; i++) {
			//创建单元格表头
			cellHeader = row.createCell(i);
			cellHeader.setCellValue(new HSSFRichTextString(excelTitle[i]));
		}
		//匹配表头设置单元格的值
		setWorkBookValue(sheet, dataCollection,0, style);

		return workbook;
	}

/**
     * (根据自定义)把具体数据写入到excel中
     * @param sheet
     * @param dataCollection
     * @param index
     * @param style
     * @param <T>
     */
    @SuppressWarnings("unchecked")
	private static<T> void setWorkBookValue(HSSFSheet sheet,Collection<T> dataCollection, int index,HSSFCellStyle style){
		T t;
		Object[] fields;
		String fieldName;
		String getMethodName;
		HSSFCell cell;
		HSSFRow row;
		Class tClass;
		Method getMethod;
		Object value;
		//遍历集合设置单元格值
		Iterator<T> it = dataCollection.iterator();
		while(it.hasNext()){
			//创建一行单元格
			index ++;
			row = sheet.createRow(index);
			//获取数据
			t = it.next();
			//利用反射,根据JavaBean属性的先后顺序,动态调用getXxx()方法得到属性值
			fields = t.getClass().getDeclaredFields();
			for(int i = 0; i < fields.length; i++){
				cell = row.createCell(i);
				style.setAlignment(HorizontalAlignment.LEFT);
				cell.setCellStyle(style);
				//利用反射,根据JavaBean属性的先后顺序,动态调用getXxx()方法得到属性值
				Field[] newFields = t.getClass().getDeclaredFields();
				fieldName = newFields[i].getName();
				getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
				try {
					tClass = t.getClass();
					getMethod = tClass.getMethod(getMethodName, new Class[]{});
					value = getMethod.invoke(t, new Object[]{});
					setCellValue(value,cell);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}
/**
	 * value格式校验
	 */
	private static void setCellValue(Object value,HSSFCell cell){
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String textValue = null;
		Pattern pattern = Pattern.compile(RULE);
		Matcher matcher;
		HSSFRichTextString richTextString;
		if (!StringUtils.isEmpty(value)){
			//value进行类型转换
			if (value instanceof Integer) {
				cell.setCellValue((Integer) value);
			} else if (value instanceof Float) {
				textValue = String.valueOf(value);
				cell.setCellValue(textValue);
			} else if (value instanceof Double) {
				textValue = String.valueOf(value);
				cell.setCellValue(textValue);
			} else if (value instanceof Long) {
				cell.setCellValue((Long) value);
			} else if (value instanceof Boolean) {
				textValue = "是";
				if (!(Boolean) value) {
					textValue = "否";
				}
			} else if (value instanceof Date) {
				textValue = sdf.format((Date) value);
			} else {
				// 其它数据类型都当作字符串简单处理
				textValue = value.toString();
			}
			if (textValue != null) {
				matcher = pattern.matcher(textValue);
				if (matcher.matches()) {
					// 是数字当作double处理
					cell.setCellValue(Double.parseDouble(textValue));
				} else {
					richTextString = new HSSFRichTextString(textValue);
					cell.setCellValue(richTextString);
				}
			}
		}
	}

/**
	 * excel 导出文件
	 * @param response
	 * @param workbook
	 * @param fileName
	 * @throws IOException
	 */
	public static void exportExcelFile(HttpServletResponse response, HSSFWorkbook workbook, String fileName) throws IOException {
		if (workbook != null) {
			response.reset();
			//指定下载的文件名
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
			String filePrefix = sdf.format(new Date());
			response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf-8");
			fileName = URLEncoder.encode(filePrefix + "_" + fileName, "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
			BufferedOutputStream bufferedOutput = null;
			try {
				bufferedOutput = new BufferedOutputStream(response.getOutputStream());
				workbook.write(bufferedOutput);
				bufferedOutput.flush();
			} catch (IOException e) {
			    e.printStackTrace();
				throw e;
			} finally {
				if (bufferedOutput != null) {
					try {
						bufferedOutput.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}
}

外部访问导出文件示例:

代码语言:javascript
复制
public void exportFile(String objectJson, HttpServletResponse response) throws Exception {
		....
		//省略业务代码
        HSSFWorkbook workbook = ExportExcelUtil.exportExcel(SHEET_NAME, TITLE_LINE, xxxList);
        ExportExcelUtil.exportExcelFile(response, workbook, FILE_NAME);
    }

特殊说明:导出操作实际上利用反射机制实现,则需保证Excel标题列顺序需与导出定义的实体对象属性顺序保持一致,否则会出现错位现象。

本文参与?腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-10-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客?前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与?腾讯云自媒体分享计划? ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实践
    • 1.maven依赖
      • 2.API
        • 3.导入
          • 4.导出
          领券
          问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
          http://www.vxiaotou.com