springmvc使用JSR-303进行校验

2023-11-05

下面提供一种springmvc的校验方案,一般没有校验或者手动写validator的话都要写好多代码好多if判断,使用JSR-303规范校验只需要在Pojo字段上加上相应的注解就可以实现校验了

1.依赖的jar包,我直接贴pom了

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
		<spring.version>4.1.1.RELEASE</spring.version>
	</properties>
	
	<dependencies>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-core</artifactId>
			<version>2.4.0</version>
		</dependency>
		<dependency>
			<groupId>com.fasterxml.jackson.core</groupId>
			<artifactId>jackson-databind</artifactId>
			<version>2.4.0</version>
		</dependency>
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3.1</version>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
		</dependency>
		<dependency>
			<groupId>javax.validation</groupId>
			<artifactId>validation-api</artifactId>
			<version>1.1.0.Final</version>
		</dependency>
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.1.3.Final</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>${spring.version}</version>
		</dependency>
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-log4j12</artifactId>
			<version>1.7.7</version>
		</dependency>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.11</version>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.4</version>
		</dependency>
		<dependency>
			<groupId>javax.el</groupId>
			<artifactId>javax.el-api</artifactId>
			<version>3.0.0</version>
		</dependency>
	</dependencies>
2.springmvc配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans 
		http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
		http://www.springframework.org/schema/tx 
		http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
		http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context-3.0.xsd
		http://www.springframework.org/schema/mvc
		http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
		http://www.springframework.org/schema/aop 
		http://www.springframework.org/schema/aop/spring-aop.xsd">

	<!-- 默认的注解映射的支持 -->
	<mvc:annotation-driven/>
	<context:annotation-config/>
	<aop:aspectj-autoproxy/>

	<!-- 自动扫描的包名 -->
	<context:component-scan base-package="spring.test.web.controller"/>
	
	<bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter" />
	
</beans>

3.写java代码了

先建一个User类

public class User {
	@NotNull
	private String username;
	
	@NotNull(message = "密码不能为空")
	private String password;
	
	public String getUsername() {
		return username;
	}
	
	public void setUsername(String username) {
		this.username = username;
	}
	
	public String getPassword() {
		return password;
	}
	
	public void setPassword(String password) {
		this.password = password;
	}
	
}
然后建一个controller试试
@ResponseBody
@RequestMapping("/test1")
public AjaxResponse validateTest1(@Valid User user, BindingResult result){
	AjaxResponse ajaxResponse = new AjaxResponse();
	Map<String, Object> map = new HashMap<>();
	if(result.hasErrors()){
		ajaxResponse.setSuccess(false);
		ajaxResponse.setHasErrors(true);
		map.put("errors", result.getAllErrors());
	}
	else {
		map.put("now", new Date());
		map.put("user", user);
	}
	ajaxResponse.setData(map);
	return ajaxResponse;
}

这个方法第一个参数上加了@Valid标注,第二个参数是必须的而且必须紧跟着@Valid参数之后,校验结果都在这个result里面

方法逻辑比较简单,调用result.hasErrors()看校验有没有错误,有错误的话就把所有的错误放进结果返回给客户端,如果没有错误就返回当前时间跟user对象

然后写个测试方法试试

@Test
public void test1() throws Exception{
	this.mockMvc.perform(post("/validator/test1")).andDo(print());
	this.mockMvc.perform(post("/validator/test1").param("username", "testusername").param("password", "testpassword")).andDo(print());
}

第一个请求的结果是

{"success":false,"message":null,"hasErrors":true,"data":[{"name":"user","message":"may not be null"},{"name":"user","message":"密码不能为空"}]}

第二个请求结果是

{"success":true,"message":null,"hasErrors":false,"data":{"now":1420788232169,"user":{"username":"testusername","password":"testpassword"}}}

很明显第一次请求没有用户名和密码两个字段校验都没有通过,第二次是成功的

用起来还是很简单的,但是如果我不想每次都在controller方法里写if(result.hasErrors())怎么办呢,写个切面,把if写在切面里,如果有errors直接就返回了,不用再执行controller方法了

@Aspect
public class ValidAspect {
	
	@Autowired private Validator validator;
	
