ExcelUtil
程序员文章站
2022-06-22 17:09:33
...
说明:数据库使用mysql,导入的字段类型只能是有varchar,Date 类型
火狐导出文件时做特殊设置,不能用url编码
源代码参考附件:
ExcelUtil.java: 导入核心代码
package com.lw.util; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.OutputStream; import java.lang.reflect.Field; import java.math.BigDecimal; import java.net.URLEncoder; import java.sql.SQLException; import java.text.ParseException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.InputMismatchException; import java.util.List; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.io.FilenameUtils; import org.apache.poi.hssf.usermodel.HSSFCell; import org.apache.poi.hssf.usermodel.HSSFCellStyle; import org.apache.poi.hssf.usermodel.HSSFDateUtil; import org.apache.poi.hssf.usermodel.HSSFFont; import org.apache.poi.hssf.usermodel.HSSFRow; import org.apache.poi.hssf.usermodel.HSSFSheet; import org.apache.poi.hssf.usermodel.HSSFWorkbook; import org.apache.poi.ss.usermodel.Cell; import org.apache.poi.ss.usermodel.CellValue; import org.apache.poi.ss.usermodel.FormulaEvaluator; 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.xssf.usermodel.XSSFWorkbook; /** * Excel组件 * * @author liwei * @version 1.0 * @since 1.0 */ public class ExcelUtil { /** * Excel 2003 */ private final static String XLS = "xls"; /** * Excel 2007 */ private final static String XLSX = "xlsx"; public static void main(String[] args) { String file = "d://importStudentDatas.xls"; String[] columnArray = new String[]{"code", "name", "birthDate"}; Map<String, ColumnCheckTypeEnum> checkColumn = new HashMap<String, ColumnCheckTypeEnum>(); checkColumn.put("code", ColumnCheckTypeEnum.CHECK_TYPE_PRICE_1); try { List<Student> list = ExcelUtil.excelToList(new File(file), 0, Student.class, columnArray, checkColumn); System.out.println(list.size()); for (int i = 0; i < list.size(); i++) { Student stu = list.get(i); System.out.println("编码:" + stu.getCode() + " >>>>> 名称:" + stu.getName() + " >>>>> 生日:" + stu.getBirthDate()); } } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } catch (ParseException e) { e.printStackTrace(); } } /*** * 导入Excel数据 * * <li>1、读取excel数据</li> * <li>2、校验数据的合法性(日期,金额,字符长度(和数据库结构比较))</li> * <li>3、合法数据绑定到bean对象中(反射)</li> * <li>4、得到数据层面校验通过的bean对象集合,</li> * @param file 导入数据文件 * @param entityClass bean对象类型bean.class * @param sheetIndex sheet索引 * @param columnArray 字段列数组 (需要导入的字段数组) * @param checkColumn 需要校验格式的字段列Map * @throws IOException * @throws NoSuchFieldException * @throws SecurityException * @throws InstantiationException * @throws SQLException * @throws IllegalAccessException * @throws ParseException */ public static <T> List<T> excelToList(File file, Integer sheetIndex, Class<T> entityClass, String[] columnArray, Map<String, ColumnCheckTypeEnum> checkColumn) throws IOException, SecurityException, NoSuchFieldException, InstantiationException, SQLException, IllegalAccessException, ParseException { List<T> list = new ArrayList<T>(); Workbook workbook = null; if (XLS.equalsIgnoreCase(FilenameUtils.getExtension(file.getName()))) { workbook = new HSSFWorkbook(new FileInputStream(file)); } else if (XLSX.equalsIgnoreCase(FilenameUtils.getExtension(file.getName()))) { workbook = new XSSFWorkbook(new FileInputStream(file)); } else { throw new IOException("导入excel出错,不支持文件类型!"); } if(sheetIndex==null) { sheetIndex = 0; } if((sheetIndex+1)>workbook.getNumberOfSheets()) { throw new IndexOutOfBoundsException("导入excel出错,指定sheet索引越界!"); } // sheet中要导出的列 if(columnArray==null || columnArray.length<1) { throw new NullPointerException("导入excel出错,导入列设置错误!"); } // 拿到sheet Sheet sheet = workbook.getSheetAt(sheetIndex); String sheetName = sheet.getSheetName(); // sheetName 使用表名称 // 解析公式结果 FormulaEvaluator evaluator = workbook.getCreationHelper().createFormulaEvaluator(); // 每个sheet中的数据 List<Map<String, Object>> dataList = readSheet(sheet, evaluator, columnArray); // 数据库表对应的字段列信息 List<ColumnData> columnDatas = null; try { columnDatas = ProDataUtil.getMySqlColumnDatas(sheetName, "scp"); } catch (SQLException e) { throw new SQLException("导入excel出错,获取表信息错误!"); } // 遍历数据库表对应的字段列信息 for(int j=0; j<dataList.size(); j++) { // 拿到每一行的数据 Map<String, Object> rowData = dataList.get(j); T o = null; try { o = (T) entityClass.newInstance(); } catch (IllegalAccessException e) { throw new IllegalAccessException("导入excel出错,错误信息:" + e.getMessage()); } for(int k=0; k<columnDatas.size(); k++) { ColumnData cd = columnDatas.get(k); Object value = rowData.get(cd.getColumnLowName()); String errMsg = "导入excel出错,错误位置>>:sheet【" + sheetName + "】中,第【"+ (j+1+1) +"】行,第【" + (getIndexOfArrayItem(cd.getColumnLowName(), columnArray) + 1 + 1) + "】列。错误信息:"; // 1、先根据设置,校验自定义校验的列 if(checkColumn.containsKey(cd.getColumnLowName())==false || ColumnCheckTypeEnum.CHECK_TYPE_NOTNULL.equals(checkColumn.get(cd.getColumnLowName()))==false) { if(value==null) { continue; } } ColumnCheckTypeEnum checkType = checkColumn.get(cd.getColumnLowName()); // 非空校验 if(ColumnCheckTypeEnum.CHECK_TYPE_NOTNULL.equals(checkType)) { if(value==null) { throw new InputMismatchException(errMsg + "此列为非空列,请检查excel数据是否为空!"); } } // 整数类型校验 else if(ColumnCheckTypeEnum.CHECK_TYPE_LONG.equals(checkType)) { try { Long.parseLong(value.toString()); } catch (NumberFormatException e) { throw new NumberFormatException(errMsg + "此列为整数列,单元格应设置为文本类型,请检查excel数据是否整数数字或单元格是否为文本类型!" + e.getMessage()); } } // 价格类型校验,取2位小数 else if(ColumnCheckTypeEnum.CHECK_TYPE_PRICE.equals(checkType)) { try { String price = value.toString(); new BigDecimal(price); if(price.indexOf(".")>-1 && price.split("\\.")[1].length()>2) { throw new InputMismatchException(errMsg + "此列为金额数值列,小数点后不超过2位小数,请检查excel数据是否合格!"); } } catch (NumberFormatException e) { throw new NumberFormatException(errMsg + "此列为金额数值列,请检查excel数据是否合格!"); } } // 价格类型校验,取4位小数 else if(ColumnCheckTypeEnum.CHECK_TYPE_PRICE_1.equals(checkType)) { try { String price = value.toString(); new BigDecimal(price); if(price.indexOf(".")>-1 && price.split("\\.")[1].length()>4) { throw new InputMismatchException(errMsg + "此列为金额数值列,小数点后不超过4位小数,请检查excel数据是否合格!"); } } catch (NumberFormatException e) { throw new NumberFormatException(errMsg + "此列为金额数值列,请检查excel数据是否合格!"); } } // 2、自定义校验完成后,进行常规校验 // 通过属性名称获取属性,把值设置到属性里面 Field field = entityClass.getDeclaredField(cd.getColumnLowName()); field.setAccessible(true); // 设置属性可访问, private if("java.lang.String".equalsIgnoreCase(cd.getJavaType())) { if(value.toString().length()>Integer.parseInt(cd.getDataMaxLength())) { throw new SQLException(errMsg + "字符长度超过数据库设置长度限制!数据库长度【"+cd.getDataMaxLength()+"】,当前文本长度【"+value.toString().length()+"】"); } try { field.set(o, value.toString()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(errMsg + e.getMessage()); } catch (IllegalAccessException e) { throw new IllegalAccessException(errMsg + e.getMessage()); } } else if("java.util.Date".equalsIgnoreCase(cd.getJavaType())) { try { field.set(o, (Date)value); } catch (ClassCastException e) { throw new ClassCastException(errMsg + "数据格式错误,无法将【"+value+"】转换为java.util.Date类型日期格式。" + e.getMessage()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(errMsg + e.getMessage()); } catch (IllegalAccessException e) { throw new IllegalAccessException(errMsg + e.getMessage()); } } else if("java.lang.Integer".equalsIgnoreCase(cd.getJavaType())) { try { // field.setInt(o, Integer.parseInt(value.toString())); // Int to Integer 赋值时类型不匹配 field.set(o, Integer.parseInt(value.toString())); } catch (NumberFormatException e) { throw new NumberFormatException(errMsg + "数据格式错误,无法将【"+value+"】转换为java.lang.Integer类型。" + e.getMessage()); } catch (IllegalArgumentException e) { throw new IllegalArgumentException(errMsg + e.getMessage()); } catch (IllegalAccessException e) { throw new IllegalAccessException(errMsg + e.getMessage()); } } } list.add(o); } return list; } /*** * 读取单个sheet * <p>导入Excel数据使用私有方法</p> * @param sheet 单个sheet * @param evaluator 解析公式结果 * @param columnArray 字段列数组 */ private static List<Map<String, Object>> readSheet(Sheet sheet, FormulaEvaluator evaluator, String... columnArray) { List<Map<String, Object>> list = new ArrayList<Map<String, Object>>(); int firstRowNum = sheet.getFirstRowNum(); int lastRowNum = sheet.getLastRowNum(); // 从第二行开始读取数据 for (int rowIndex = firstRowNum + 1; rowIndex <= lastRowNum; rowIndex++) { Row row = sheet.getRow(rowIndex); short firstCellNum = row.getFirstCellNum(); // short maxColIx = row.getLastCellNum(); Map<String, Object> rowMap = new HashMap<String, Object>(); // 读取列的时候,按照设置好的字段列的数量长度循环读取 for (short colIndex = firstCellNum; colIndex < columnArray.length; colIndex++) { Cell cell = row.getCell(new Integer(colIndex)+1); // 从第二列开始导入, 第一列序号列不做导入 CellValue cellValue = evaluator.evaluate(cell); if (cellValue == null) { continue; } // 经过公式解析,最后只存在Boolean、Numeric和String三种数据类型,此外就是Error了 // 其余数据类型,根据官方文档,完全可以忽略http://poi.apache.org/spreadsheet/eval.html switch (cellValue.getCellType()) { case Cell.CELL_TYPE_BOOLEAN: rowMap.put(columnArray[colIndex], cellValue.getBooleanValue()); break; case Cell.CELL_TYPE_NUMERIC: // 这里的日期类型会被转换为数字类型,需要判别后区分处理 if (HSSFDateUtil.isCellDateFormatted(cell)) { rowMap.put(columnArray[colIndex], cell.getDateCellValue()); } else { rowMap.put(columnArray[colIndex], cellValue.getNumberValue()); } break; case Cell.CELL_TYPE_STRING: rowMap.put(columnArray[colIndex], cellValue.getStringValue()); break; case Cell.CELL_TYPE_FORMULA: break; case Cell.CELL_TYPE_BLANK: break; case Cell.CELL_TYPE_ERROR: break; default: break; } } list.add(rowMap); } return list; } private static int getIndexOfArrayItem(String arrItem, String[] array) { int index = -1; for (int i = 0; i < array.length; i++) { if(array[i].equals(arrItem)) { index = i; break; } } return index; } /*** * 导出Excel数据 * @param sheetName sheet名称 * @param fileName 导出文件名 * @param list 要导出的数据 * @param response * @throws IOException */ public static void exportDatas(String sheetName, String fileName, List<Map<String, Object>> list, HttpServletRequest request, HttpServletResponse response) throws IOException { HSSFWorkbook wb = new HSSFWorkbook(); HSSFSheet sheet = wb.createSheet(sheetName); int rowNum = 0; // 设置单元格样式(标题样式) HSSFCellStyle styleTitle = wb.createCellStyle(); styleTitle.setBorderBottom(HSSFCellStyle.BORDER_THIN); styleTitle.setBorderLeft(HSSFCellStyle.BORDER_THIN); styleTitle.setBorderRight(HSSFCellStyle.BORDER_THIN); styleTitle.setBorderTop(HSSFCellStyle.BORDER_THIN); // 对齐方式 styleTitle.setAlignment(HSSFCellStyle.ALIGN_CENTER); styleTitle.setVerticalAlignment(HSSFCellStyle.VERTICAL_CENTER); // 字体 HSSFFont font = wb.createFont(); font.setBoldweight(HSSFFont.BOLDWEIGHT_BOLD); styleTitle.setFont(font); // 设置单元格样式(数据值样式) HSSFCellStyle styleContent = wb.createCellStyle(); styleContent.setBorderBottom(HSSFCellStyle.BORDER_THIN); styleContent.setBorderLeft(HSSFCellStyle.BORDER_THIN); styleContent.setBorderRight(HSSFCellStyle.BORDER_THIN); styleContent.setBorderTop(HSSFCellStyle.BORDER_THIN); styleContent.setAlignment(HSSFCellStyle.ALIGN_CENTER); // 标题行 HSSFRow rowTitle = sheet.createRow(rowNum++); int i = 0; HSSFCell cellH0 = rowTitle.createCell(i++); cellH0.setCellValue("序号"); cellH0.setCellStyle(styleTitle); for(Map.Entry<String, Object> tmp : list.get(0).entrySet()) { HSSFCell cellH = rowTitle.createCell(i++); cellH.setCellValue(tmp.getKey()); cellH.setCellStyle(styleTitle); } int cellOrder = 1; for (Map<String, Object> map : list) { HSSFRow row = sheet.createRow(rowNum++); int j = 0; // 序号 HSSFCell cellC0 = row.createCell(j++); cellC0.setCellValue(cellOrder++); cellC0.setCellStyle(styleContent); for(Map.Entry<String, Object> entry : map.entrySet()) { HSSFCell cellC = row.createCell(j++); sheet.setColumnWidth(cellC.getColumnIndex(), 256 * (11 + 10)); cellC.setCellValue(entry.getValue()+""); cellC.setCellStyle(styleContent); } } String agent = request.getHeader("User-Agent"); // 火狐浏览器导出文件不会url解码 if(StringUtil.isEmpty(agent)==false && agent.toLowerCase().indexOf("firefox")>-1) { response.setHeader("Content-disposition", "attachment;filename=\"" + new String(fileName.getBytes("UTF-8"), "ISO-8859-1")+".xls\""); } else { response.setHeader("Content-disposition", "attachment;filename=" + URLEncoder.encode(fileName+".xls", "UTF-8")); } response.setContentType("application/vnd.ms-excel;charset=UTF-8"); OutputStream out = response.getOutputStream(); wb.write(out); out.flush(); out.close(); } }
ProDataUtil.java 获取数据库表信息
package com.lw.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.List; public class ProDataUtil { private static String url = "jdbc:mysql://192.168.1.1:3306/dbName?characterEncoding=utf8&zeroDateTimeBehavior=convertToNull"; private static String username = "root"; private static String password = "root"; private static String driverClassName = "com.mysql.jdbc.Driver"; /** * 查询表的字段,封装成List * * @param tableName 表名 * @param schemaName 数据库名 * @return * @throws SQLException */ public static List<ColumnData> getMySqlColumnDatas(String tableName, String schemaName) throws SQLException { String SQLColumns = " select COLUMN_NAME,DATA_TYPE,column_comment,numeric_scale,numeric_precision,character_maximum_length,ordinal_position from information_schema.COLUMNS where table_name = '" + tableName + "'" + " and TABLE_SCHEMA='" + schemaName + "' " + " ORDER by ordinal_position"; Connection con = getConnection(); PreparedStatement ps = con.prepareStatement(SQLColumns); List<ColumnData> columnList = new ArrayList<ColumnData>(); ResultSet rs = ps.executeQuery(); while (rs.next()) { String name = rs.getString(1); String lowName = getColumnBeanName(name); // 将XXX_XXX转换成xxxXxx的格式 String type = rs.getString(2).toUpperCase(); // mysql 区分大小写 String javaType = getType(rs.getString(2), rs.getString(4), rs.getString(5)); // mysql 区分大小写 String comment = rs.getString(3); String dataScale = rs.getString(4); String dataPrecision = rs.getString(5); String dataMaxLength = rs.getString(6); ColumnData cd = new ColumnData(name, lowName, type, javaType, comment, dataScale, dataPrecision, dataMaxLength); columnList.add(cd); } rs.close(); ps.close(); con.close(); return columnList; } public static Connection getConnection() throws SQLException { try{ Class.forName(driverClassName); }catch(Exception e){ e.printStackTrace(); } return DriverManager.getConnection(url, username, password); } private static String getColumnBeanName(String column) { String[] split = column.split("_"); StringBuffer columnVal = new StringBuffer(); if (split.length > 1) { for (int i = 0; i < split.length; i++) { String colVal = ""; if (i == 0) { colVal = split[i].toLowerCase(); columnVal.append(colVal); } else { colVal = split[i].substring(0, 1).toUpperCase() + split[i].substring(1, split[i].length()).toLowerCase(); columnVal.append(colVal); } } columnVal.toString(); } else { String colVal = column.toLowerCase(); columnVal.append(colVal); } return columnVal.toString(); } /*** * 获取java类型 * @param type 数据库数据类型 * @param dataScale 小数位数 * @param dataPrecision 数据精度 * @return */ private static String getType(String type, String dataScale, String dataPrecision){ type=type.toLowerCase(); if("char".equalsIgnoreCase(type) || "varchar".equalsIgnoreCase(type)|| "varchar2".equalsIgnoreCase(type)){ return "java.lang.String"; }else if("NUMBER".equalsIgnoreCase(type)|| "numeric".equalsIgnoreCase(type)){// if((dataScale!=null&&!dataScale.equals("")&&!dataScale.equals("0"))){ if(dataPrecision!=null&&dataPrecision.equals("38")){ return "java.math.BigDecimal"; }else{ return "java.lang.Double"; } }else { if(dataPrecision!=null&&dataPrecision.equals("38")){ return "java.math.BigDecimal"; }else{ return "java.lang.Long"; } } }else if("decimal".equalsIgnoreCase(type)){// return "java.math.BigDecimal"; }else if( "DATE".equalsIgnoreCase(type)){ return "java.util.Date"; }else if( "DATETIME".equalsIgnoreCase(type)){ return "java.util.Date"; }else if( "BLOB".equalsIgnoreCase(type)){ return "java.sql.Blob"; }else if( "CLOB".equalsIgnoreCase(type)){ return "java.sql.Clob"; }else if("int".equalsIgnoreCase(type)){ return "java.lang.Integer"; }else if("TINYINT".equalsIgnoreCase(type)){ return "java.lang.Boolean"; }else if("double".equalsIgnoreCase(type)){ return "java.math.BigDecimal"; }else if("datetime".equalsIgnoreCase(type)){ return "java.util.Date"; } return null; } }