-
2020-11-16 17:17:21
Flask接收请求
flask 通过request方法来接收前端请求过来的参数,具体常用的方法:
方法 描述 args get请求的方法 data 原始的请求数据 form 接收post请求方法的参数 files 接收文件请求参数 method 请求方式,加载页面的请求都是get请求 referer 请求来源 host 主机 host_url 主机地址 以上数据存放在url或者请求头部。
表单请求
就是利用HTML的表单和组件向服务器发起请求,在过程当中需要对form标签设置以下参数
参数 描述 method 请求方式,默认是GET action 请求的地址,就是将数据提交到哪里,默认提交到当前路由 enctype 用来表述请求数据不单单是字符 注意:form表单的元素必须有name标签,否者前端请求不发送数据。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="get" action="/index/"> <input type="text"> <button>搜索</button> </form> </body> </html>
POST请求
post请求用于向服务器提交数据,flask视图函数默认只接受get请求数据,post数据需要设置,并且使用request.form接受post数据
@app.route("/add_page/",methods = ["GET","POST"]) def add_page(): if request.method == "POST": #获取post提交的数据 data = request.form p_name = data.get("p_name") gender = data.get("gender") age = data.get("age") education = data.get("education") department = data.get("department") position = data.get("position") #定义工号 number = Person.query.all()[-1].id+1 #定义工资 m = 5000 # 基本工资 m_1 = 1000 # 职级工资 if position == "部长": m_1 = 1000 * 4 elif position == "经理": m_1 = 1000 * 3 elif position == "组长": m_1 = 1000 * 2 money = m + m_1 #保存数据 p = Person() p.work_number = str(number).zfill(8) p.p_name = p_name p.gender = gender p.age = age p.education = education p.department = department p.position = position p.money = money p.save() return render_template("add_page.html")
post数据需要在form标签上设置method属性
<form method="post"> <div> <label>姓名:</label> <input type="text" name="p_name"> </div> <div> <label>性别:</label> <input type="radio" value="男" name="gender">男 <input type="radio" value="女" name="gender">女 </div> <div> <label>年龄</label> <input type="number" name="age"> </div> <div> <label>学历</label> <input type="text" name="education"> </div> <div> <label>部门</label> <select name="department"> <option value="人事部">人事部</option> <option value="人事部">财务部</option> <option value="人事部">后勤部</option> <option value="人事部">研发部</option> <option value="人事部">销售部</option> <option value="人事部">安保部</option> <option value="人事部">市场部</option> <option value="人事部">采购部</option> </select> </div> <div> <label>职位</label> <select name="position"> <option value="部长">部长</option> <option value="经理">经理</option> <option value="组长">组长</option> <option value="职员">职员</option> </select> </div> <div> <input type="submit" value="提交"> </div> </form>
flask 表单文件提交
前端需要注意在form标签上添加enctype属性
<form method="post" enctype="multipart/form-data"> <div class="form-group"> <label class="control-label">标题:</label> <input class="form-control" type="text" name="title" placeholder="标题"> </div> <div class="form-group"> <label class="control-label">作者:</label> <input class="form-control" type="text" name="author" placeholder="作者"> </div> <div class="form-group"> <label class="control-label">内容:</label> <textarea class="form-control ckeditor" name="content"></textarea> </div> <div class="form-group"> <label class="control-label">图片:</label> <input type="file" name="picture"> </div> <div class="form-group"> <button class="btn btn-primary btn-block">提交</button> </div> </form>
后端需要request.files接收数据,并且在保存图片的同时,将路径保存到数据库
@app.route("/add_news/",methods = ["GET","POST"]) def add_news(): if request.method == "POST": data = request.form title = data.get("title") author = data.get("author") content = data.get("content") #保存图片 picture = request.files.get("picture") #图片名称 filename = picture.filename #图片保存路径 path = os.path.join( os.path.dirname( os.path.abspath(__file__) ),"static" ) file_path = os.path.join("img",filename) save_path = os.path.join(path,file_path) picture.save(save_path) #保存 news = News() news.title = title news.author = author news.content = content news.picture = file_path news.public_time = datetime.datetime.now() news.save() return redirect8 #跳转 return render_template("add_news.html")
ajax技术
常规web请求,总是会刷新页面,这个事情不是很好。
以用户名 重复校验为例子
前端可以通过js或者jq构建ajax结构
$.ajax({ url: "/has_user/?username="+value, //请求的地址 类似form的action type: "get", //请求的方法 类似form表单的method data: "", // 类似input的数据 success: function (data) { console.log(data); $("#error").text(data["d"]) }, //请求成功执行的函数,会接收返回的数据 error: function (error) { console.log(data) } //请求失败执行的函数,会接收返回的数据 })
注意ajax通常不会和页面共用一个视图,因为标准ajax数据返回格式是json。
@app.route("/demo/") def ajax_demo(): """ 返回页面 :return: """ return render_template("ajax_demo.html") from flask import jsonify #json @app.route("/has_user/") def has_user(): """ 处理ajax,数据返回到请求ajax地址的js当中 :return: """ user = request.args.get("username") p = Person.query.filter(Person.username == user).first() result = {"l":[1,2,3]} if p: result["d"] = "用户名已经存在" else: result["d"] = "用户名可以使用" return jsonify(result)
Cookie和Session
Cookie(曲奇)机制:在用户请求服务器的时候,服务器下发身份校验到用户本地,之后用户携带这个校验数据请求服务器其他地方,服务器通过这个校验数据识别用户身份,这种机制就是cookie机制。
HTTP的每次请求是独立的,和上一次,下一次请求没有关系,所以需要采用上述的cookie机制来进行身份校验。
由于cookie保存在本地,就会出现以下情况:
1、可以被拒绝
2、可以被仿照
3、可以被劫持
使用cookie步骤:
1、下发cookie(生成cookie)
cookie必须通过response对象进行下发,render_template返回的是一个字符串对象,需要使用make_response对象进行转换
response.set_cookie 可以设置cookie
参数 描述 key cookie的键 value cookie的值 max_age 寿命,有效期,秒 60*15 默认关闭浏览器,cookie过期 expires 过期时间,具体的时间节点,和max_age冲突 path cookie起作用的范围 默认是 /,也可以设置其他路由 domain 起作用的网站,或者域名 www.baidu.com secure 是否采用用安全的cookie传输方式 httponly 只使用http协议,不使用https协议 samesite 起作用的url from flask import make_response @app.route("/cookieExm/") def cookieExm(): response = make_response(render_template("empty.html")) response.set_cookie("name","laobian") return response
2、携带cookie请求,浏览器会自动安装cookie设置携带cookie去请求。
3、校验cookie
获取
比对
@app.route("/getcookie/") def getcookie(): name = request.cookies.get("hello") if name and name == "laobian": response = make_response("laobian") else: response = make_response("校验失败") return response
案例:
登录案例
密码加密
import hashlib def setPassWord(password): md5 = hashlib.md5() md5.update(password.encode()) return md5.hexdigest()
注册
@app.route("/register/",methods=["GET","POST"]) def register(): """ 密码需要加密 """ if request.method == "POST": #接收post数据 username = request.form.get("username") password = request.form.get("password") #校验用户名是否重复 user = Person.query.filter_by(username = username).first() if not user: p = Person() p.username = username #密码加密 p.password = setPassWord(password) #保存数据 p.save() #跳转到登录页面 return redirect("/login/") return render_template("register.html")
登录
@app.route("/login/",methods=["GET","POST"]) def login(): if request.method == "POST": # 接收post数据 username = request.form.get("username") password = request.form.get("password") password = setPassWord(password) #对请求密码加密 user = Person.query.filter_by(username = username,password = password).first() #校验用户名和密码 if user: #设置cookie respone = redirect("/index/") #本身就是response对象 respone.set_cookie("username",user.username) #设置cookie return respone #返回响应 return render_template("login.html")
首页
登录校验
from functools import wraps def is_login(fun): @wraps(fun) def inner(*args,**kwargs): username = request.cookies.get("username") if username and Person.query.filter_by(username=username).first(): return fun(*args,**kwargs) #返回被装饰函数的功能 else: return redirect("/login/") #否者返回登录页面 return inner
退出
@app.route("/logout/") def logout(): """ 退出就是删除cookie的过程 :return: """ response = redirect("/login/") response.delete_cookie("username") #删除客户浏览器本地cookie return response
更多相关内容 -
easypoi的使用-导入校验
2021-09-29 16:18:53easypoi导入校验 一、导入之基础校验 现在产品需要对导入的Excel进行校验,不合法的Excel不允许入库,需要返回具体的错误信息给前端,提示给用户,错误信息中需要包含行号以及对应的错误。 因为 EasyPOI 支持 ...easypoi导入校验
一、导入之基础校验
现在产品需要对导入的Excel进行校验,不合法的Excel不允许入库,需要返回具体的错误信息给前端,提示给用户,错误信息中需要包含行号以及对应的错误。
因为 EasyPOI 支持 Hibernate Validator ,所以直接使用就可以了,因为要将错误信息以及错误行号返回,所以需要用到 EasyPOI 的高级用法,实现
IExcelDataModel
与IExcelModel
接口,IExcelDataModel
负责设置行号,IExcelModel
负责设置错误信息如果使用到了 @Pattern 注解,则字段类型必须是 String 类型,否则会抛出异常
本文中的原
Integer
类型的gender
修改成为String
类型的genderStr
,record
字段也修改为了 String 类型的recordStr
等等同理如果校验 Date 类型字段,先将类型改成String,正则表达式参考下文写法。也就是说原本
Integer
类型的这里需要注意,如果@Excel注解中设置了
replace
属性,则Hibernate Validator 校验的是替换后的值导出时候的实体类
@Data public class TalentUserInputEntity{ @Excel(name = "姓名*") private String name; @Excel(name = "性别*") private Integer gender; @Excel(name = "手机号*") private String phone; @Excel(name = "开始工作时间*") private Date workTime; @Excel(name = "民族*") private String national; @Excel(name = "语言水平*") private String languageProficiency; @Excel(name = "出生日期*") private Date birth; @Excel(name = "职位*") private String jobsName; @Excel(name = "职位类型*") private String categoryName; @Excel(name = "薪资*") private Integer salary; @Excel(name = "工作地点*") private String workArea; @ExcelCollection(name = "工作经历*") private List<ExperienceInputEntity> experienceList; @ExcelCollection(name = "教育经历*") private List<EducationInputEntity> educationList; @ExcelCollection(name = "获奖情况") private List<AwardsInputEntity> awardList; @ExcelCollection(name = "技能证书") private List<PunishmentInputEntity> punishmentList; @Excel(name = "特长") private String specialty; }
导入时候的实体类
@Data public class TalentUserInputEntity implements IExcelDataModel, IExcelModel { // 时间格式校验正则 public static final String DATE_REGEXP = "(Mon|Tue|Wed|Thu|Fri|Sat|Sun)( )(Dec|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov)( )\\d{2}( )(00:00:00)( )(CST)( )\\d{4}"; /** * 行号 */ private int rowNum; /** * 错误消息 */ private String errorMsg; @Excel(name = "姓名*") @NotBlank(message = "[姓名]不能为空") private String name; @Excel(name = "性别*", replace = {"男_0", "女_1"}) @Pattern(regexp = "[01]", message = "性别错误") private String genderStr; @Excel(name = "手机号*") private String phone; @Excel(name = "开始工作时间*") @Pattern(regexp = DATE_REGEXP, message = "[开始工作时间]时间格式错误") private String workTimeStr; @Excel(name = "民族*") @NotBlank(message = "[民族]不能为空") private String national; @Excel(name = "语言水平*") @NotBlank(message = "[语言水平]不能为空") private String languageProficiency; @Excel(name = "出生日期*") @Pattern(regexp = DATE_REGEXP, message = "[出生日期]时间格式错误") private String birthStr; @Excel(name = "职位*") @NotBlank(message = "[职位]不能为空") private String jobsName; @Excel(name = "职位类型*") @NotBlank(message = "[职位类型]不能为空") private String categoryName; @Excel(name = "薪资*", replace = {"3K以下_1", "3K-5K_2", "5K-10K_3", "10K-20K_4", "20K-50K_5", "50K以上_6"}) @Pattern(regexp = "[123456]", message = "薪资信息错误") private String salaryStr; @Excel(name = "工作地点*") @NotBlank(message = "[工作地点]不能为空") private String workArea; @ExcelCollection(name = "工作经历*") private List<ExperienceInputEntity> experienceList; @ExcelCollection(name = "教育经历*") private List<EducationInputEntity> educationList; @ExcelCollection(name = "获奖情况") private List<AwardsInputEntity> awardList; @ExcelCollection(name = "技能证书") private List<PunishmentInputEntity> punishmentList; @Excel(name = "特长") private String specialty; @Override public String getErrorMsg() { return errorMsg; } @Override public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } @Override public Integer getRowNum() { return rowNum; } @Override public void setRowNum(Integer rowNum) { this.rowNum = rowNum; } // 工作经历 @Data public class ExperienceInputEntity { @Excel(name = "公司名称*") private String companyName; @Excel(name = "所在行业*") private String industry; @Excel(name = "开始时间*") @Pattern(regexp = DATE_REGEXP, message = "[工作经历][开始时间]时间格式错误") private String beginTimeStr; @Excel(name = "结束时间*") @Pattern(regexp = DATE_REGEXP, message = "[工作经历][结束时间]时间格式错误") private String finishTimeStr; @Excel(name = "职位名称*") private String jobTitle; @Excel(name = "所属部门*") private String department; @Excel(name = "工作内容*") private String description; } // 教育经历 @Data public class EducationInputEntity { @Excel(name = "学校*") private String schoolName; @Excel(name = "学历*", replace = {"初中及以下_1", "中专_2", "高中_3", "大专_4", "本科_5", "硕士_6", "博士_7"}) @Pattern(regexp = "[1234567]", message = "学历信息错误") private String recordStr; @Excel(name = "开始年份*") @Pattern(regexp = DATE_REGEXP, message = "[教育经历][开始年份]时间格式错误") private String beginTimeStr; @Excel(name = "毕业年份*") @Pattern(regexp = DATE_REGEXP, message = "[教育经历][毕业年份]时间格式错误") private String finishTimeStr; @Excel(name = "专业*") private String profession; } }
二、导入值自定义校验之重复值校验
上文所作的校验只是一些基本的校验,可能会有诸如Excel中重复行校验,Excel中数据与数据库重复校验等等。这种校验就无法通过 Hibernate Validator 来完成,只能写代码来实现校验逻辑了。
首先从简单的Excel数据与数据库值重复校验开始。为了便于演示,就不引入数据库了,直接Mock一些数据用来判断是否重复。
@Service public class MockTalentDataService { private static List<TalentUser> talentUsers = new ArrayList<>(); static { TalentUser u1 = new TalentUser(1L, "凌风", "18311342567"); TalentUser u2 = new TalentUser(2L, "张三", "18512343567"); TalentUser u3 = new TalentUser(3L, "李四", "18902343267"); talentUsers.add(u1); talentUsers.add(u2); talentUsers.add(u3); } /** * 校验是否重复 */ public boolean checkForDuplicates(String name, String phone) { // 姓名与手机号相等个数不等于0则为重复 return talentUsers.stream().anyMatch(e -> e.getName().equals(name) && e.getPhone().equals(phone)); } }
其中Mock数据中 ID 为 1 的数据与示例Excel2 中的数据是重复的。
EasyPOI 提供了校验的接口,这需要我们自己写一个用于校验的类。在这个类中,可以对导入时的每一行数据进行校验,框架通过ExcelVerifyHandlerResult
对象来判断是否校验通过,校验不通过需要传递ErrorMsg
。@Component public class TalentImportVerifyHandler implements IExcelVerifyHandler<TalentUserInputEntity> { @Resource private MockTalentDataService mockTalentDataService; @Override public ExcelVerifyHandlerResult verifyHandler(TalentUserInputEntity inputEntity) { StringJoiner joiner = new StringJoiner(","); // 根据姓名与手机号判断数据是否重复 String name = inputEntity.getName(); String phone = inputEntity.getPhone(); // mock 数据库 boolean duplicates = mockTalentDataService.checkForDuplicates(name, phone); if (duplicates) { joiner.add("数据与数据库数据重复"); } if (joiner.length() != 0) { return new ExcelVerifyHandlerResult(false, joiner.toString()); } return new ExcelVerifyHandlerResult(true); } }
修改校验处代码,设置校验类对象。
@Resource private TalentImportVerifyHandler talentImportVerifyHandler; @PostMapping("/upload") public Boolean upload(@RequestParam("file") MultipartFile multipartFile) throws Exception { ImportParams params = new ImportParams(); // 表头设置为2行 params.setHeadRows(2); // 标题行设置为0行,默认是0,可以不设置 params.setTitleRows(0); // 开启Excel校验 params.setNeedVerfiy(true); params.setVerifyHandler(talentImportVerifyHandler); ExcelImportResult<TalentUserInputEntity> result = ExcelImportUtil.importExcelMore(multipartFile.getInputStream(), TalentUserInputEntity.class, params); System.out.println("是否校验失败: " + result.isVerfiyFail()); System.out.println("校验失败的集合:" + JSONObject.toJSONString(result.getFailList())); System.out.println("校验通过的集合:" + JSONObject.toJSONString(result.getList())); for (TalentUserInputEntity entity : result.getFailList()) { int line = entity.getRowNum() + 1; String msg = "第" + line + "行的错误是:" + entity.getErrorMsg(); System.out.println(msg); } return true; }
上传 示例Excel2 文件测试,结果输出:
而第七行的数据正是与Mock中的数据相重复的。
三、导入值自定义校验之Collection对象校验
上文中还有一个待解决的问题,就是Collection中的对象添加了Hibernate Validator 注解校验但是并未生效的问题,现在就来解决一下。上一步中实现了导入对象的校验类,校验类会校验Excel中的每一条数据, 那我是不是可以直接在校验类中校验Collection中对象了呢?实践证明行不通,因为这个校验类的verifyHandler方法只会被调用一次,所以Collection中只有一条记录。既然这里行不通的话,就只能对导入结果再进行校验了。
因为Collection中的数据EasyPOI校验不到,所以有问题的数据也可能会被框架放到result.getList()中而不是result.getFailList() 中,为了校验需要将两个集合合并为一个集合,使用 EasyPOI 自带的工具类 PoiValidationUtil 进行校验 Collection 中的对象。
@Resource private TalentImportVerifyHandler talentImportVerifyHandler; @PostMapping("/upload") public Boolean upload(@RequestParam("file") MultipartFile multipartFile) throws Exception { ImportParams params = new ImportParams(); // 表头设置为2行 params.setHeadRows(2); // 标题行设置为0行,默认是0,可以不设置 params.setTitleRows(0); // 开启Excel校验 params.setNeedVerfiy(true); params.setVerifyHandler(talentImportVerifyHandler); ExcelImportResult<TalentUserInputEntity> result = ExcelImportUtil.importExcelMore(multipartFile.getInputStream(), TalentUserInputEntity.class, params); System.out.println("是否校验失败: " + result.isVerfiyFail()); System.out.println("校验失败的集合:" + JSONObject.toJSONString(result.getFailList())); System.out.println("校验通过的集合:" + JSONObject.toJSONString(result.getList())); // 合并结果集 List<TalentUserInputEntity> resultList = new ArrayList<>(); resultList.addAll(result.getFailList()); resultList.addAll(result.getList()); for (TalentUserInputEntity inputEntity : resultList) { StringJoiner joiner = new StringJoiner(","); joiner.add(inputEntity.getErrorMsg()); // 校验Collection的元素 inputEntity.getExperienceList().forEach(e -> verify(joiner, e)); inputEntity.getEducationList().forEach(e -> verify(joiner, e)); inputEntity.getAwardList().forEach(e -> verify(joiner, e)); inputEntity.getPunishmentList().forEach(e -> verify(joiner, e)); inputEntity.setErrorMsg(joiner.toString()); } for (TalentUserInputEntity entity : result.getFailList()) { int line = entity.getRowNum() + 1; String msg = "第" + line + "行的错误是:" + entity.getErrorMsg(); System.out.println(msg); } return true; } private void verify(StringJoiner joiner, Object object) { String validationMsg = PoiValidationUtil.validation(object, null); if (StringUtils.isNotEmpty(validationMsg)) { joiner.add(validationMsg); } }
上传 示例Excel2 ,结果如下:
四、导入值自定义校验之Excel重复行校验
上文中对Excel中数据与数据库数据进行重复校验,可有些需求是要求数据库在入库前需要对Excel的的重复行进行校验。这需要在校验类中完成,但校验类中并没有全部行的数据,该如何实现呢?博主的做法是将导入的数据放到 ThreadLocal 中进行暂存,从而达到在校验类中校验Excel重复行的目的。ThreadLocal使用注意完之后一定要及时清理!
首先定义什么叫重复行,完全相同的两行是重复行,本文中设定name 与 phone 相同的行为重复行,由于只需要比较这两个字段,所以我们需要重写导入对象的equals与hashCode方法。
@Data public class TalentUserInputEntity implements IExcelDataModel, IExcelModel { // 时间格式校验正则 public static final String DATE_REGEXP = "(Mon|Tue|Wed|Thu|Fri|Sat|Sun)( )(Dec|Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov)( )\\d{2}( )(00:00:00)( )(CST)( )\\d{4}"; /** * 行号 */ private int rowNum; /** * 错误消息 */ private String errorMsg; @Excel(name = "姓名*") @NotBlank(message = "[姓名]不能为空") private String name; @Excel(name = "性别*", replace = {"男_0", "女_1"}) @Pattern(regexp = "[01]", message = "性别错误") private String genderStr; @Excel(name = "手机号*") @Pattern(regexp = "[0-9]{11}", message = "手机号不正确") private String phone; @Excel(name = "开始工作时间*") @Pattern(regexp = DATE_REGEXP, message = "[开始工作时间]时间格式错误") private String workTimeStr; @Excel(name = "民族*") @NotBlank(message = "[民族]不能为空") private String national; @Excel(name = "语言水平*") @NotBlank(message = "[语言水平]不能为空") private String languageProficiency; @Excel(name = "出生日期*") @Pattern(regexp = DATE_REGEXP, message = "[出生日期]时间格式错误") private String birthStr; @Excel(name = "职位*") @NotBlank(message = "[职位]不能为空") private String jobsName; @Excel(name = "职位类型*") @NotBlank(message = "[职位类型]不能为空") private String categoryName; @Excel(name = "薪资*", replace = {"3K以下_1", "3K-5K_2", "5K-10K_3", "10K-20K_4", "20K-50K_5", "50K以上_6"}) @Pattern(regexp = "[123456]", message = "薪资信息错误") private String salaryStr; @Excel(name = "工作地点*") @NotBlank(message = "[工作地点]不能为空") private String workArea; @ExcelCollection(name = "工作经历*") private List<ExperienceInputEntity> experienceList; @ExcelCollection(name = "教育经历*") private List<EducationInputEntity> educationList; @ExcelCollection(name = "获奖情况") private List<AwardsInputEntity> awardList; @ExcelCollection(name = "技能证书") private List<PunishmentInputEntity> punishmentList; @Excel(name = "特长") private String specialty; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TalentUserInputEntity that = (TalentUserInputEntity) o; return Objects.equals(name, that.name) && Objects.equals(phone, that.phone); } @Override public int hashCode() { return Objects.hash(name, phone); } @Override public String getErrorMsg() { return errorMsg; } @Override public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } @Override public Integer getRowNum() { return rowNum; } @Override public void setRowNum(Integer rowNum) { this.rowNum = rowNum; } }
修改校验类代码,实现重复行的校验逻辑
@Component public class TalentImportVerifyHandler implements IExcelVerifyHandler<TalentUserInputEntity> { private final ThreadLocal<List<TalentUserInputEntity>> threadLocal = new ThreadLocal<>(); @Resource private MockTalentDataService mockTalentDataService; @Override public ExcelVerifyHandlerResult verifyHandler(TalentUserInputEntity inputEntity) { StringJoiner joiner = new StringJoiner(","); // 根据姓名与手机号判断数据是否重复 String name = inputEntity.getName(); String phone = inputEntity.getPhone(); // mock 数据库 boolean duplicates = mockTalentDataService.checkForDuplicates(name, phone); if (duplicates) { joiner.add("数据与数据库数据重复"); } List<TalentUserInputEntity> threadLocalVal = threadLocal.get(); if (threadLocalVal == null) { threadLocalVal = new ArrayList<>(); } threadLocalVal.forEach(e -> { if (e.equals(inputEntity)) { int lineNumber = e.getRowNum() + 1; joiner.add("数据与第" + lineNumber + "行重复"); } }); // 添加本行数据对象到ThreadLocal中 threadLocalVal.add(inputEntity); threadLocal.set(threadLocalVal); if (joiner.length() != 0) { return new ExcelVerifyHandlerResult(false, joiner.toString()); } return new ExcelVerifyHandlerResult(true); } public ThreadLocal<List<TalentUserInputEntity>> getThreadLocal() { return threadLocal; } }
由于校验类中使用了ThreadLocal,因此需要及时释放,修改导入处的代码。
@Resource private TalentImportVerifyHandler talentImportVerifyHandler; @PostMapping("/upload") public Boolean upload(@RequestParam("file") MultipartFile multipartFile) throws Exception { ExcelImportResult<TalentUserInputEntity> result; try { ImportParams params = new ImportParams(); // 表头设置为2行 params.setHeadRows(2); // 标题行设置为0行,默认是0,可以不设置 params.setTitleRows(0); // 开启Excel校验 params.setNeedVerfiy(true); params.setVerifyHandler(talentImportVerifyHandler); result = ExcelImportUtil.importExcelMore(multipartFile.getInputStream(), TalentUserInputEntity.class, params); } finally { // 清除threadLocal 防止内存泄漏 ThreadLocal<List<TalentUserInputEntity>> threadLocal = talentImportVerifyHandler.getThreadLocal(); if (threadLocal != null) { threadLocal.remove(); } } System.out.println("是否校验失败: " + result.isVerfiyFail()); System.out.println("校验失败的集合:" + JSONObject.toJSONString(result.getFailList())); System.out.println("校验通过的集合:" + JSONObject.toJSONString(result.getList())); // 合并结果集 List<TalentUserInputEntity> resultList = new ArrayList<>(); resultList.addAll(result.getFailList()); resultList.addAll(result.getList()); for (TalentUserInputEntity inputEntity : resultList) { StringJoiner joiner = new StringJoiner(","); joiner.add(inputEntity.getErrorMsg()); // 校验Collection的元素 inputEntity.getExperienceList().forEach(e -> verify(joiner, e)); inputEntity.getEducationList().forEach(e -> verify(joiner, e)); inputEntity.getAwardList().forEach(e -> verify(joiner, e)); inputEntity.getPunishmentList().forEach(e -> verify(joiner, e)); inputEntity.setErrorMsg(joiner.toString()); } for (TalentUserInputEntity entity : result.getFailList()) { int line = entity.getRowNum() + 1; String msg = "第" + line + "行的错误是:" + entity.getErrorMsg(); System.out.println(msg); } return true; } private void verify(StringJoiner joiner, Object object) { String validationMsg = PoiValidationUtil.validation(object, null); if (StringUtils.isNotEmpty(validationMsg)) { joiner.add(validationMsg); } }
导入示例Excel2,结果如下:
五、案例
实体类
CourseEntity.java
package com.mye.hl11easypoi.api.pojo; import cn.afterturn.easypoi.excel.annotation.Excel; import cn.afterturn.easypoi.excel.annotation.ExcelCollection; import cn.afterturn.easypoi.excel.annotation.ExcelEntity; import cn.afterturn.easypoi.excel.annotation.ExcelTarget; import cn.afterturn.easypoi.handler.inter.IExcelDataModel; import cn.afterturn.easypoi.handler.inter.IExcelModel; import lombok.Data; import java.util.List; @Data @ExcelTarget("courseEntity") public class CourseEntity implements java.io.Serializable, IExcelModel, IExcelDataModel { /** * 主键 */ private String id; /** * 课程名称 * needMerge 是否需要纵向合并单元格(用于list创建的多个row) */ @Excel(name = "课程名称", orderNum = "0", width = 25, needMerge = true) private String name; /** * 老师主键 */ // @ExcelEntity(id = "major") private TeacherEntity chineseTeacher; /** * 老师主键 */ @ExcelEntity(id = "absent") private TeacherEntity mathTeacher; @ExcelCollection(name = "学生", orderNum = "3") private List<StudentEntity> students; private String errorMsg; //自定义一个errorMsg接受下面重写IExcelModel接口的get和setErrorMsg方法。 private Integer rowNum; //自定义一个rowNum接受下面重写IExcelModel接口的get和setRowNum方法。 @Override public String getErrorMsg() { return errorMsg; } @Override public void setErrorMsg(String errorMsg) { this.errorMsg = errorMsg; } @Override public Integer getRowNum() { return rowNum; } @Override public void setRowNum(Integer rowNum) { this.rowNum = rowNum; } }
StudentEntity.java
package com.mye.hl11easypoi.api.pojo; import cn.afterturn.easypoi.excel.annotation.Excel; import lombok.Data; import java.util.Date; @Data public class StudentEntity implements java.io.Serializable { /** * id */ private String id; /** * 学生姓名 */ @Excel(name = "学生姓名", height = 20, width = 30, isImportField = "true") private String name; /** * 学生性别 */ @Excel(name = "学生性别", replace = {"男_1", "女_2"}, suffix = "生", isImportField = "true") private int sex; @Excel(name = "出生日期", exportFormat = "yyyyMMddHHmmss", format = "yyyy-MM-dd", isImportField = "true", width = 20) private Date birthday; @Excel(name = "进校日期", exportFormat = "yyyyMMddHHmmss", format = "yyyy-MM-dd") private Date registrationDate; }
TeacherEntity.java
package com.mye.hl11easypoi.api.pojo; import cn.afterturn.easypoi.excel.annotation.Excel; import lombok.Data; @Data public class TeacherEntity { /** * 教师名称 * isImportField 导入Excel时,对Excel中的字段进行校验,如果没有该字段,导入失败 */ @Excel(name = "教师姓名", width = 30, orderNum = "1" ,isImportField = "true") private String name; /** * 教师性别 * replace 值的替换,`replace = {"男_1", "女_2"} `将值为1的替换为男 * suffix 文字后缀 */ @Excel(name = "教师性别", replace = {"男_1", "女_2"}, suffix = "生", isImportField = "true",orderNum = "2") private int sex; }
自定义校验类
package com.mye.hl11easypoi.api.verifyHandler; import cn.afterturn.easypoi.excel.entity.result.ExcelVerifyHandlerResult; import cn.afterturn.easypoi.handler.inter.IExcelVerifyHandler; import com.mye.hl11easypoi.api.pojo.CourseEntity; public class MyVerifyHandler implements IExcelVerifyHandler<CourseEntity> { @Override public ExcelVerifyHandlerResult verifyHandler(CourseEntity courseEntity) { ExcelVerifyHandlerResult result = new ExcelVerifyHandlerResult(); //假设我们要添加用户, //现在去数据库查询getName,如果存在则表示校验不通过。 //假设现在数据库中有个getName 测试课程 if ("测试课程".equals(courseEntity.getName())) { result.setMsg("该课程已存在"); result.setSuccess(false); return result; } result.setSuccess(true); return result; } }
测试类
package com.mye.hl11easypoi; import cn.afterturn.easypoi.excel.ExcelExportUtil; import cn.afterturn.easypoi.excel.entity.ExportParams; import cn.afterturn.easypoi.excel.entity.ImportParams; import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult; import cn.afterturn.easypoi.excel.imports.ExcelImportService; import cn.hutool.json.JSONUtil; import com.mye.hl11easypoi.api.pojo.*; import com.mye.hl11easypoi.api.verifyHandler.MyVerifyHandler; import org.apache.poi.ss.usermodel.Workbook; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.util.*; @SpringBootTest(classes = Hl11EasypoiApplication.class) @RunWith(SpringRunner.class) public class TestPOI { @Test public void testExportExcel() throws Exception { List<CourseEntity> courseEntityList = new ArrayList<>(); CourseEntity courseEntity = new CourseEntity(); courseEntity.setId("1"); courseEntity.setName("测试课程"); // 第二个 CourseEntity courseEntity1 = new CourseEntity(); courseEntity1.setId("2"); courseEntity1.setName("数学"); TeacherEntity teacherEntity1 = new TeacherEntity(); teacherEntity1.setSex(1); teacherEntity1.setName("李老师"); TeacherEntity teacherEntity = new TeacherEntity(); teacherEntity.setName("张老师"); teacherEntity.setSex(1); courseEntity.setMathTeacher(teacherEntity); courseEntity1.setMathTeacher(teacherEntity1); List<StudentEntity> studentEntities = new ArrayList<>(); for (int i = 1; i <= 2; i++) { StudentEntity studentEntity = new StudentEntity(); studentEntity.setName("学生" + i); studentEntity.setSex(i); studentEntity.setBirthday(new Date()); studentEntities.add(studentEntity); } courseEntity.setStudents(studentEntities); courseEntity1.setStudents(studentEntities); courseEntityList.add(courseEntity); courseEntityList.add(courseEntity1); System.out.println(courseEntityList+"11111111111111"); Date start = new Date(); Workbook workbook = ExcelExportUtil.exportExcel( new ExportParams("导出测试", null, "测试"), CourseEntity.class, courseEntityList); System.out.println(new Date().getTime() - start.getTime()); File savefile = new File("E:/desktop/excel/"); if (!savefile.exists()) { savefile.mkdirs(); } FileOutputStream fos = new FileOutputStream("E:/desktop/excel/教师课程学生导出测试.xls"); workbook.write(fos); fos.close(); } @Test public void testImport2() throws Exception { // 参数1:导入excel文件流 参数2:导入类型 参数3:导入的配置对象 ImportParams importParams = new ImportParams(); importParams.setTitleRows(1); // 设置标题列占几行 importParams.setHeadRows(2); // 设置字段名称占几行 即header importParams.setNeedVerify(true);//开启校验 importParams.setVerifyHandler(new MyVerifyHandler()); importParams.setStartSheetIndex(0); // 设置从第几张表格开始读取,这里0代表第一张表,默认从第一张表读取 BufferedInputStream bis = new BufferedInputStream(new FileInputStream(new File("E:/desktop/excel/教师课程学生导出测试.xls"))); ExcelImportResult result = new ExcelImportService().importExcelByIs(bis, CourseEntity.class, importParams, true); //这个是正确导入的 List<CourseEntity> list = result.getList(); System.out.println("成功导入的集合:"+JSONUtil.toJsonStr(list)); List<CourseEntity> failList = result.getFailList(); System.out.println("失败导入的集合"+JSONUtil.toJsonStr(failList)); for (CourseEntity courseEntity : failList) { int line = courseEntity.getRowNum(); String msg = "第" + line + "行的错误是:" + courseEntity.getErrorMsg(); System.out.println(msg); } //将错误excel信息返回给客户端 ExportParams exportParams = new ExportParams(); Workbook workbook = ExcelExportUtil.exportExcel(exportParams, CourseEntity.class, failList); // HttpServletResponse response = null; // response.setHeader("content-Type", "application/vnd.ms-excel"); // response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode("用户数据表","UTF-8") + ".xls"); // response.setCharacterEncoding("UTF-8"); // workbook.write(response.getOutputStream()); FileOutputStream fos = new FileOutputStream("E:/desktop/excel/用户数据表.xls"); workbook.write(fos); fos.close(); } }
导出结果
导入结果
-
JavaScript数据简单校验设计
2021-12-05 16:51:07** JavaScript数据简单校验设计-HTML简单获取另一个HTML输入框的内容以及地区的选择获取 资源获取链接: https://download.csdn.net/download/Tian208/56339522 ** 一、目的 综合使用HTML、JavaScript和CSS进行注册...**
JavaScript数据简单校验设计-HTML简单获取另一个HTML输入框的内容以及地区的选择获取
资源获取链接:
https://download.csdn.net/download/Tian208/56339522**
一、目的
综合使用HTML、JavaScript和CSS进行注册页面设计,具体要求如下:
1)注意整个页面的色调和美观
2)使用Frameset+Table布局(div也可)
3)对用户ID和用户名、口令不符合条件及时判断
4)对口令不一致进行及时判断(34的及时判断,要求提示信息必须显示在同一个页面,也就是说显示在当前的行的后面或者上面或者下面)
5)判断Email地址是否合法
6)在“提交”后能在新页面显示所有的输入信息
程序效果:
二、过程
源码模块:
1gerenxinxi.css
.ziti{ font-family:黑体; font-size: 25px; width: 300; height: 30px; text-align: center; border: 3; background-color: #ffffff; line-height: 28px; border-top-left-radius: 5px; border-bottom-left-radius: 5px; } .quanju{ width: 300px; height: 600px; padding: 20px; position: absolute; left: 50%; top: 50%; margin-left: -200px; margin-top: -280px; } .quanju1{ text-align: center; } .text_field { width: 180px; height: 28px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; background-color: #ffffff; } #all{ width: 100%; height: 20px; } form p > * { display: inline-block; vertical-align:middle; }
2denlu.js
.ziti{ font-family:黑体; font-size: 25px; width: 300; height: 30px; text-align: center; border: 3; background-color: #ffffff; line-height: 28px; border-top-left-radius: 5px; border-bottom-left-radius: 5px; } .quanju{ width: 300px; height: 600px; padding: 20px; position: absolute; left: 50%; top: 50%; margin-left: -200px; margin-top: -280px; } .quanju1{ text-align: center; } .text_field { width: 180px; height: 28px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; background-color: #ffffff; } #all{ width: 100%; height: 20px; } form p > * { display: inline-block; vertical-align:middle; }
Web-实验2-hjt08.html(首页HTML设计)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>web-实验二</title> </head> <body background="Picture\zuomian1.jpg" style=" background-repeat:no-repeat ; background-size:100% 100%; background-attachment: fixed;"> <style type="text/css"> .mytable{ width:100%; height:100%; margin:0 auto; } .left{ width:1180px; height:550px; margin:0 auto; } .right{ width:600px; height:550px; margin:0 auto; } </style> <table class="mytable"> <tr> <td colspan="3" style="background-color:#600000;font-size:15px;height:40px;text-align:center;color:aliceblue"> <h1>用户注册</h1> </td> </tr> <tr> <td colspan="3" style="font-size:7px;text-align:left" background="Picture\zuomian1.jpg"> <h1>用户注册界面,请按要求操作</h1> </td> </tr> <tr> <td class="left"> <iframe src="用户注册信息.html" name="iframe_a" class="mytable"></iframe> </td> <td style="background-color:#600000;font-size:25px;height:480px;width:50px;vertical-align:top"></td> <td class="right"> <iframe src="shiping.html" name="iframe_b" class="mytable"></iframe> </table> </body> </html>
用户注册信息.HTMl
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <meta name="Generator" content="EditPlus®"> <meta name="Author" content=""> <meta name="Keywords" content=""> <meta name="Description" content=""> <title>web-实验二</title> </head> <script language="javascript" src="js/denlu.js" type="text/javascript" charset="utf-8"></script> <body background="Picture\zuomian1.jpg" style=" background-repeat:no-repeat ; background-size:100% 100%; background-attachment: fixed;" onload='getProvince()'> <style type="text/css"> .mytable{ width:100%; height:100%; margin:0 auto; font-weight: 200; } .mytable1{ font-weight:1000; width:100%; height:100%; margin:0 auto; text-align:center; background-color:#ffffff; } .left{ width:1180px; height:520px; margin:0 auto; } .right{ width:600px; height:520px; margin:0 auto; } .hang{ background-color:#600000; font-size:25px; width:50px; text-align:center; } .shuju{ height:20px; font-size:20px; } </style> <div> <form action="test.html" method="get"> <table class="mytable" border="3"cellpadding="6" cellspacing="6"> <tr> <td colspan="1" style="background-color:#7B7B7B;font-size:10px;height:10px;text-align:center;color:aliceblue"> <h1>注册界面</h1> </td> </tr> <tr class="mytable1" > <td valign="middle" >用 户 ID: <input type="text" placeholder="请输入你的用户ID:8-16位" pattern="\w{8,16}" id="userId"; name="userId" class="shuju"/></td> <span id="s_userId" class="error"></span> <tr class="mytable1" > <td valign="middle">用 户 名: <input type="text" placeholder="请输入你的姓名" id="name" pattern="\w{0,16}" name="name" class="shuju"/></td> <span id="s_name" class="error"></span> <tr class="mytable1"> <tr> <td valign="middle" class="mytable1" id="xingbie">性别: <input type="radio" name="xingbie" value="男">男 <input type="radio" name="xingbie" value="女">女 </td> </tr> <tr class="mytable1" > <td valign="middle">密 码: <input type="text" placeholder="请输入你的密码:8-16位" pattern="\w{8,16}" class="shuju" id="password" name="password"></td> <span id="s_password" class="error"></span> <tr> <td valign="middle" class="mytable1" id="xueli">学历: <input type="radio" name="xueli" value="专科">专科 <input type="radio" name="xueli" value="本科">本科 <input type="radio" name="xueli" value="硕士">硕士 <input type="radio" name="xueli" value="研究生">研究生 <input type="radio" name="xueli" value="博士">博士 </td> </tr> <tr class="mytable1" > <td valign="middle">生 日: <input type="date" placeholder="请输入你的生日:xxxx-xx-xx" id="birthday" name="birthday" class="shuju"/></td> <tr class="mytable1"> <td valign="middle"><label for="email">E-mail:</label> <input type="email" name="email" id="email" placeholder="请输入邮箱" class="shuju"> <span id="s_email" class="error"></span> </td> <tr class="mytable1"> <td>地区:</td> <tr class="mytable1"><td> <select id="province" onchange="chooseProvince(this)"> <option value="1">请选择省</option> </select> <select id="city" onchange="chooseCity(this)"> <option value="2">请选择市</option> </select> <select id="area"> <option value="3">请选择区</option> </select> </td> </tr> <tr class="mytable1" > <td valign="middle">地 址: <input type="text" placeholder="请输入你的地址" id="address" name="address" class="shuju"/></td> <tr class="mytable1" > <td valign="middle">手机号码: <input type="text" placeholder="请输入你的手机号码:11位" pattern="\w{11}" id="Tel" name="Tel" class="shuju"/></td> <span id="s_Tel" class="error"></span> <tr class="mytable1"> <td id="td_reset"><input type="reset" id="btn_reset" value="重置" > <input type="button" id="btn_sub1" value="确认信息" onclick="page()"> <input type="submit" id="btn_sub" value="提交" onclick="page()"> </td> </table> </form> </div> </body> </html>
information.html(在“提交”后能在新页面显示所有的输入信息)
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>个人资料</title> <link rel="stylesheet" href="css/gerenxinxi.css"> </head> <script language="javascript" src="js/denlu.js" type="text/javascript" charset="utf-8"></script> <body> <style type="text/css"> </style> <div id="all"> <div class="quanju" align="center"> <form> <p><label class="ziti">用户ID:</label><input type="text" id="userId" class="text_field"/></p> <p><label class="ziti">用户名:</label><input type="text" id="name" class="text_field"/></p> <p><label class="ziti">性别: .</label><input type="text" id="xingbie" class="text_field"/></p> <p><label class="ziti">密码: .</label><input type="text" id="password" class="text_field"/></p> <p><label class="ziti">生日: .</label><input type="text" id="birthday" class="text_field"/></p> <p><label class="ziti">学历: .</label><input type="text" id="xueli" class="text_field"/></p> <p><label class="ziti">地区: .</label><input type="text" id="area1" class="text_field"/></p> <p><label class="ziti">E-mail: </label><input type="text" id="email" class="text_field"/></p> <p><label class="ziti">地址: .</label><input type="text" id="address" class="text_field"/></p> <p><label class="ziti">手机号: </label><input type="text" id="Tel" class="text_field"/></p> <div class="quanju1"> <a><input valign="middle" type="button" value="返回" onClick="onClick1()"></a><br> </div> </form> </div> </div> <table> <tr> <td> </td> </tr> </table> <script type="text/javascript"> document.getElementById("userId").value =window.localStorage.getItem("userId"); document.getElementById("name").value =window.localStorage.getItem("name"); document.getElementById("password").value=window.localStorage.getItem("password"); document.getElementById("birthday").value=window.localStorage.getItem("birthday"); document.getElementById("xueli").value =window.localStorage.getItem("xueli"); document.getElementById("xingbie").value =window.localStorage.getItem("xingbie"); document.getElementById("area1").value =window.localStorage.getItem("area1"); document.getElementById("email").value =window.localStorage.getItem("email"); document.getElementById("address").value =window.localStorage.getItem("address"); document.getElementById("Tel").value =window.localStorage.getItem("Tel"); </script> </body> </html>
提交成功页面设计test.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <script language="javascript" src="js/denlu.js" type="text/javascript" charset="utf-8"></script> <style> body{text-align:center} </style> <script type="text/javascript"> function onClick(){ window.location.href="用户注册信息.html"; } </script> <body> <form> <table> <tr> <br><br><br><br> <td valign="middle"><input type="button" id=in value="已提交" onclick="onClick()" style="background-color:#7B7B7B;font-size:35px;width:400px;height:80px;text-align:center;color:aliceblue"> </td> </tr> <tr> <td> <input type="button" id=in value="返回" onclick="onClick()" style="background-color:#7B7B7B;font-size:35px;width:400px;height:80px;text-align:center;color:aliceblue"> </td> </table> </form> </body> </html>
查看个人信息按钮设计shiping.html
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <script language="javascript" src="js/denlu.js" type="text/javascript" charset="utf-8"></script> <style> body{text-align:center} </style> <script type="text/javascript"> function onClick(){ window.location.href="用户注册信息.html"; } </script> <body> <form> <table> <tr> <br><br><br><br> <td valign="middle"><input type="button" id=in value="已提交" onclick="onClick()" style="background-color:#7B7B7B;font-size:35px;width:400px;height:80px;text-align:center;color:aliceblue"> </td> </tr> <tr> <td> <input type="button" id=in value="返回" onclick="onClick()" style="background-color:#7B7B7B;font-size:35px;width:400px;height:80px;text-align:center;color:aliceblue"> </td> </table> </form> </body> </html>
三、实验总结
此文章用来当做学习实验笔记,许多知识未知,不够好的地方可多多指教,如果需要,可以随便使用,谢谢大家! -
SpringBoot整合Hibernate-Validator校验器
2021-05-15 20:30:18SpringBoot整合Hibernate-Validator校验器 使用内置校验器 1.1 引入依赖 1.2 给字段加上相关注解 1.3 给方法参数加上@Validated注解 1.4 捕获MethodArgumentNotValidException异常信息 1.5 使用ApiPos调试接口 使用...SpringBoot整合Hibernate-Validator校验器
- 使用内置校验器
1.1 引入依赖
1.2 给字段加上相关注解
1.3 给方法参数加上@Validated注解
1.4 捕获MethodArgumentNotValidException异常信息
1.5 使用ApiPos调试接口 - 使用自定义校验器
2.1 自定义注解类
2.2 自定义校验业务逻辑类 - Validator校验的常用注解
1使用内置校验器
1.1 引入依赖
新版本的SpringBoot需要手动引入,老版本只需引入spring-boot-starter-web即可,里面集成了Hibernate-Validator,这里讲述新版本的SpringBoot,以2.4.1为例
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
1.2 给字段加上相关注解
首先创建一个Student实体类
@Data public class Student implements Serializable { private String name; private Integer age; }
然后给字段加上Hibernate-Validator校验器内置的注解
@Data public class Student implements Serializable { @NotEmpty(message = "姓名不能空") private String name; @NotNull(message = "年龄不能为空") @Range(min = 0, max = 200, message = "年龄不合法") private Integer age; }
解释:message代表提示信息
注解 作用类型 说明 @NotEmpty 字符串 被注释的字符串必须非空 @NotNull 字符串 被注释的字符串必须不为null @Range 数值类型、字符串、字节等 被注释的元素大小必须在指定的范围内,min代表最小,max代表最大 1.3 给方法参数加上@Validated注解
首先创建一个控制器类,随便写一个方法,只要参数为Student类型的即可,不要忘记加@RequestBody 注解
@GetMapping("/test") public Student test3(@Validated @RequestBody Student student) { System.out.println(student); return student; }
1.4 捕获MethodArgumentNotValidException异常信息
创建一个全局异常处理类,用于捕获抛出的异常,这里主要是通过Stream的API获取到注解中message属性的值
@RestControllerAdvice public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public ResponseEntity<String> handle(MethodArgumentNotValidException e) { List<ObjectError> allErrors = e.getBindingResult().getAllErrors(); ObjectError objectError = allErrors.stream().findFirst().get(); // 获取message的值 return new ResponseEntity<>(objectError.getDefaultMessage(), HttpStatus.BAD_REQUEST); } }
1.5 使用ApiPos调试接口
参数合法的结果
控制台输出Student(name=pcdd, age=21)
姓名为空的结果
姓名为空串的结果
年龄为-1时的结果
2 使用自定义校验器
Hibernate-Validator校验器的功能可以满足大多数的需求,但如果需要实现一些其他的验证功能,则可以根据规则进行自定义。
2.1 使用自定义注解
如果要自定义验证功能,则需要先自定义注解,以便在实体Bean中使用它。
先给Student实体类新增一个字段education表示学历,定义一个注解@CustomConstraint 对education字段进行校验,规定值必须是专科、本科 、研究生中的一项@Data public class Student implements Serializable { @NotEmpty(message = "姓名不能空") private String name; @NotNull(message = "年龄不能为空") @Range(min = 0, max = 200, message = "年龄不合法") private Integer age; @NotNull(message = "学历不能为空") @CustomConstraint private String education; }
自定义注解@CustomConstraint
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Constraint(validatedBy = CustomConstraintValidator.class) public @interface CustomConstraint { String message() default "学历必须是专科、本科、研究生中的一项"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
2.2 自定义业务校验逻辑类
创建一个类,实现ConstraintValidator<A,T>接口,重写两个方法:initialize和isValid,分别表示初始化验证消息的方法和执行验证的方法。
public class CustomConstraintValidator implements ConstraintValidator<CustomConstraint, String> { @Override public void initialize(CustomConstraint constraintAnnotation) { System.out.println("自定义验证类启动"); } @Override public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) { return "专科".equals(s) || "本科".equals(s) || "研究生".equals(s); } }
ConstraintValidator<A,T>是一个泛型接口,A表示之前我们自定义的注解,T表示被这个注解注释的字段的类型,这里指String(学历用String类型表示)
输入一个合法的值,观察结果
输入一个非法的值,比如硕士,观察结果
3 Validator校验的常用注解
注解 作用类型 说明 @NotBlank(message =) 字符串 验证字符串非null,且长度必须大于0 @Email 字符串 被注释的元素必须是电子邮箱地址 @Length(min=,max=) 字符串 被注释的字符串的大小必须在指定的范围内,min 代表最小,max代表最大 @NotEmpty 字符串 被注释的字符串必须非空 @NotEmptyPattern 字符串 在字符串不为空的情况下,是否匹配正则表达式 @DateValidator 字符串 验证日期格式是否满足正则表达式,Local为英语 @DateFormatCheckPattern 字符串 验证日期格式是否满足正则表达式,Local是自己手动指定的 @Range(min=,max=,message=) 字符串、数值类型、字节等 被注释的元素必须在合适的范围内 @NotNull 任意 被注释的元素必须为null @AssertTrue 布尔值 被注释的元素必须为true @AssertFalse 布尔值 被注释的元素必须为false @Min(value) 数字 被注释的元素必须是一个数字,且大于或等于指定的最小值 @Max(value) 数字 被注释的元素必须是一个数字,且小于或等于指定的最大值 @DecimalMin(value) 数字 被注释的元素必须是一个数字,且大于或等于指定的最小值 @DecimalMax(value) 数字 被注释的元素必须是一个数字,且小于或等于指定的最大值 @Size(max=, min=) 数字 被注释的元素必须是一个数字,min代表最小,max代表最大 @Digits (integer, fraction) 数字 被注释的元素必须是一个数字,且在可接收的范围内 @Past 日期 被注释的元素必须是一个过去的日期 - 使用内置校验器
-
Python(八)校验两个excell表格值是否一致
2022-02-27 10:56:35xls(filename, xlsname) 2、check_recommend_export 校验导出数据与列表数据是否一致 import os import time from os import listdir from os.path import isfile, join from selenium import webdriver import ... -
EAN校验码的计算方法
2017-12-26 16:39:29末位为校验码 /** EAN码校验位的计算方法 从代码位置序号2开始,所有偶数位的数字代码求和为a。 将上步中的a乘以3为a。 从代码位置序号3开始,所有奇数位的数字代码求和为b。 将a和b相加为c。... -
jQuery的表单校验插件validator
2020-02-17 10:18:49何为插件:插件就是将jquery实现的常用操作进行封装,我们只需要学会插件的使用语法,就可以使用简单...在rules中通过校验规则名称使用校验规则 ,在messages中定义该规则对应的错误提示信息。 <!-- 需要引入的文... -
通过反射校验实体类中属性值是否符合要求
2020-08-01 17:35:23业务逻辑中通常对于保存或者导入的信息需要进行校验,这时候我们如果通过后台校验可能需要大量的ifelse去判断,那不如通过一个反射写一个通用的校验,请看代码--》 import org.apache.commons.lang3.ObjectUtils;... -
校友会小程序开发笔记十五: 小程序前端数据校验体系的设计与实现
2021-01-07 18:28:59一种是自己封装Validate插件进行表单验证,基于以上原因,小女子自己封装了前端数据校验规则一套,并且与云开发后端数据校验的写法和规则一致(云开发后端数据校验体系参见上一篇笔记:)) 校友录小程序集中校验... -
[爬虫]字节跳动招聘爬取实战-csrf校验
2021-01-07 14:56:19其中这个posts接口才有我们需要的json数据: 观察相应头发现一个重要参数csrf: 说明抖音的网站具备csrf校验的功能,后文将再介绍如何获取到这个csrf的token。 参看请求参数: 参数包装函数 为了正常爬取时的方便,... -
校验2validate校验
2017-11-24 13:13:51education : "请填写您的学历", major : "请填写您的专业", position : "请填写您意向职位", workAdd : "请填写您的意向工作地", phone : { required : "请填写您的手机号", number : "只能输入... -
[JQuery] - 用validate插件校验表单
2019-05-19 20:05:02四.validate表单校验常用规则 一.功能效果 二.部分特殊规则 2.1 错误信息位置更改 在表单某选项中增加代码 < label class = " error " for = " 表单中选项的name " > label > 例如 : 性别必选 ... -
ASP.NET EXCEL导入,身份证、手机号长度校验数据校验
2020-04-01 09:32:06} if (string.IsNullOrEmpty(dr["学历"].ToString())) { strErr.Append("第" + irowIndex + "行【学历】未填写!\r\n"); //continue; } else { curData.EducationalLevel = dr["学历"] == DBNull.Value ? (int)学历... -
vildForm表单校验
2018-06-22 10:22:31vildForm表单校验 一、 HTML部分 <!-- 页面结构 --> <div class="ue-container" id="sandbox-container"> <!-- 验证信息nowrap --> <... -
使用Servlet和Ajax完成登录注册的校验+Vue
2020-08-23 14:09:34一.Servlet登录注册校验 1.实现功能 实现功能: 1.登录有记住密码选项 2.使用Ajax输入用户名失去光标进行校验,不重复显示用户名可以使用,重复显示不可使用 3.注册时加入验证码 4.存入数据库中的密码经过MD5加密过... -
JQuery 表单校验
2016-03-08 20:46:00edu:"至少要选择一个学历", birthday:{ required:"出生日期不能为空", dateISO:"出生日期格式不正确" }, email:{ required:"email不能为空", email:"email地址的... -
jQuery formValidator表单校验插件ver2.9.1介绍和在线演示
2019-10-05 15:58:57jQuery formValidator表单校验插件插件目前提示错误,有两种模式:showword和showalert,即文字提示和窗口提示目前支持5种大的校验方式,分别是:InputValidator(针对input、textarea、select控件的字符长度、值范围... -
请写出用于校验HTML 文本框中输入的内容全部为数字 的javascript代码
2021-06-16 10:35:55取得经济学、管理科学与工程或土建类大学本科学历参加物业管理师资格考试的人要求从事物业管工作 文艺复兴是14—16世纪反映西欧各国正在形成中的资产阶级要求的思想、文化运动。其主要中心 神州二号”无人飞船环绕... -
SSM_EasyUI公司员工管理系统 | 毕业设计
2022-04-07 13:02:593 同时使用了了hibernate提供的校验框架,对客户端数据进行校验! 4 Mybati数据库DAO层采用的是Mapper代理开发方法,输入映射采用的是POJO包装类型实现,输出映射采用了resultMap类型,实现了数据库多对一映射。 5 ... -
网络工程师成为适合低学历人群的热门高薪职业
2020-03-26 16:49:54有网友评价说:网络工程师是现在最适合低学历人群的热门高薪职业。为什么会这样说呢?接下来让小编为你详细解读网络工程师。 网络工程师到底是做什么的? 网络工程师是通过学习和训练,掌握网络技术的理论知识和操作... -
SSM_EasyUI公司员工信息管理系统源码 SSMGSYGXXGLXT.rar
2021-09-18 19:40:373 同时使用了了hibernate提供的校验框架,对客户端数据进行校验! 4 Mybati数据库DAO层采用的是Mapper代理开发方法,输入映射采用的是POJO包装类型实现,输出映射采用了resultMap类型,实现了数据库多对一映射。 5 ... -
2017年自考计算机应用基础模拟试题1
2021-06-28 10:53:41如果采用的多项式为G(X)=X4+X+1,那么对于要传的信息串1101011011的CRC校验码是( )。 A.1011 B.1101 C.:1110 D.1100 7.Windows 中“资源管理器”中部的窗口分隔条 A.可以移动 B.不可以移动 C.自动移动 D.以上说法... -
谁说专科学历找不到Java工作?自学Java,第一份工作13k。
2021-11-25 13:21:29这是一个技术行业,最终能不能找到工作,找到什么样的工作主要还是看技术学的怎么样,学历,专业对口只是一个人的加分项,如果不是进大公司,只是选择一些中小公司的话,公司主要看重的还是这个人的实际 -
从开始无学历送货到系统集成工程师的历程
2021-06-18 15:42:24扯了半天,无学历、无人脉的技术宅到底该怎么做呢? 1,潜心研究,保持初心。 2,要自信,要坚持 3,多和同行交流。 当年也确实醉心在搞技术,很多东西到现在亦然是不懂,在我面试后后,原单位的另外一个同事也成功...