	@Around("@annotation(org.springframework.web.bind.annotation.ResponseBody)")
	public Object doTest(ProceedingJoinPoint pjp) throws Throwable{
		MethodSignature signature = (MethodSignature) pjp.getSignature();
		Method method = signature.getMethod();
		if(!AjaxResponse.class.equals(method.getReturnType())){
			pjp.proceed();
		}
		Object[] args = pjp.getArgs();
		Annotation[][] annotations = method.getParameterAnnotations();
		for(int i = 0; i < annotations.length; i++){
			if(!hasValidAnnotation(annotations[i])){
				continue;
			}
			if(!(i < annotations.length-1 && args[i+1] instanceof BindingResult)){
				//验证对象后面没有跟bindingResult,事实上如果没有应该到不了这一步
				continue;
			}
			BindingResult result = (BindingResult) args[i+1];
			if(result.hasErrors()){
				AjaxResponse ajaxResponse = new AjaxResponse();
				ajaxResponse.setSuccess(false);
				ajaxResponse.setHasErrors(true);
				ajaxResponse.setData(processErrors(result));
				return ajaxResponse;
			}
		}
		return pjp.proceed();
	}

	private boolean hasValidAnnotation(Annotation[] annotations){
		if(annotations == null){
			return false;
		}
		for(Annotation annotation : annotations){
			if(annotation instanceof Valid){
				return true;
			}
		}
		return false;
	}
	
	private List<BindingError> processErrors(BindingResult result){
		if(result != null && result.hasErrors()){
			List<BindingError> list = new ArrayList<BindingError>();
			for(ObjectError error : result.getAllErrors()){
				BindingError be = new BindingError();
				be.setMessage(error.getDefaultMessage());
				be.setName(error.getObjectName());
				list.add(be);
			}
			return list;
		}
		return null;
	}
}

注意要在springmvc配置文件加一行<bean class="spring.test.web.aop.ValidAspect"/>

然后再写个方法逻辑跟上面的类似

@ResponseBody
@RequestMapping("/test2")
public AjaxResponse validateTest2(@Valid User user, BindingResult result){
	AjaxResponse ajaxResponse = new AjaxResponse();
	Map<String, Object> map = new HashMap<>();
	map.put("now", new Date());
	map.put("user", user);
	ajaxResponse.setData(map);
	return ajaxResponse;
}

这里没有再去判断hasErrors()了,然后测试一下

写测试方式试一下

@Test
public void test2() throws Exception{
	this.mockMvc.perform(post("/validator/test2")).andDo(print());
	this.mockMvc.perform(post("/validator/test2").param("username", "testusername").param("password", "testpassword")).andDo(print());
}

第一个请求结果是

{"success":false,"message":null,"hasErrors":true,"data":[{"name":"user","message":"密码不能为空"},{"name":"user","message":"may not be null"}]}
第二个请求结果是

{"success":true,"message":null,"hasErrors":false,"data":{"now":1420788479105,"user":{"username":"testusername","password":"testpassword"}}}
效果跟上面是一样的

当然我这个切面仅仅是个示范,我拦截的是带有ResponseBody注解的方法,我这些方法会返回一个统一的格式,如果是要返回别的视图就要自己定义注解加其他参数了

JSR-303原生支持的校验注解也是有限的,如果要实现其他的验证,可以自己拓展,拓展方法就下次再说了,我也才刚接触。


本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

springmvc使用JSR-303进行校验 的相关文章

