ExcelUtil

说明:数据库使用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&amp;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;
    }

	
}

  

猜你喜欢

转载自davidhhs.iteye.com/blog/2299334