一、产品需求
1.下载指定的excel数据模板
2.excel模板写入数据并导入
3.导入的时候根据校验规则进行筛选,导入成功的返回成功列表,数据存在问题的返回失败列表,失败列表支持数据编辑修正
看到需求的第一眼,可能就觉得第三点有点难度,我们知道,传统的数据校验可以通过在传输对象dto上面加注解实现。

//第一种
public result test1(@requestbody @validated testdto dto) {...}
//第二种
public result test2(@requestbody @valid testdto dto{...}
//第三种
public result test3(@requestbody @validated(value = {savegroup.class}) testdto dto) {...}
testdto里面会有一些类似 @notnull、@notblank、@size等校验注解,这里就不列了。
然后在全局异常拦截那里进行统一封装,使其返回的数据结构尽量保持统一,所以一般还得有一个restexceptionhandler类。
@controlleradvice
public class restexceptionhandler {
/**
* 处理参数验证失败异常
* @param e
* @return
*/
@exceptionhandler(methodargumentnotvalidexception.class)
@responsebody
@responsestatus(httpstatus.ok)
private response<?> methodargumentnotvalidexception(methodargumentnotvalidexception e) {
log.warn("methodargumentnotvalidexception", e);
fielderror fielderror = e.getbindingresult().getfielderror();
return responseutils.create(commoncodeenum.validate_error.getcode(), commoncodeenum.validate_error.getmessage(), fielderror.getdefaultmessage());
}
}讲到常见的数据校验,那么我们画风一转,再回来看需求,可见以上是不满足需求的,首先,我们的入参是一个文件流(指定的excel模板文件),我们得先解析文件再进行数据校验,合法的放一个集合,不合法的放另一个集合;再者,即使入参是一个数组,这种校验一旦不满足立马进异常处理了,无法返回给前端正确的数据结构,所以今天就分享解决这类需求的解决方案。
二、解决方法
基础数据
userexcelvo
import lombok.data;
import java.util.list;
/**
*
*/
@data
public class userexcelvo {
/**
* 成功列表
*/
private list<userexcel> success;
/**
* 失败列表
*/
private list<userexcel> fail;
}userexcel
import com.alibaba.excel.annotation.excelproperty;
import lombok.allargsconstructor;
import lombok.data;
import lombok.noargsconstructor;
import javax.validation.constraints.notblank;
import javax.validation.constraints.pattern;
import javax.validation.constraints.size;
import java.io.serializable;
/**
*
*/
@data
@allargsconstructor
@noargsconstructor
public class userexcel implements serializable {
@notblank(message = "手机号不能为空")
@size(max = 4)
@excelproperty(value = "用户名", index = 0)
private string name;
@excelproperty(value = "年龄", index = 1)
private integer age;
@pattern(regexp = "^[1][3,4,5,7,8][0-9]{9}$$", message = "手机号不合法")
@notblank(message = "手机号不能为空")
@excelproperty(value = "手机号", index = 2)
private string mobile;
@excelproperty(value = "性别", index = 3)
private string sex;
}excel模板数据:

方案一:大量if-else判断校验
import com.alibaba.excel.easyexcel;
import org.apache.commons.lang3.stringutils;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;
import org.springframework.web.multipart.multipartfile;
import java.io.ioexception;
import java.util.arraylist;
import java.util.list;
/**
*
*/
@restcontroller
@requestmapping("/excel")
public class excelcontroller {
@postmapping("/importexcel1")
public userexcelvo importexcel(@requestparam("file") multipartfile file) {
list<userexcel> list;
list<userexcel> fail = new arraylist<>();
userexcelvo userexcelvo = new userexcelvo();
string mobilereg = "^[1][3,4,5,7,8][0-9]{9}$";
try {
list = easyexcel.read(file.getinputstream(), userexcel.class, new modelexcellistener()).sheet().doreadsync();
list.foreach(data -> {
// 处理姓名的校验
if (stringutils.isempty(data.getname()) || data.getname().length() > 4) {
fail.add(data);
return;
}
// 处理手机号的校验
if (stringutils.isempty(data.getmobile()) || !data.getmobile().matches(mobilereg)) {
fail.add(data);
return;
}
// 以下根据字段多少可能有n个if...
});
userexcelvo.setfail(fail);
list.removeall(fail);
userexcelvo.setsuccess(list);
} catch (ioexception e) {
e.printstacktrace();
}
return userexcelvo;
}
}方案二:请求体加入注解进行校验
实际的业务场景,一个excel里面假如是订单数据,最少是几十个字段起步的,难道要写几十个if else吗?方案一明显是不合理的,因此使用注解的方式帮我们解决。
validationutils
import javax.validation.validation;
import javax.validation.validator;
import javax.validation.validatorfactory;
/**
*
*/
public class validationutils {
public static validator getvalidator() {
return validator;
}
static validator validator;
static {
validatorfactory validatorfactory = validation.builddefaultvalidatorfactory();
validator = validatorfactory.getvalidator();
}
}modelexcellistener
import com.alibaba.excel.context.analysiscontext;
import com.alibaba.excel.event.analysiseventlistener;
import lombok.extern.slf4j.slf4j;
import java.util.arraylist;
import java.util.list;
/**
*
*/
@slf4j
public class modelexcellistener extends analysiseventlistener<userexcel> {
private list<userexcel> datas = new arraylist<>();
/**
* 通过 analysiscontext 对象还可以获取当前 sheet,当前行等数据
*/
@override
public void invoke(userexcel data, analysiscontext context) {
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
log.info("读取到数据{}",data);
datas.add(data);
//根据业务自行处理,可以写入数据库等等
}
//所有的数据解析完了调用
@override
public void doafterallanalysed(analysiscontext context) {
log.info("所有数据解析完成");
}
}请求:
import com.alibaba.excel.easyexcel;
import org.springframework.web.bind.annotation.postmapping;
import org.springframework.web.bind.annotation.requestparam;
import org.springframework.web.bind.annotation.restcontroller;
import org.springframework.web.multipart.multipartfile;
import javax.validation.constraintviolation;
import java.io.ioexception;
import java.util.arraylist;
import java.util.list;
import java.util.set;
/**
*
*/
@restcontroller
@requestmapping("/excel")
public class excelcontroller {
@postmapping("/importexcel2")
public userexcelvo importexcelv2(@requestparam("file") multipartfile file) {
list<userexcel> list;
list<userexcel> fail = new arraylist<>();
userexcelvo userexcelvo = new userexcelvo();
try {
list = easyexcel.read(file.getinputstream(), userexcel.class, new modelexcellistener()).sheet().doreadsync();
list.foreach(data -> {
set<constraintviolation<userexcel>> violations = validationutils.getvalidator().validate(data);
if (violations.size() > 0) {
fail.add(data);
}
});
userexcelvo.setfail(fail);
list.removeall(fail);
userexcelvo.setsuccess(list);
} catch (ioexception e) {
e.printstacktrace();
}
return userexcelvo;
}
}三、测试结果
方案一的结果:
{
"success": [
{
"name": "张2",
"age": 19,
"mobile": "13056781235",
"sex": "女"
},
{
"name": "张3",
"age": 20,
"mobile": "13056781236",
"sex": "男"
},
{
"name": "张4",
"age": 21,
"mobile": "13056781237",
"sex": "女"
},
{
"name": "张5",
"age": 22,
"mobile": "13056781238",
"sex": "男"
},
{
"name": "张6",
"age": 23,
"mobile": "13056781239",
"sex": "男"
},
{
"name": "张7",
"age": 24,
"mobile": "13056781240",
"sex": "男"
},
{
"name": "张8",
"age": 25,
"mobile": "13056781241",
"sex": "男"
},
{
"name": "张9",
"age": 26,
"mobile": "13056781242",
"sex": "男"
}
],
"fail": [
{
"name": "张1",
"age": 18,
"mobile": "3056781234",
"sex": "男"
},
{
"name": "张10",
"age": 27,
"mobile": "130567812436",
"sex": "男"
}
]
}方案二的结果:
{
"success": [
{
"name": "张2",
"age": 19,
"mobile": "13056781235",
"sex": "女"
},
{
"name": "张3",
"age": 20,
"mobile": "13056781236",
"sex": "男"
},
{
"name": "张4",
"age": 21,
"mobile": "13056781237",
"sex": "女"
},
{
"name": "张5",
"age": 22,
"mobile": "13056781238",
"sex": "男"
},
{
"name": "张6",
"age": 23,
"mobile": "13056781239",
"sex": "男"
},
{
"name": "张7",
"age": 24,
"mobile": "13056781240",
"sex": "男"
},
{
"name": "张8",
"age": 25,
"mobile": "13056781241",
"sex": "男"
},
{
"name": "张9",
"age": 26,
"mobile": "13056781242",
"sex": "男"
}
],
"fail": [
{
"name": "张1",
"age": 18,
"mobile": "3056781234",
"sex": "男"
},
{
"name": "张10",
"age": 27,
"mobile": "130567812436",
"sex": "男"
}
]
}发现两种方案的测试结果虽然是一样的,但是很明显,方案二更优秀。我们后续写代码的时候,除了做功能,也要考虑代码的扩展性,不然产品说加个功能,我们又得吭哧吭哧写代码了。
以上就是使用java实现excel导入并进行数据校验的详细内容,更多关于java excel导入与数据校验的资料请关注代码网其它相关文章!
发表评论