随机推荐

  • python代码使用cython进行加密

    python代码加密 前言 加密的多种方式 Cython加密 步骤 注意 部署 前言 加密的多种方式 发布编译过的pyc文件 缺点 很容易被反编译 PyInstaller 是一个用来将 Python 程序打包成一个独立可执行软件包 支持 W
  • 粉丝提问

    粉丝提问 c语言 如何定义一个和库函数名一样的函数 并在函数中调用该库函数 一个端口号可以同时被两个进程绑定吗 两个线程 两个互斥锁 怎么形成一个死循环 一个例子让你看清线程调度的随机性 问题描述 某个函数fun 1 是在lib内 没法修改
  • R语言:cbind()和rbind()

    可以利用函数cbind 和rbind 把向量和矩阵拼成一个新的矩阵 概略地说 cbind 把矩阵横向合并成一个大矩阵 列方式 而rbind 是纵向合并 行方式 cbind 根据列进行合并 即叠加所有列 m列的矩阵与n列的矩阵cbind 最后
  • ant design of vue 之文件上传组件(腾讯云)封装

    原理 通过调用后台接口获取腾讯云秘钥 然后将秘钥以及文件信息上传到腾讯云 获取文件腾讯云存储信息 最后组件将腾讯云存储信息返回出去 在组件外部调用后台接口将腾讯云信息存到后台 安装cos js sdk v5依赖 npm i cos js s
  • 2021数据治理工具图谱研究报告 附下载

    根据2021年4月发布的 国家数据资源调查报告 2020 显示 2019年我国数据产量总规模为3 9ZB 同比增加29 3 占全球数据总产量 42ZB 的9 3 人均数据产量方面 2019年我国人均数据产量为3TB 数据来源结构方面 数据资
  • 机器学习中的高斯过程

    0 前言 写这篇文章的目的就是为了总结一下最近在学习的高斯过程的一些内容 但是由于我是初学者可能有些地方理解不到位 请大家多多谅解 文末附上了一些数学方面的推导 1 高斯过程定义 高斯过程是在连续域上定义的一种随机过程 可以看成连续域中所有
  • vue中通过js把从接口取到的url中的{}里的参数替换成对应的值

    最近工作中遇到个需求 首先在一个页面中给按钮配置个点击跳转的链接 手动输入需要跳转的url及其需要的参数 后续要在另一个页面中通过接口取到配置的这个url 并替换掉当中的参数 第一次处理这种情况 所以记录一下 前端页面配置url 参数值通过
  • 【YOLO系列】YOLOv5超详细解读(网络详解)

    前言 吼吼 终于来到了YOLOv5啦 首先 一个热知识 YOLOv5没有发表正式论文哦 为什么呢 可能YOLOv5项目的作者Glenn Jocher还在吃帽子吧 hh 目录 前言 一 YOLOv5的网络结构 二 输入端 1 Mosaic数据
  • m118w重置墨粉_富士施乐 Fuji Xerox DocuPrint M118w/M118z重置墨粉页面计数器及重置硒鼓...

    富士施乐M118w的硒鼓和分仓是独立的 前几天M118w就提示墨粉已经不足 于是Pop就看了一下机器 打印了约1200张了 随机器来的原装可能就是这样而已 于是就了解了一下富士施乐M118w如何加粉 如何换硒鼓 以及如何清零重置硒鼓的操作
  • Mac os 10.14装virtualbox 失败的解决方案

    1 Mac 系统装virtualbox 失败如下 2 由于Mac 10 14的安全级别更高 所以导致这个软件安装过程失败 需要一下操作安装就没问题 2 1 开启通用里的允许任何来源 sudo spctl master disable 2 2
  • LeetCode 44 Wildcard Matching (通配符匹配 记忆化搜索 剪枝 推荐)

    Given an input string s and a pattern p implement wildcard pattern matching with support for and Matches any single char
  • Freertos中vTaskDelay()是怎么用的

    1 常见的使用场景 void vLED Task void pvParameters while 1 Heartbeat LED vTaskDelay 1000 portTICK RATE MS 说明 上面这段代码的意思是 led翻转后经过
  • Exception in thread "main" java.lang.NoClassDefFoundError解决

    1 错误描述 Exception in thread main java lang NoClassDefFoundError HelloWorld wrong name org xuwei HelloWorld at java lang C
  • 2018年最好的8款杀毒软件

    如今 网络犯罪和欺骗和攻击电脑的病毒 特洛伊木马和网络钓鱼诈骗导致损失的事件并没有像人们想像的那么频繁发生 这意味着很多人正在使用最强大的安全软件保护自己的电脑 而其一如既往地重要 这就是为什么推出这个2018年全球最佳防病毒软件名单的原因
  • 搭建商城的微服务架构-1

    创建父项目 mall 先创建一个 父项目 mall 再在这个父项目中创建多个子项目 修改pom文件 最终mall的pom文件如下
  • 目标检测算法回顾之Anchor free篇章

    基于anchor free的目标检测方法 一 背景与定义 1 1 anchor based的特征 1 2 anchor的好处 1 3 anchor的局限 1 4 anchor free 与anchor based的区别 二 概述 三 早期探
  • 以太坊2.0 节点搭建:共识端+执行端

    1 配置 本人使用配置 共识端 prysm 版本 3 1 1 执行端 geth 版本 1 10 23 当前使用1 10 25 OS centos7 6 CPU 8核 Memory 16GB RAM Storage 3T SSD Networ
  • 算法梳理boosting\bagging\RF(1)

    LeetCode题目记录 1 集成学习概念 1 1 集成学习分类 1 2 集成学习步骤 2 个体学习器概念 3 boosting bagging 3 1 boosting 3 2 bagging 3 3 二者的区别 4 随机森林的思想 5
  • mlxtend实现简单的Apriori算法(关联算法)

    关联算法有几个重要的概念 下面以官方教程为例 Apple Beer Rice Chicken Apple Beer Rice Apple Beer Apple Bananas Milk Beer Rice Chicken Milk Beer
  • springmvc使用JSR-303进行校验

    下面提供一种springmvc的校验方案 一般没有校验或者手动写validator的话都要写好多代码好多if判断 使用JSR 303规范校验只需要在Pojo字段上加上相应的注解就可以实现校验了 1 依赖的jar包 我直接贴pom了