第一步: 将Excel表转换成List<ExcelDto> 其中 ExcelDto 属性全部设置成String (便于自定义注解正则校验)
第二步: 设置自定义注解(1:长度校验注解 2:正则校验注解 3:不能重复)
第三步:编写校验方法返回错误数据、错误数据list、 可导入数据list
第四步: 将可导入数据list导入数据库(涉及到相关数据库校验 例如:唯一性字段)
代码:
导入类:
package com.qkkj.hardwaremgmt.web.util;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.regex.Pattern;
import org.apache.commons.lang.time.FastDateFormat;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.DateUtil;
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.usermodel.WorkbookFactory;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import com.qkkj.hardwaremgmt.database.exceldto.ExcelColumn;
import com.qkkj.hardwaremgmt.database.exceldto.ExcelValidateResult;
import com.qkkj.hardwaremgmt.database.exceldto.ValidateNoRepeat;
import com.qkkj.hardwaremgmt.database.exceldto.ValidateNotBlank;
import com.qkkj.hardwaremgmt.database.exceldto.ValidateRegex;
import com.qkkj.hardwaremgmt.database.exceldto.ValidateSize;
/**
* 功能说明:Excel 导入/导出
* 典型用法:无
* 特殊用法:无
* 创建者:wangfd
* 创建时间: 2018年5月14日
* 修改时间:
* 修改原因:
* 修改内容:
* 版本号:1.0
*/
public class ImportExcelUtil {
private static final String PAGE_ROW_INDEX = "excelIndex"; //数据行所在页数和行数
private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat("0");// 格式化 number为整
private static final DecimalFormat DECIMAL_FORMAT_PERCENT = new DecimalFormat("##.00%");//格式化分比格式,后面不足2位的用0补齐
// private static final DecimalFormat df_per_ = new DecimalFormat("0.00%");//格式化分比格式,后面不足2位的用0补齐,比如0.00,%0.01%
// private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd"); // 格式化日期字符串
private static final FastDateFormat FAST_DATE_FORMAT = FastDateFormat.getInstance("yyyy/MM/dd");
private static final DecimalFormat DECIMAL_FORMAT_NUMBER = new DecimalFormat("0.00E000"); //格式化科学计数器
private static final Pattern POINTS_PATTERN = Pattern.compile("0.0+_*[^/s]+"); //小数匹配
/**
* 对外提供读取excel 的方法
* @param file
* @return
* @throws IOException
*/
public static List<List<Object>> readExcel(MultipartFile file) throws IOException {
String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
if(Objects.equals("xls", extension) || Objects.equals("xlsx", extension)) {
return readExcel(file.getInputStream());
} else {
throw new IOException("不支持的文件类型");
}
}
/**
* 对外提供读取excel 的方法
* @param file
* @param cls
* @return
* @throws IOException
*/
public static <T> List<T> readExcel(MultipartFile file, Class<T> cls) throws IOException {
String extension = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".") + 1).toLowerCase();
if(Objects.equals("xls", extension) || Objects.equals("xlsx", extension)) {
return readExcelString(file.getInputStream(), cls);
} else {
throw new IOException("不支持的文件类型");
}
}
/**
* 读取 office excel
*
* @param stream
* @return
* @throws IOException
*/
private static List<List<Object>> readExcel(InputStream inputStream) throws IOException {
List<List<Object>> list = new LinkedList<>();
Workbook workbook = null;
try {
workbook = WorkbookFactory.create(inputStream);
int sheetsNumber = workbook.getNumberOfSheets();
for (int n = 0; n < sheetsNumber; n++) {
Sheet sheet = workbook.getSheetAt(n);
Object value = null;
Row row = null;
Cell cell = null;
for (int i = sheet.getFirstRowNum() + 1; i <= sheet.getPhysicalNumberOfRows(); i++) { // 从第二行开始读取
row = sheet.getRow(i);
if (StringUtils.isEmpty(row)) {
continue;
}
List<Object> linked = new LinkedList<>();
for (int j = row.getFirstCellNum(); j <= row.getLastCellNum(); j++) {
cell = row.getCell(j);
if (StringUtils.isEmpty(cell)) {
continue;
}
value = getCellValue(cell);
linked.add(value);
}
list.add(linked);
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(inputStream != null){
inputStream.close();
}
if(workbook != null) {
workbook.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return list;
}
/**
* 获取excel数据 将之转换成bean
*
* @param path
* @param cls
* @param <T>
* @return
*/
@SuppressWarnings("unused")
private static <T> List<T> readExcel(InputStream inputStream, Class<T> cls) {
List<T> dataList = new LinkedList<T>();
Workbook workbook = null;
try {
workbook = WorkbookFactory.create(inputStream);
Map<String, List<Field>> classMap = new HashMap<String, List<Field>>();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
if (annotation != null) {
String value = annotation.value();
if (!classMap.containsKey(value)) {
classMap.put(value, new ArrayList<Field>());
}
field.setAccessible(true);
classMap.get(value).add(field);
}
}
Map<Integer, List<Field>> reflectionMap = new HashMap<Integer, List<Field>>();
int sheetsNumber = workbook.getNumberOfSheets();
for (int n = 0; n < sheetsNumber; n++) {
Sheet sheet = workbook.getSheetAt(n);
for (int j = sheet.getRow(0).getFirstCellNum(); j < sheet.getRow(0).getLastCellNum(); j++) { //首行提取注解
Object cellValue = getCellValue(sheet.getRow(0).getCell(j));
if (classMap.containsKey(cellValue)) {
reflectionMap.put(j, classMap.get(cellValue));
}
}
Row row = null;
Cell cell = null;
for (int i = sheet.getFirstRowNum() + 1; i < sheet.getPhysicalNumberOfRows(); i++) {
row = sheet.getRow(i);
T t = cls.newInstance();
for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
cell = row.getCell(j);
if (reflectionMap.containsKey(j)) {
Object cellValue = getCellValue(cell);
List<Field> fieldList = reflectionMap.get(j);
for (Field field : fieldList) {
try {
field.set(t, cellValue);
} catch (Exception e) {
//logger.error()
}
}
}
}
dataList.add(t);
}
}
} catch (Exception e) {
dataList = null;
} finally {
try {
if(inputStream != null){
inputStream.close();
}
if(workbook != null) {
workbook.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return dataList;
}
/**
* 获取excel数据 将之转换成bean
* 功能重写 excel 导入表数据都是string 存入数据库时候再转换
* @param path
* @param cls
* @param <T>
* @return
*/
private static <T> List<T> readExcelString(InputStream inputStream, Class<T> cls) {
List<T> dataList = new LinkedList<T>();
Workbook workbook = null;
try {
workbook = WorkbookFactory.create(inputStream);
Map<String, Field> tableHeads = new HashMap<String, Field>();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);//私有属性设置访问权限
ExcelColumn annotation = field.getAnnotation(ExcelColumn.class);
if (annotation != null) {
String value = annotation.value();//获得表头文字列名称
if (!tableHeads.containsKey(value)) {//获得列名称对应的数据库字段编码
tableHeads.put(value, field);
}
}
}
Map<Integer, Field> reflectionMap = new HashMap<Integer, Field>();
int sheetsNumber = workbook.getNumberOfSheets();
for (int n = 0; n < sheetsNumber; n++) {
Sheet sheet = workbook.getSheetAt(n);
if(sheet.getLastRowNum() == 0 && sheet.getPhysicalNumberOfRows() == 0) {
continue;
}
for (int j = sheet.getRow(0).getFirstCellNum(); j < sheet.getRow(0).getLastCellNum(); j++) { //首行提取注解
String cellValue = (String) getCellValue(sheet.getRow(0).getCell(j));
if (tableHeads.containsKey(cellValue)) {
reflectionMap.put(j, tableHeads.get(cellValue));
}
}
Row row = null;
Cell cell = null;
for (int i = sheet.getFirstRowNum() + 1; i < sheet.getPhysicalNumberOfRows(); i++) {
row = sheet.getRow(i);
T t = cls.newInstance();
for (int j = row.getFirstCellNum(); j < row.getLastCellNum(); j++) {
cell = row.getCell(j);
if (reflectionMap.containsKey(j)) {
Object cellValue = getCellValue(cell);
Field fielditem = reflectionMap.get(j);
fielditem.set(t, cellValue);
}
}
//数据行页数已经行数设置
StringBuffer pageRowIndex = new StringBuffer();
pageRowIndex = pageRowIndex.append(String.valueOf(n+1)).append(",").append(String.valueOf(i+1));
Field indexField = tableHeads.get(PAGE_ROW_INDEX);
indexField.set(t, pageRowIndex.toString());
dataList.add(t);
}
}
} catch (Exception e) {
dataList = null;
} finally {
try {
if(inputStream != null){
inputStream.close();
}
if(workbook != null) {
workbook.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return dataList;
}
/**
* 获取excel 单元格数据
*
* @param cell
* @return
*/
private static Object getCellValue(Cell cell) {
Object value = null;
switch (cell.getCellTypeEnum()) {
case _NONE:
break;
case STRING:
value = cell.getStringCellValue();
break;
case NUMERIC:
if(DateUtil.isCellDateFormatted(cell)){ //日期
value = FAST_DATE_FORMAT.format(DateUtil.getJavaDate(cell.getNumericCellValue()));//统一转成 yyyy/MM/dd
} else if("@".equals(cell.getCellStyle().getDataFormatString())
|| "General".equals(cell.getCellStyle().getDataFormatString())
|| "0_ ".equals(cell.getCellStyle().getDataFormatString())){
//文本 or 常规 or 整型数值
value = DECIMAL_FORMAT.format(cell.getNumericCellValue());
} else if(POINTS_PATTERN.matcher(cell.getCellStyle().getDataFormatString()).matches()){ //正则匹配小数类型
value = cell.getNumericCellValue(); //直接显示
} else if("0.00E+00".equals(cell.getCellStyle().getDataFormatString())){//科学计数
value = cell.getNumericCellValue(); //待完善
value = DECIMAL_FORMAT_NUMBER.format(value);
} else if("0.00%".equals(cell.getCellStyle().getDataFormatString())){//百分比
value = cell.getNumericCellValue(); //待完善
value = DECIMAL_FORMAT_PERCENT.format(value);
} else if("# ?/?".equals(cell.getCellStyle().getDataFormatString())){//分数
value = cell.getNumericCellValue(); 待完善
} else { //货币
value = cell.getNumericCellValue();
value = DecimalFormat.getCurrencyInstance().format(value);
}
break;
case BOOLEAN:
value = cell.getBooleanCellValue();
break;
case BLANK:
//value = ",";
break;
default:
value = cell.toString();
}
return value;
}
/**
* 校验字符串长度
*/
private static boolean ValidateLength(int min , int max , String value) {
if(null == value || StringUtils.isEmpty(value) || value.length()>max || value.length()<min) {
return false;
}
return true;
}
/**
* 校验字符串是否为空
*/
private static boolean ValidateBlank(String value) {
if(null==value || "".equals(value.trim())) {
return false;
}
return true;
}
/**
* 正则校验
*/
private static boolean ValidateRegex(String regex , String value) {
if(null == value || "".equals(value.trim())) {
return false;
}
return value.matches(regex);
}
/**
* 数据校验
* @param totalList
* @param cls
*/
@SuppressWarnings("unchecked")
public static <T> ExcelValidateResult validateExcel(List<T> totalList , Class<T> cls) {
try {
ExcelValidateResult result = new ExcelValidateResult();
//正确数据数量
List<T> importList = new LinkedList<T>();
//错误数据数量
List<T> errorList = new LinkedList<T>();
//错误信息
List<T> errorMessageList = new LinkedList<T>();
//重复性校验map
Map<String,Map<String,String>> mapRepeat = new HashMap<String,Map<String,String>>();
//设置数据总数
result.setTotalnumber(totalList.size());
Field[] fields = cls.getDeclaredFields();
for (int i = 0 ; i<totalList.size() ; i++) {
T errormessage = cls.newInstance();
T item = totalList.get(i);
boolean errorflag = false;
for (Field field : fields) {
field.setAccessible(true);//私有属性设置访问权限
String fieldValue = (String) field.get(item);//获取属性值
String fieldProperty = field.getName();
//非空校验
ValidateNotBlank annotationBlank = field.getAnnotation(ValidateNotBlank.class);
if (annotationBlank != null) {
if(!ValidateBlank(fieldValue)) {
String message = (String) field.get(errormessage);
if(StringUtils.isEmpty(message)) {
field.set(errormessage, annotationBlank.message());
}else {
field.set(errormessage, message + "," + annotationBlank.message());
}
errorflag = true;
};
}
//长度校验
ValidateSize annotationSize = field.getAnnotation(ValidateSize.class);
if (annotationSize != null) {
int max = annotationSize.max();
int min = annotationSize.min();
if(!ValidateLength(min, max, fieldValue)) {
String message = (String) field.get(errormessage);
if(StringUtils.isEmpty(message)) {
field.set(errormessage, annotationSize.message());
}else {
field.set(errormessage, message + "," + annotationSize.message());
}
errorflag = true;
};
}
//正则校验
ValidateRegex annotationRegex = field.getAnnotation(ValidateRegex.class);
if (annotationRegex != null) {
String regexContent = annotationRegex.regexContent();
if(!ValidateRegex(regexContent , fieldValue)) {
String message = (String) field.get(errormessage);
if(StringUtils.isEmpty(message)) {
field.set(errormessage, annotationRegex.message());
}else {
field.set(errormessage, message + "," + annotationRegex.message());
}
errorflag = true;
}
}
//重复性校验
ValidateNoRepeat annotationRepeat = field.getAnnotation(ValidateNoRepeat.class);
if (annotationRepeat != null) {
if(!mapRepeat.containsKey(fieldProperty)) {
Map<String,String> map = new HashMap<String,String>();
map.put(fieldValue, fieldValue);
mapRepeat.put(fieldProperty, map);
}else {
Map<String,String> map = mapRepeat.get(fieldProperty);
if(map.containsKey(fieldValue)) {
String message = (String) field.get(errormessage);
if(StringUtils.isEmpty(message)) {
field.set(errormessage, annotationRepeat.message());
}else {
field.set(errormessage, message + "," + annotationRepeat.message());
}
errorflag = true;
}else {
map.put(fieldValue,fieldValue);
mapRepeat.put(fieldProperty, map);
}
}
}
}
if(errorflag) {
errorList.add(item);
errorMessageList.add(errormessage);
}else {
importList.add(item);
}
}
result.setImportList((List<Object>) importList);
result.setErrorList((List<Object>) errorList);
result.setErrorMessageList((List<Object>) errorMessageList);
return result;
} catch (Exception e) {
return null;
}
}
}
自定义注解:
表头:
package com.qkkj.hardwaremgmt.database.exceldto;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ExcelColumn {
public String value() default "";
}
不能重复校验:
package com.qkkj.hardwaremgmt.database.exceldto;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidateNoRepeat {
public String message() default "内容不能重复";
}
非空校验:
package com.qkkj.hardwaremgmt.database.exceldto;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidateNotBlank {
public String message() default "内容不可以为空";
}
package com.qkkj.hardwaremgmt.database.exceldto;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
正则校验
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidateRegex {
public String message() default "内容格式不正确";
//默认时间格式校验 2018-01-01
public String regexContent() default "[0-9][0-9]-(0[1-9]|1[0-2])-(0[1-9]|1[0-9]|2[0-9]|3[01])";
}
长度校验:
package com.qkkj.hardwaremgmt.database.exceldto;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValidateSize {
//最小长度校验
public int min() default 0;
//最大长度校验
public int max() default 20;
public String message() default "长度不在合理范围内";
}
对象拷贝类:正对ExcelDto实体树形特性说有属性都是String 类型 -- 转换成对应的数据库实体 涉及到不同类型的转换
package com.qkkj.hardwaremgmt.web.util;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.lang.StringUtils;
/**
* 导入类型装换
* @author wangfudong
*
*/
public class BeanCopyUtils {
/**
* 复制名称相同类型相同字段的值
*
* @param obj
* @param clazz2
* @param <T1>
* @param <T2>
* @return
*/
public static <T1, T2> T2 copyData(T1 obj, Class<T2> clazz2) {
//1. 获取源数据的类
Class<? extends Object> clazz1 = obj.getClass();//源数据类
//2. 创建一个目标数据实例
final T2 obj2 = getInstance(clazz2);
//3. 获取clazz1和clazz2中的属性
Field[] fields1 = clazz1.getDeclaredFields();
Field[] fields2 = clazz2.getDeclaredFields();
//4. 遍历fields2
for (Field f1 : fields1) {
//4-1. 遍历fields1,逐字段匹配
for (Field f2 : fields2) {
// 复制字段
copyField(obj, obj2, f1, f2);
}
}
return obj2;
}
/**
* 复制相同名称相同类型的字段的值
*
* @param obj
* @param obj2
* @param f1
* @param f2
* @param <T1>
* @param <T2>
*/
private static <T1, T2> void copyField(T1 obj, T2 obj2, Field f1, Field f2) {
try {
//字段名要相同,字段类型也要相同
if (f1.getName().equals(f2.getName())){
//3-2. 获取obj这个字段的值
f1.setAccessible(true);
String val = (String) f1.get(obj);
Object valType = typeTancelation(val,f2.getType().getName());
//3-3. 把这个值赋给obj2这个字段
f2.setAccessible(true);
f2.set(obj2, valType);
//3-4. 访问权限还原
f2.setAccessible(false);
f1.setAccessible(false);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 获得泛型类的实例
*
* @param tClass
* @param <T>
* @return
*/
public static <T> T getInstance(Class<T> tClass) {
try {
T t = tClass.newInstance();
return t;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
/**
* 类型装换类
*/
private static Object typeTancelation(String value, String type) {
if("int".equals(type) ) {
return Integer.parseInt(value);
}else if("java.lang.Integer".equals(type)) {
return Integer.valueOf(value);
}else if("double".equals(type)) {
return Double.parseDouble(value);
}else if("java.lang.Double".equals(value)) {
return Double.valueOf(value);
}else if("float".equals(value)) {
return Float.parseFloat(value);
}else if("java.lang.Float".equals(value)) {
return Float.valueOf(value);
}else if("long".equals(type)) {
return Long.parseLong(value);
}else if("java.lang.Long".equals(type)) {
return Long.valueOf(value);
}else if("short".equals(type)) {
return Short.parseShort(value);
}else if("java.lang.Short".equals(type)) {
return Short.valueOf(value);
}else if("byte".equals(type)) {
return Byte.parseByte(value);
}else if("java.lang.Byte".equals(type)) {
return Byte.valueOf(value);
}else if("boolean".equals(type)) {
return Boolean.parseBoolean(value);
}else if("java.lang.Boolean".equals(type)) {
return Boolean.valueOf(value);
}else if("char".equals(type)) {
if(null == value || "".equals(value)) {
return null;
}else {
return value.charAt(0);
}
}else if("java.math.BigDecimal".equals(type)) {
return new BigDecimal(value);
}else if("java.util.Date".equals(type)) {
try {
//yyyy/mm/dd
if(value.indexOf("/")>=0) {
String[] arr = value.split("/");
if(arr[1].length()==1) {
arr[1] = "0"+arr[1];
}
if(arr[2].length()==1) {
arr[2] = "0"+arr[2];
}
List<String> typeList = Arrays.asList(arr);
return new SimpleDateFormat("yyyy-MM-dd").parse(StringUtils.join(typeList, '-'));
}
//yyyy-mm-dd
return new SimpleDateFormat("yyyy-MM-dd").parse(value);
} catch (ParseException e) {
return null;
}
}
return value;
}
}