参数校验虽说大多在前台通过js完成,但是也应该懂得如何在后端实现参数的简单校验。由于本人目前处于初级阶段,所以文章的深度有限。随着时间推移我会逐渐更新。
参数校验的步骤我就不在赘述,推荐:
参数校验的步骤
我感觉这篇文章,博主其实写的还可以。
我这只说参数校验的另外一种方法,通过继承和引用实现参数校验。
首先是Model参数类:
speaker.java
package com.zhiyou100.video.model;
import java.sql.Date;
import javax.validation.constraints.Size;
import org.springframework.web.multipart.MultipartFile;
import com.zhiyou100.video.common.ValidateGroup1;
public class Speaker {
private int id;
@Size(min=2,max=5,message="{name.error}",groups={ValidateGroup1.class})
private String speakerName;
private String speakerJob;
private String speakerHeadUrl;
private String speakerDescr;
private MultipartFile icon;
private Date insertTime;
private Date updateTime;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSpeakerName() {
return speakerName;
}
public void setSpeakerName(String speakerName) {
this.speakerName = speakerName;
}
public String getSpeakerJob() {
return speakerJob;
}
public void setSpeakerJob(String speakerJob) {
this.speakerJob = speakerJob;
}
public String getSpeakerHeadUrl() {
return speakerHeadUrl;
}
public void setSpeakerHeadUrl(String speakerHeadUrl) {
this.speakerHeadUrl = speakerHeadUrl;
}
public String getSpeakerDescr() {
return speakerDescr;
}
public void setSpeakerDescr(String speakerDescr) {
this.speakerDescr = speakerDescr;
}
public Date getInsertTime() {
return insertTime;
}
public void setInsertTime(Date insertTime) {
this.insertTime = insertTime;
}
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public MultipartFile getIcon() {
return icon;
}
public void setIcon(MultipartFile icon) {
this.icon = icon;
}
@Override
public String toString() {
return "SpeakerModel [id=" + id + ", speakerName=" + speakerName + ", speakerJob=" + speakerJob
+ ", speakerHeadUrl=" + speakerHeadUrl + ", speakerDescr=" + speakerDescr + ", insertTime=" + insertTime
+ ", updateTime=" + updateTime + "]";
}
}
我这里为方便,只写了一种校验:校验输入的speakername的最小为2最大不超过5.我这里让参数校验不通过,传递到了另外一个页面上。
addError.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
${message}
</body>
</html>
如果参数校验不通过会跳转到这个jsp页面上面,给出提示信息。这些信息来源于。
CustomValidationMessage.properties文件
age.error=年龄在1到100之间
hobby.error=爱好输入不正确'
name.error=姓名错误
这个东西,在配置校验框架的时候已经提到。
接着就是进行,校验工作。
我这里是将校验安排在了一个父类BaseController.java,和一个工具类BeanValidators.java里面。
而这样,只需要在controller层调用相应的方法即可
BeanValidators.java
package com.zhiyou100.video.util;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
/**
* Validator(Hibernate Validator)工具类.
*
* ConstraintViolation中包含propertyPath, message 和invalidValue等信息.
* 提供了各种convert方法,适合不同的i18n需求: 1. List<String>, String内容为message 2.
* List<String>, String内容为propertyPath + separator + message 3.
* Map<propertyPath, message>
*
*/
public class BeanValidators {
/**
* 调用JSR303的validate方法, 验证失败时抛出ConstraintViolationException.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static void validateWithException(Validator validator, Object object, Class<?>... groups)
throws ConstraintViolationException {
Set constraintViolations = validator.validate(object, groups);
if (!constraintViolations.isEmpty()) {
throw new ConstraintViolationException(constraintViolations);
}
}
/**
* 辅助方法,
* 转换ConstraintViolationException中的Set<ConstraintViolations>中为List<message>.
*/
public static List<String> extractMessage(ConstraintViolationException e) {
return extractMessage(e.getConstraintViolations());
}
/**
* 辅助方法, 转换Set<ConstraintViolation>为List<message>
*/
@SuppressWarnings("rawtypes")
public static List<String> extractMessage(Set<? extends ConstraintViolation> constraintViolations) {
List<String> errorMessages = new ArrayList<String>();
for (ConstraintViolation violation : constraintViolations) {
errorMessages.add(violation.getMessage());
}
return errorMessages;
}
/**
* 辅助方法,
* 转换ConstraintViolationException中的Set<ConstraintViolations>为Map<property,
* message>.
*/
public static Map<String, String> extractPropertyAndMessage(ConstraintViolationException e) {
return extractPropertyAndMessage(e.getConstraintViolations());
}
/**
* 辅助方法, 转换Set<ConstraintViolation>为Map<property, message>.
*/
@SuppressWarnings("rawtypes")
public static Map<String, String> extractPropertyAndMessage(
Set<? extends ConstraintViolation> constraintViolations) {
Map<String, String> errorMessages = new HashMap<String, String>();
for (ConstraintViolation violation : constraintViolations) {
errorMessages.put(violation.getPropertyPath().toString(), violation.getMessage());
}
return errorMessages;
}
/**
* 辅助方法,
* 转换ConstraintViolationException中的Set<ConstraintViolations>为List<propertyPath
* message>.
*/
public static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e) {
return extractPropertyAndMessageAsList(e.getConstraintViolations(), " ");
}
/**
* 辅助方法, 转换Set<ConstraintViolations>为List<propertyPath message>.
*/
@SuppressWarnings("rawtypes")
public static List<String> extractPropertyAndMessageAsList(
Set<? extends ConstraintViolation> constraintViolations) {
return extractPropertyAndMessageAsList(constraintViolations, " ");
}
/**
* 1234 辅助方法,
* 转换ConstraintViolationException中的Set<ConstraintViolations>为List<propertyPath
* +separator+ message>.
*/
public static List<String> extractPropertyAndMessageAsList(ConstraintViolationException e, String separator) {
return extractPropertyAndMessageAsList(e.getConstraintViolations(), separator);
}
/**
* 辅助方法, 转换Set<ConstraintViolation>为List<propertyPath +separator+ message>.
*/
@SuppressWarnings("rawtypes")
public static List<String> extractPropertyAndMessageAsList(Set<? extends ConstraintViolation> constraintViolations,
String separator) {
List<String> errorMessages = new ArrayList<String>();
for (ConstraintViolation violation : constraintViolations) {
try {
errorMessages.add(violation.getPropertyPath() + separator
+ new String(violation.getMessage().getBytes("ISO-8859-1"), "UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return errorMessages;
}
}
BaseController.java
package com.zhiyou100.video.controller;
import java.beans.PropertyEditorSupport;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.List;
import javax.validation.ConstraintViolationException;
import javax.validation.Validator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ui.Model;
import org.springframework.validation.BindException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.InitBinder;
import com.zhiyou100.video.util.BeanValidators;
import com.zhiyou100.video.util.DateUtil;
public class BaseController {
/*
* 作业 io nio 今天讲的内容
*
* 明天讲mybatis
*
*/
@Autowired
protected Validator validator;
/**
* 初始化数据绑定 1. 将所有传递进来的String进行HTML编码,防止XSS攻击 2. 将字段中Date类型转换为String类型
*/
@InitBinder
protected void initBinder(WebDataBinder binder) {
// 任何转换器都不配置 按格式输入(yyyy-MM-dd,yyyy-MM-dd HH:mm:ss)不会报错 否则400
// 转换器配置的两种方式掌握
// 如果配置了参数校验springmvc 参数绑定如果出现异常就不会报400错误了 但是不能正常赋值
/*
* binder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
*
* @Override public void setAsText(String text) {
* setValue(DateUtil.stringToDateyy(text));
*
* }
*
* });
*/
binder.registerCustomEditor(Timestamp.class, new PropertyEditorSupport() {
@Override
public void setAsText(String text) {
setValue(new Timestamp(DateUtil.stringToDate(text).getTime()));
}
});
}
/**
* 异常处理
*
* @return
*/
@ExceptionHandler({ BindException.class, IllegalStateException.class })
public String bindException() {
return "/error/400";
}
/*
* 权限异常
*
* 业务异常 都可以在这处理
*
*
*
*/
/**
* 服务端参数有效性验证
*
* @param object
* 验证的实体对象
* @param groups
* 验证组
* @return 验证成功:返回true;严重失败:将错误信息添加到 message 中
*/
protected boolean beanValidator(Model model, Object object, Class<?>... groups) {
try {
BeanValidators.validateWithException(validator, object, groups);
} catch (ConstraintViolationException ex) {
List<String> list = BeanValidators.extractPropertyAndMessageAsList(ex, ": ");
list.add(0, "数据验证失败:");
addMessage(model, list.toArray(new String[] {}));
return false;
}
return true;
}
/**
* 服务端参数有效性验证
*
* @param object
* 验证的实体对象
* @param groups
* 验证组,不传入此参数时,同@Valid注解验证
* @return 验证成功:继续执行;验证失败:抛出异常跳转400页面。
*/
protected void beanValidator(Object object, Class<?>... groups) {
BeanValidators.validateWithException(validator, object, groups);
}
/**
* 添加Model消息
*
* @param message
*/
protected void addMessage(Model model, String... messages) {
StringBuilder sb = new StringBuilder();
for (String message : messages) {
sb.append(message).append(messages.length > 1 ? "<br/>" : "");
}
model.addAttribute("message", sb.toString());
}
}
配置好这两个类,就可以在controller层进行校验操作:
if (!this.beanValidator(model, speaker, ValidateGroup1.class)) {
return "/admin/speaker/addError";
}
这个就是核心代码,如果参数为真,那么就执行if里面的return操作,返回到一个jsp页面上显示效果如下:
源码我稍后上传GitHub之后,再补个链接出来。有什么问题,或者不对的地方,请指出来,共同进步。