本例主要示例EasyExecl 数据导入,如何处理数据验证
1:引入pom依赖
<!--easyExecl
-->
<dependency>
<groupId>com
.alibaba
</groupId
>
<artifactId>easyexcel
</artifactId
>
<version>2.1.4</version
>
</dependency
>
2:easyExecl核心类
import com
.alibaba
.excel
.annotation
.ExcelProperty
;
import com
.alibaba
.excel
.context
.AnalysisContext
;
import com
.alibaba
.excel
.event
.AnalysisEventListener
;
import com
.alibaba
.excel
.exception
.ExcelAnalysisException
;
import com
.alibaba
.excel
.util
.StringUtils
;
import com
.qingnian
.spring
.service
.ExcelCheckManager
;
import com
.qingnian
.spring
.utils
.EasyExcelValiHelper
;
import com
.qingnian
.spring
.utils
.ExcelCheckErrDto
;
import com
.qingnian
.spring
.utils
.ExcelCheckResult
;
import lombok
.Data
;
import lombok
.EqualsAndHashCode
;
import java
.lang
.reflect
.Field
;
import java
.util
.*
;
@Data
@EqualsAndHashCode(callSuper
=false)
public class EasyExcelListener <T> extends AnalysisEventListener<T> {
private List
<T> successList
= new ArrayList<>();
private List
<ExcelCheckErrDto
<T>> errList
= new ArrayList<>();
private ExcelCheckManager
<T> excelCheckManager
;
private List
<T> list
= new ArrayList<>();
private Class
<T> clazz
;
public EasyExcelListener(ExcelCheckManager
<T> excelCheckManager
){
this.excelCheckManager
= excelCheckManager
;
}
public EasyExcelListener(ExcelCheckManager
<T> excelCheckManager
,Class
<T> clazz
){
this.excelCheckManager
= excelCheckManager
;
this.clazz
= clazz
;
}
@Override
public void invoke(T t
, AnalysisContext analysisContext
) {
String errMsg
;
try {
errMsg
= EasyExcelValiHelper
.validateEntity(t
);
} catch (NoSuchFieldException e
) {
errMsg
= "解析数据出错";
e
.printStackTrace();
}
if (!StringUtils
.isEmpty(errMsg
)){
ExcelCheckErrDto excelCheckErrDto
= new ExcelCheckErrDto(t
, errMsg
);
errList
.add(excelCheckErrDto
);
}else{
list
.add(t
);
}
if (list
.size() > 1000){
ExcelCheckResult result
= excelCheckManager
.checkImportExcel(list
);
successList
.addAll(result
.getSuccessDtos());
errList
.addAll(result
.getErrDtos());
list
.clear();
}
}
@Override
public void doAfterAllAnalysed(AnalysisContext analysisContext
) {
ExcelCheckResult result
= excelCheckManager
.checkImportExcel(list
);
successList
.addAll(result
.getSuccessDtos());
errList
.addAll(result
.getErrDtos());
list
.clear();
}
@Override
public void invokeHeadMap(Map
<Integer, String> headMap
, AnalysisContext context
) {
super.invokeHeadMap(headMap
, context
);
if (clazz
!= null
){
try {
Map
<Integer, String> indexNameMap
= getIndexNameMap(clazz
);
Set
<Integer> keySet
= indexNameMap
.keySet();
for (Integer key
: keySet
) {
if (StringUtils
.isEmpty(headMap
.get(key
))){
throw new ExcelAnalysisException("解析excel出错,请传入正确格式的excel");
}
if (!headMap
.get(key
).equals(indexNameMap
.get(key
))){
throw new ExcelAnalysisException("解析excel出错,请传入正确格式的excel");
}
}
} catch (NoSuchFieldException e
) {
e
.printStackTrace();
}
}
}
@SuppressWarnings("rawtypes")
public Map
<Integer,String> getIndexNameMap(Class
clazz) throws NoSuchFieldException
{
Map
<Integer,String> result
= new HashMap<>();
Field field
;
Field
[] fields
=clazz
.getDeclaredFields();
for (int i
= 0; i
<fields
.length
; i
++) {
field
=clazz
.getDeclaredField(fields
[i
].getName());
field
.setAccessible(true);
ExcelProperty excelProperty
=field
.getAnnotation(ExcelProperty
.class);
if(excelProperty
!=null
){
int index
= excelProperty
.index();
String
[] values
= excelProperty
.value();
StringBuilder value
= new StringBuilder();
for (String v
: values
) {
value
.append(v
);
}
result
.put(index
,value
.toString());
}
}
return result
;
}
}
3: 定义业务验证总接口
import com
.qingnian
.spring
.utils
.ExcelCheckResult
;
import java
.util
.List
;
public interface ExcelCheckManager<T> {
ExcelCheckResult
checkImportExcel(List
<T> objects
);
}
4:定义业务校验的返回类,包含成功集,和失败集
import lombok
.Data
;
import java
.util
.ArrayList
;
import java
.util
.List
;
@Data
public class ExcelCheckResult<T> {
private List
<T> successDtos
;
private List
<ExcelCheckErrDto
<T>> errDtos
;
public ExcelCheckResult(List
<T> successDtos
, List
<ExcelCheckErrDto
<T>> errDtos
){
this.successDtos
=successDtos
;
this.errDtos
= errDtos
;
}
public ExcelCheckResult(List
<ExcelCheckErrDto
<T>> errDtos
){
this.successDtos
=new ArrayList<>();
this.errDtos
= errDtos
;
}
}
5:业务逻辑校验错误实体类
import lombok
.Data
;
@Data
public class ExcelCheckErrDto<T> {
private T t
;
private String errMsg
;
public ExcelCheckErrDto(){}
public ExcelCheckErrDto(T t
, String errMsg
){
this.t
= t
;
this.errMsg
= errMsg
;
}
}
=============================================== 接下来我们针对一个表,对其导入的数据做验证
CREATE TABLE `good`
(
`id`
bigint(20) NOT NULL DEFAULT
'0',
`name`
varchar(10) DEFAULT NULL COMMENT
'物品名称',
`price`
bigint(20) DEFAULT NULL COMMENT
'物品价格',
PRIMARY KEY
(`id`
)
) ENGINE
=InnoDB DEFAULT CHARSET
=utf8
;
@Data
public class Good {
private Long id
;
private int price
;
private String name
;
}
6:数据格式验证类
import com
.alibaba
.excel
.annotation
.ExcelProperty
;
import javax
.validation
.ConstraintViolation
;
import javax
.validation
.Validation
;
import javax
.validation
.Validator
;
import javax
.validation
.groups
.Default
;
import java
.lang
.reflect
.Field
;
import java
.util
.Set
;
public class EasyExcelValiHelper {
private EasyExcelValiHelper(){}
private static Validator validator
= Validation
.buildDefaultValidatorFactory().getValidator();
public static <T> String
validateEntity(T obj
) throws NoSuchFieldException
{
StringBuilder result
= new StringBuilder();
Set
<ConstraintViolation
<T>> set
= validator
.validate(obj
, Default
.class);
if (set
!= null
&& !set
.isEmpty()) {
for (ConstraintViolation
<T> cv
: set
) {
Field declaredField
= obj
.getClass().getDeclaredField(cv
.getPropertyPath().toString());
ExcelProperty annotation
= declaredField
.getAnnotation(ExcelProperty
.class);
result
.append(annotation
.value()[0]+cv
.getMessage()).append(";");
}
}
return result
.toString();
}
}
7:验证类可验证的Execl模板类说明
import com
.alibaba
.excel
.annotation
.ExcelProperty
;
import com
.alibaba
.excel
.metadata
.BaseRowModel
;
import com
.qingnian
.spring
.utils
.ExcelPatternMsg
;
import lombok
.Data
;
import org
.hibernate
.validator
.constraints
.Length
;
import javax
.validation
.constraints
.NotBlank
;
import javax
.validation
.constraints
.Pattern
;
@Data
public class GoodExecl extends BaseRowModel{
@ExcelProperty(index
= 0,value
= "id")
@Pattern(regexp
= ExcelPatternMsg
.NUMBER
,message
= ExcelPatternMsg
.NUMBER_MSG
)
@NotBlank(message
="主键不能为空")
private String id
;
@ExcelProperty(index
= 1,value
= "价格")
@Pattern(regexp
= ExcelPatternMsg
.DECIMAL
,message
= ExcelPatternMsg
.DECIMAL_MSG
)
private String price
;
@ExcelProperty(index
= 2,value
= "物品名称")
@Length(min
=0,max
= 10)
private String name
;
@ExcelProperty(index
= 3,value
= "备注信息")
private String errMessger
;
}
正则检验帮助类:
public class ExcelPatternMsg {
public static final String DECIMAL
= "^[0-9]+\\.{0,1}[0-9]{0,2}$";
public static final String DECIMAL_MSG
= "只能输入整数或者小数";
public static final String DATE1
= "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})\\/(((0[13578]|1[02])\\/(0[1-9]|[12][0-9]|3[01]))|"+
"((0[469]|11)\\/(0[1-9]|[12][0-9]|30))|(02\\/(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|"+
"((0[48]|[2468][048]|[3579][26])00))\\/02\\/29)$";
public static final String DATE1_MSG
= "输入正确的日期格式:yyyy/MM/dd";
public static final String DATE2
= "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|"+
"((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|"+
"((0[48]|[2468][048]|[3579][26])00))-02-29)$";
public static final String DATE2_MSG
= "输入正确的日期格式:yyyy-MM-dd";
public static final String DATE3
= "(([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|"+
"((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|"+
"((0[48]|[2468][048]|[3579][26])00))0229)$";
public static final String DATE3_MSG
= "输入正确的日期格式:yyyyMMdd";
public static final String DATE_TIME1
= "^((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})-(((0[13578]|1[02])-(0[1-9]|[12][0-9]|3[01]))|" +
"((0[469]|11)-(0[1-9]|[12][0-9]|30))|(02-(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))-02-29))\\s+([0-1]?[0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
public static final String DATE_TIME1_MSG
= "输入正确的日期格式:yyyy-MM-dd HH:mm:ss";
public static final String DATE_TIME2
= "((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})\\/(((0[13578]|1[02])\\/(0[1-9]|[12][0-9]|3[01]))|"+
"((0[469]|11)\\/(0[1-9]|[12][0-9]|30))|(02\\/(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|"+
"((0[48]|[2468][048]|[3579][26])00))\\/02\\/29))\\s([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
public static final String DATE_TIME2_MSG
= "输入正确的日期格式:yyyy/MM/dd HH:mm:ss";
public static final String DATE_TIME3
= "((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|"+
"((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|((0[48]|[2468][048]|[3579][26])00))0229))"+
"([0-1][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])$";
public static final String DATE_TIME3_MSG
= "输入正确的日期格式:yyyyMMddHHmmss";
public static final String DATE_TIME4
= "((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|"+
"((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|"+
"((0[48]|[2468][048]|[3579][26])00))0229))([0-1][0-9]|2[0-3])([0-5][0-9])([0-5][0-9])([0-9]{3})$";
public static final String DATE_TIME4_MSG
= "输入正确的日期格式:yyyyMMddHHmmssSSS";
public static final String DATE_TIME5
= "((([0-9]{3}[1-9]|[0-9]{2}[1-9][0-9]{1}|[0-9]{1}[1-9][0-9]{2}|[1-9][0-9]{3})(((0[13578]|1[02])(0[1-9]|[12][0-9]|3[01]))|"+
"((0[469]|11)(0[1-9]|[12][0-9]|30))|(02(0[1-9]|[1][0-9]|2[0-8]))))|((([0-9]{2})(0[48]|[2468][048]|[13579][26])|"+
"((0[48]|[2468][048]|[3579][26])00))0229))\\s([0-1][0-9]|2[0-3]):([0-5][0-9]):([0-5][0-9])$";
public static final String DATE_TIME5_MSG
= "输入正确的日期格式:yyyyMMdd HH:mm:ss";
public static final String NUMBER_LETTER
= "^[a-z0-9A-Z]+$";
public static final String NUMBER_LETTER_MSG
= "只能输入数字和字母";
public static final String NUMBER
= "^[0-9]*$";
public static final String NUMBER_MSG
= "只能输入数字";
}
8:业务接口继承业务校验总接口
import com
.qingnian
.spring
.domain
.Good
;
import com
.qingnian
.spring
.domain
.GoodExecl
;
public interface GoodService extends ExcelCheckManager<GoodExecl>{
Good
selectOne(Long id
);
}
9:业务实现类加以实现
import com
.qingnian
.spring
.dao
.GoodDao
;
import com
.qingnian
.spring
.domain
.Good
;
import com
.qingnian
.spring
.domain
.GoodExecl
;
import com
.qingnian
.spring
.service
.GoodService
;
import com
.qingnian
.spring
.utils
.ExcelCheckErrDto
;
import com
.qingnian
.spring
.utils
.ExcelCheckResult
;
import lombok
.extern
.slf4j
.Slf4j
;
import org
.apache
.commons
.lang3
.StringUtils
;
import org
.springframework
.beans
.factory
.annotation
.Autowired
;
import org
.springframework
.stereotype
.Service
;
import java
.util
.ArrayList
;
import java
.util
.List
;
@Service
@Slf4j
public class GoodServiceImpl implements GoodService {
public static final String ERR_NAME
= "史珍香";
@Autowired
private GoodDao goodDao
;
@Override
public Good
selectOne(Long id
) {
return goodDao
.selectOne(id
);
}
@Override
public ExcelCheckResult
checkImportExcel(List
<GoodExecl> objects
) {
List
<GoodExecl> successList
= new ArrayList<>();
List
<ExcelCheckErrDto
<GoodExecl>> errList
= new ArrayList<>();
for (GoodExecl GoodExecl
: objects
) {
StringBuilder errMsg
= new StringBuilder();
if (ERR_NAME
.equals(GoodExecl
.getName()))
errMsg
.append("请输入正确的名字").append(";");
if (StringUtils
.isEmpty(errMsg
.toString())){
successList
.add(GoodExecl
);
}else{
errList
.add(new ExcelCheckErrDto(GoodExecl
,errMsg
.toString()));
}
}
return new ExcelCheckResult(successList
,errList
);
}
}
10:控制层调用
@PostMapping("/importExcel")
public Result
importExcel(@RequestParam MultipartFile file
) throws IOException
{
Result result
= new Result();
EasyExcelListener easyExcelListener
= new EasyExcelListener(goodService
,GoodExecl
.class);
EasyExcelFactory
.read(file
.getInputStream(),GoodExecl
.class,easyExcelListener
).sheet().doRead();
List
<ExcelCheckErrDto
<GoodExecl>> errList
= easyExcelListener
.getErrList();
List successList
= easyExcelListener
.getSuccessList();
int successCount
=null
==successList
?0:successList
.size();
int errCount
=null
==errList
?0:errList
.size();
int total
=successCount
+errCount
;
result
.setMessage("验证通过"+successCount
+"条,失败"+errCount
+"条");
return result
;
}
@PostMapping("/importExcel/errExecl")
public void importExcelErrExecl(HttpServletResponse response
,HttpServletRequest request
, @RequestParam MultipartFile file
) throws IOException
{
EasyExcelListener easyExcelListener
= new EasyExcelListener(goodService
,GoodExecl
.class);
EasyExcelFactory
.read(file
.getInputStream(),GoodExecl
.class,easyExcelListener
).sheet().doRead();
List
<ExcelCheckErrDto
<GoodExecl>> errList
= easyExcelListener
.getErrList();
if (!errList
.isEmpty()){
List
<GoodExecl> excelErrDtos
= errList
.stream().map(excelCheckErrDto
-> {
GoodExeclErr goodExeclErr
= JSON
.parseObject(JSON
.toJSONString(excelCheckErrDto
.getT()), GoodExeclErr
.class);
goodExeclErr
.setErrMsg(excelCheckErrDto
.getErrMsg());
return goodExeclErr
;
}).collect(Collectors
.toList());
ExcelExportUtil
.export(excelErrDtos
,"商品表", "good",new GoodExecl(),response
,request
);
}
}