`
wdmcygah
  • 浏览: 63258 次
社区版块
存档分类
最新评论

前后台校验示例及讲解

阅读更多

在开发Java Web程序时,前后校验逻辑应该是必不可少的一部分。其中,前台校验更多地是从用户体验的角度出发,而后台校验更多地是从数据安全的角度出发。本博文基于Spring MVC写了一个前台后台结合校验的示例,不过没有使用Spring MVC自带的校验框架。示例前台使用Jquery Validation进行校验,后台使用Hibernate Validation进行校验,所以示例所需要的校验逻辑并不依赖于Spring MVC,只要引入相应的校验包,即可在任何Java Web环境中实现校验功能。(使用Spring MVC自带校验逻辑进行校验,改天有空再写个示例)

如果Jquery Validation使用不熟悉的话,可以查看我的Jquery Validation实用示例及讲解
如果Hibernate Validation使用不熟悉的话,可以查看我的Hibernate Validation使用示例及讲解

下面直接上示例代码:
一、主要依赖

   jquery.validate.js 

<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-validator</artifactId>
			<version>5.1.3.Final</version>
		</dependency>

 

 二、后台Controller类

该类只是模拟注册功能,并有一个用户名是否存在判断逻辑,主要是为了体现前后台校验的用法,所以没写其它逻辑,实际情况肯定比这复杂得多。

/**
 * 注册控制器
 * @author wdmcygah
 *
 */
@Controller
@RequestMapping("/register")
public class RegisterController {

	/**
	 * 注册页面展示
	 */
	@RequestMapping("/show")
	public String register(){
		return "/register/show";
	}
	
	/**
	 * 注册方法(主要为了演示使用Hibernate validation进行校验)
	 */
	@RequestMapping(value="/create",method=RequestMethod.POST)
	public String doRegister(RegisterInfo info,Model model){
		//1、进行参数校验(这里省略名字重复校验,只演示相关用法)
		ValidationResult result = ValidationUtils.validateEntity(info);
		if( result.isHasErrors() ){
			model.addAttribute("errorMsg", result.getErrorMsg());
			return "/register/show";
		}
		
		//2、注册逻辑——省略
		model.addAttribute("successFlag", "1");
		return "/register/show";
	}
	
	/**
	 * 判断用户名是否存在
	 * 详细描述:
	 * 1、这里只作简单的演示,若名称以y开头则返回不存在。实际运用中可能是查询数据库
	 * 2、注意这里用到@ResponseBody注解,表示返回值不是视图名,直接将返回值绑定到response body中
	 * @param name
	 * @return
	 */
	@RequestMapping(value="isNameExists",method=RequestMethod.POST)
	@ResponseBody
	public String isNameExists( String name ){
		if( StringUtils.isEmpty(name) ){
			return "false";
		}
		//只有以'y'开头的名字才是不存在的
		if( name.startsWith("y") ){
			return "true";
		}
		return "false";
	}
}

 

三、后台校验工具类

该类对Hibernate Validation方法进行了简单封装,实现校验实体对象的功能,返回是自定义的校验对象。

/**
 * 校验工具类
 * @author wdmcygah
 *
 */
public class ValidationUtils {

	private static Validator validator =  Validation.buildDefaultValidatorFactory().getValidator();
	
	public static <T> ValidationResult validateEntity(T obj){
		ValidationResult result = new ValidationResult();
		 Set<ConstraintViolation<T>> set = validator.validate(obj,Default.class);
		 if( CollectionUtils.isNotEmpty(set) ){
			 result.setHasErrors(true);
			 Map<String,String> errorMsg = new HashMap<String,String>();
			 for(ConstraintViolation<T> cv : set){
				 errorMsg.put(cv.getPropertyPath().toString(), cv.getMessage());
			 }
			 result.setErrorMsg(errorMsg);
		 }
		 return result;
	}
	
}

 

四、后台校验结果类

/**
 * 校验结果
 * @author wdmcygah
 *
 */
public class ValidationResult {

	//校验结果是否有错
	private boolean hasErrors;
	
	//校验错误信息
	private Map<String,String> errorMsg;

	public boolean isHasErrors() {
		return hasErrors;
	}

	public void setHasErrors(boolean hasErrors) {
		this.hasErrors = hasErrors;
	}

	public Map<String, String> getErrorMsg() {
		return errorMsg;
	}

	public void setErrorMsg(Map<String, String> errorMsg) {
		this.errorMsg = errorMsg;
	}

	@Override
	public String toString() {
		return "ValidationResult [hasErrors=" + hasErrors + ", errorMsg="
				+ errorMsg + "]";
	}

}

 

五、后台被校验对象

/**
 * 注册信息
 * @author wdmcygah
 *
 */
public class RegisterInfo {

	@NotBlank(message="名字不能为空或者空串")
	private String name;
	
	@NotBlank(message="密码不能为空或者空串")
	@Pattern(regexp="(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{5,10}",message="密码必须是5~10位数字和字母的组合")
	private String password;
	
	@NotBlank(message="邮箱不能为空或者空串")
	@Email(message="邮箱格式不正确")
	private String email;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}
	
}

 

六、前台注册页面

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<!-- Bootstrap -->
<link href="<%=request.getContextPath()%>/statics/css/bootstrap.min.css"
	rel="stylesheet">
<!-- 这里引入的是校验提示的样式 -->
<link href="<%=request.getContextPath()%>/statics/css/valid.css"
	rel="stylesheet">
</head>
<body>
	<div class="container">

		<form action="create.htm" method="post" id="registerForm"
			class="form-horizontal" role="form">
			<fieldset class="text-center">
				<legend> 前后台校验功能测试页面 </legend>
				<c:choose>
					<c:when test="${successFlag=='1'}">
							注册成功!
								<button type="button" class="btn btn-primary btn-large"
							onclick="window.location.href='show.htm' ">返回</button>
					</c:when>
					<c:otherwise>
						<div class="form-group">
							<label class="col-sm-4 control-label" for="name">姓名</label>
							<div class="col-sm-4">
								<input type="text" class="form-control" name="name" id="name">
							</div>
							<label class="error" for="name">${errorMsg.name}</label>
						</div>
						<div class="form-group">
							<label class="col-sm-4 control-label" for="password">密码</label>
							<div class="col-sm-4">
								<input type="password" class="form-control" name="password"
									id="password">
							</div>
							<label class="error" for="password">${errorMsg.password}</label>
						</div>
						<div class="form-group">
							<label class="col-sm-4 control-label" for="email">电子邮箱</label>
							<div class="col-sm-4">
								<input type="text" class="form-control" name="email" id="email">
							</div>
							<label class="error" for="email">${errorMsg.email}</label>
						</div>
						<div class="form-actions ">
							<button type="submit" class="btn btn-primary btn-large">提交</button>
							<button type="reset" class="btn">取消</button>
						</div>
					</c:otherwise>
				</c:choose>
			</fieldset>
		</form>
	</div>

	<!-- js -->
	<script
		src="<%=request.getContextPath()%>/statics/js/import/jquery-1.11.1.js"></script>
	<script
		src="<%=request.getContextPath()%>/statics/js/import/jquery.validate.js"></script>
	<script
		src="<%=request.getContextPath()%>/statics/js/import/bootstrap.min.js"></script>
	<!-- 这里引入的是校验提示信息的JS文件 -->
	<script
		src="<%=request.getContextPath()%>/statics/js/import/messages_zh.js"></script>
	<!-- 这里引入的是表单校验的JS文件 -->
	<script
		src="<%=request.getContextPath()%>/statics/js/my/register_validation.js"></script>
	<!-- 这里引入的是扩展Jquery validation的自定义JS文件 -->
	<script
		src="<%=request.getContextPath()%>/statics/js/my/additional-methods.js"></script>
</body>
</html>

 

七、前台校验JS

这里主要介绍下validate方法中的remote,后面跟的是一个ajax请求,判断名字是否存在,后台只用返回“true”或者“false”,表示校验是否通过就行了。这个在表单异步校验的时候非常实用。

$(function() {

	$('#registerForm').validate({
		rules : {
			name : {
				required : true,
				remote : {
					url : "isNameExists.htm", //后台处理程序
					type : "post", //数据发送方式
					data : { //要传递的数据
						name : function() {
							return $("#name").val();
						}
					}
				}
			},
			password : {
				required : true,
			},
			email : {
				required : true,
				email : true
			}
		},
		messages:{
			name:{
				remote:"名字已经存在"
			}
		},
		success : "valid",
		errorClass : "error",
		errorPlacement : function(error, element) {
			error.appendTo(element.parent().parent());
		}
	});
});

 

这里限于篇幅,只展示了主要逻辑代码,若想查看完整源码,可以查看我的Github仓库:https://github.com/wdmcygah/research-spring。其中仓库里面有些与本博文不相关的代码,注意区分。

代码在JDK1.8、chrome浏览器下测试通过。测试访问地址:http://localhost:8080/spring/register/show.htm,如果想完全地测试后台校验,需要把文中的JS校验方法注释掉,或者把浏览器的JS禁用。

 

 

3
2
分享到:
评论
4 楼 wdmcygah 2015-01-13  
yunpheng 写道
wdmcygah 写道
yunpheng 写道
“前后校验逻辑应该是必不可少的一部分。其中,前台校验更多地是从用户体验的角度出发,而后台校验更多地是从数据安全的角度出发。”

这句话总结的很到位!
前端做过的校验,到后端了还要再做。但是上面的例子中,“判断用户名是否存在”,在后端为什么没有再做校验呢?从数据安全的角度,如果用户绕过了前端,直接到后端了,应该要做校验
判断用户名是否存在做了校验,ajax请求到后台的,多用几组数据试下,例如“123”、“y123”

多谢回复!
可能我表述的不够明确,你这里前端使用Jquery Validation进行校验,后端使用Hibernate Validation进行校验,但我看了你的代码,“判断用户名是否存在”只是在前端做了校验(通过Jquery Validation的remote选项ajax请求到后台),后端Hibernate Validation里面并没有校验。如果我绕过你的前端页面,直接发起http请求到后端注册,那就不会经过前端的校验了,所以后端为了保证数据安全,应该进一步做校验,不是吗?
  是的,后台没有再检查是否重复,这里因为只是演示用法,所以没加,还是有失严谨。实际情况是需要保持一致的。你说得很对。
3 楼 yunpheng 2015-01-13  
wdmcygah 写道
yunpheng 写道
“前后校验逻辑应该是必不可少的一部分。其中,前台校验更多地是从用户体验的角度出发,而后台校验更多地是从数据安全的角度出发。”

这句话总结的很到位!
前端做过的校验,到后端了还要再做。但是上面的例子中,“判断用户名是否存在”,在后端为什么没有再做校验呢?从数据安全的角度,如果用户绕过了前端,直接到后端了,应该要做校验
判断用户名是否存在做了校验,ajax请求到后台的,多用几组数据试下,例如“123”、“y123”

多谢回复!
可能我表述的不够明确,你这里前端使用Jquery Validation进行校验,后端使用Hibernate Validation进行校验,但我看了你的代码,“判断用户名是否存在”只是在前端做了校验(通过Jquery Validation的remote选项ajax请求到后台),后端Hibernate Validation里面并没有校验。如果我绕过你的前端页面,直接发起http请求到后端注册,那就不会经过前端的校验了,所以后端为了保证数据安全,应该进一步做校验,不是吗?
2 楼 wdmcygah 2015-01-12  
yunpheng 写道
“前后校验逻辑应该是必不可少的一部分。其中,前台校验更多地是从用户体验的角度出发,而后台校验更多地是从数据安全的角度出发。”

这句话总结的很到位!
前端做过的校验,到后端了还要再做。但是上面的例子中,“判断用户名是否存在”,在后端为什么没有再做校验呢?从数据安全的角度,如果用户绕过了前端,直接到后端了,应该要做校验
判断用户名是否存在做了校验,ajax请求到后台的,多用几组数据试下,例如“123”、“y123”
1 楼 yunpheng 2015-01-12  
“前后校验逻辑应该是必不可少的一部分。其中,前台校验更多地是从用户体验的角度出发,而后台校验更多地是从数据安全的角度出发。”

这句话总结的很到位!
前端做过的校验,到后端了还要再做。但是上面的例子中,“判断用户名是否存在”,在后端为什么没有再做校验呢?从数据安全的角度,如果用户绕过了前端,直接到后端了,应该要做校验

相关推荐

    关于Android短信验证码的获取的示例

    本文将详细讲解如何在Android应用中实现短信验证码的获取功能,以供开发者参考。 首先,我们需要选择一个短信验证服务提供商,例如容联云通讯。在开始之前,您需要在该服务商的官方网站上注册一个开发者账号,并...

    使用layui前端框架弹出form表单以及提交的示例

    下面,我们就按照步骤来详细讲解这个示例。 **第一步:引入layui相关文件** 在开始之前,你需要在HTML页面中引入layui的基本样式文件(layui.css)和核心脚本文件(layui.js)。这两个文件是layui框架的基础,它们...

    PHP实现APP微信支付的实例讲解

    微信服务器在接收到请求后会进行校验,如果校验通过,则返回预支付交易会话标识,APP端接收到这个标识后,就可以调起微信支付的支付接口完成支付流程。 除此之外,文章中还提到,APP端需要接收来自微信服务器的预...

    FM430扫码枪串口通讯Demo

    FM430扫码枪串口通讯Demo是一款针对FM430型号扫码枪的软件示例,主要用于演示如何通过串行接口(Serial Port)与该设备进行数据交互。在IT行业中,串口通讯是一种常见的硬件设备与计算机之间的通信方式,尤其在工业...

    datagridview的列编辑

    本篇将详细讲解`DataGridView`控件的列编辑功能。 一、DataGridView概述 `DataGridView`控件是一个可自定义的网格视图,支持多种数据源,包括数组、数据库、XML等。它的主要功能包括数据的显示、排序、分页、过滤...

    delphi串口通信工程开发实例导航

    本教程“Delphi串口通信工程开发实例导航”将深入讲解如何在Delphi环境中实现串口通信,帮助开发者掌握这一关键技术。 首先,我们需要了解串口通信的基本概念。串口通信,也称为串行通信,是数据一次传输一位的通信...

    软件自动更新源码

    1. **安全验证**:在下载和应用更新前,务必验证文件的完整性,可以使用MD5或SHA校验和。 2. **用户交互**:提供清晰的更新提示,让用户知道更新过程。 3. **后台更新**:尽量在用户不使用软件时进行更新,以避免...

    activiti文档

    - **校验图形和导出到自定义的输出格式**:验证图形的正确性及导出功能。 #### 13. Activiti Explorer - **流程图**:查看流程图。 - **任务**:管理待办任务。 - **启动流程实例**:启动新的流程实例。 - **我的...

Global site tag (gtag.js) - Google Analytics