一、产品需求
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导入与数据校验的资料请关注代码网其它相关文章!
发表评论