springmvc基于注解的使用(类型转换器&数据格式化&数据校验)
- 1、类型转换器
- 2、数据格式化
- 2.1、提交时的jsp
- 2.2、后端控制器
- 2.3、实体类
- 2.4、最后展示的jsp
- 3、数据格式化(hibernate-validate)
- 3.1、描述
- 3.2、使用普通标签实现
- 3.3、使用form标签实现
1、类型转换器
在SpringMvc中有许多的类型转换器,都在Convert这个接口下面定义着,但是有时候我们也会遇到我们需要转换的形式SpringMvc没有提供,我们就可以自定义一个类型转换器:
Convert接口类:
自定义类型转换器:
步骤在代码中:
import org.springframework.core.convert.converter.Converter;
import org.springframework.util.StringUtils;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @author dujlc
* 1、定义类型转换器 需要明确 源类型 目标类型
* 2、在convert方法自定义类型的实现方法
* 3、在SpringMvc中配置我们的自定义类型转换器
* 4、在annotation-driven中加入自定义类型转换器
*/
public class MyStringToDateConvert implements Converter<String, Date> {
public Date convert(String s) {
if(!StringUtils.isEmpty(s)){
try {
if(s.split("-").length == 3){
DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
return df.parse(s);
}
if(s.split("/").length == 3){
DateFormat df = new SimpleDateFormat("yyyy/MM/dd");
return df.parse(s);
}
} catch (ParseException e) {
e.printStackTrace();
}
}
return null;
}
}
Spring配置文件中的配置:
<!-- 配置访问静态资源 -->
<mvc:annotation-driven conversion-service="conversionService"></mvc:annotation-driven>
<!-- 配置自定义类型转换器 -->
<!-- 如果需要注解的方式去支持日期格式转换,则需要改成org.springframework.format.support.FormattingConversionServiceFactoryBean类 -->
<bean class="org.springframework.context.support.ConversionServiceFactoryBean" name="conversionService">
<property name="converters">
<set>
<bean class="cool.ale.convert.MyStringToDateConvert"></bean>
</set>
</property>
</bean>
2、数据格式化
我们可以使用到SpringMvc的标签库
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
主要作用就是对显示的数据进行格式化
2.1、提交时的jsp
<%--
Created by IntelliJ IDEA.
User: dujlc
Date: 2021/6/3
Time: 22:07
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<html>
<head>
<title>Title</title>
</head>
<body>
<h1>添加用户</h1>
<form action="${pageContext.request.contextPath}/addUser" method="post">
<p>
id:<input type="text" name="id" value="123"/>
</p>
<p>
userName:<input type="text" name="userName" value="张三"/>
</p>
<p>
birthday:<input type="text" name="birthday" value="2021/01/01"/>
</p>
<p>
balance:<input type="text" name="balance" value="5000"/>
</p>
<p>
salary:<input type="text" name="salary" value="10000"/>
</p>
<p>
taskCount:<input type="text" name="taskCount" value="0.99"/>
</p>
<p>
hobbies:<input type="checkbox" name="hobbies" name="唱歌" checked="true"/>唱歌
<input type="checkbox" name="hobbies" name="跳舞" checked="true"/>跳舞
</p>
<p>
<input type="submit" value="提交"/>
</p>
</form>
</body>
</html>
2.2、后端控制器
@Controller
public class UserController {
@RequestMapping("/addUser")
public String add(User user){
System.out.println(user);
return "show";
}
}
2.3、实体类
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.format.annotation.NumberFormat;
import java.util.Arrays;
import java.util.Date;
/**
* @author dujlc
*/
public class User {
private Integer id;
private String userName;
@DateTimeFormat(pattern = "yyyy/MM/dd")
private Date birthday;
/**
* ¥5000
*/
@NumberFormat(style = NumberFormat.Style.CURRENCY)
private Double balance;
/**
* 工资 10,000.00
*/
@NumberFormat(pattern = "#,###,##")
private Double salary;
/**
* 任务完成比 90%
*/
@NumberFormat(style = NumberFormat.Style.PERCENT)
private Double taskCount;
private String[] hobbies;
}
2.4、最后展示的jsp
<%@ taglib prefix="spring" uri="http://www.springframework.org/tags" %>
<%--
Created by IntelliJ IDEA.
User: dujlc
Date: 2021/6/3
Time: 20:36
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
`<p>
id:${user.id} <br/>
</p>
<p>
userName:${user.userName} <br/>
</p>
<p>
birthday: <spring:eval expression="user.birthday"></spring:eval><br/>
</p>
<p>
balance:<spring:eval expression="user.balance"></spring:eval> <br/>
</p>
<p>
salary:<spring:eval expression="user.salary"></spring:eval> <br/>
</p>
<p>
taskCount:<spring:eval expression="user.taskCount"></spring:eval> <br/>
</p>
<p>
hobbies: <spring:eval expression="user.hobbies"></spring:eval> <br/>
</p>
</body>
</html>
3、数据格式化(hibernate-validate)
3.1、描述
前端数据校验有风险,所以后端也需要校验。
JSR303是Java为Bean数据合法性校验提供的标准,它已经包含在JavaEE6.0中。JSR303是通过在Bean属性上标注类似于@NotNull、@Max等标准的注解指定校验规则。
这个时候我们就需要了解一个hibernate-validate的东西,这个就是对我们的数据进行校验的。
所以我们需要导入hibernate-validate的依赖才可以去使用其中的注解,在mvn仓库中找到以下依赖并导入。
3.2、使用普通标签实现
1、加入hibernate-validate的依赖。
2、一定要注意!!将新加入的jar包加入到WEB-INF的lib文件夹下。
3、在javaBean的属性上面加上对应的注解,可以设置message属性提供更友好的提示信息。(特别注意:添加注解时导入的包一定时import javax.validation.constraints.下面的。)
4、在需要验证的对应的方法的参数上加上@Valid注解。
5、如果需要在当前页面显示错误,不需要直接抛出错误页面,可以参数中写入BindingResult result参数。
下面有注解示例和代码示例:
@Valid | 被注释的元素是一个对象,需要检查此对象的所有字段值 |
@Null | 被注释的元素必须为 null |
@NotNull | 被注释的元素必须不为 null |
@AssertTrue | 被注释的元素必须为 true |
@AssertFalse | 被注释的元素必须为 false |
@Min(value) | 指定最小值 |
@Max(value) | 指定最大值 |
@DecimalMin(value) | 指定最小值(且必须是数字) |
@DecimalMax(value) | 指定最大值(且必须是数字) |
@Size(max, min) | 指定的元素必须在某范围内 |
@Digits (integer, fraction) | 指定的元素必须在某范围内(且必须是数字) |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注释的元素必须符合指定的正则表达式 |
1、Person实体类
@NotNull
@Min(1)
private Integer id;
@NotEmpty
private String userName;
@Past(message = "输入的日期不能大于当前日期。")
private Date birthday;
private Double balance;
@Range(min = 2000,max = 10000)
private Double salary;
@Range(min = 0,max = 1)
private Double taskCount;
private String[] hobbies;
2、控制器类
/**
* @author dujlc
*
* 基于原生form表单实现方式:
* 1、在将错误信息循环通过map存入到request域中
* 2、在jsp通过 ${errors.id} 获取到对应的错误信息
*/
@Controller
public class PersonController {
@RequestMapping("/addPerson")
public String add(@Valid Person person, BindingResult result, Model model){
/*
将错误信息取出来,输出到jsp页面
*/
// 判断当前是否出现了错误
if(result.hasErrors()){
// 存放错误信息:key=错误信息的属性 value=错误信息
// 这样就有利于在jsp中分别取出${errors.id}
Map<String,String> errors = new HashMap<String, String>();
// 获取所有的错误信息 包含 错误的属性,错误信息
List<FieldError> fieldErrors = result.getFieldErrors();
// 循环转移到Map中
for(FieldError fieldError : fieldErrors){
// fieldError.getField()是属性名
// fieldError.getDefaultMessage()是错误信息
errors.put(fieldError.getField(),fieldError.getDefaultMessage());
}
model.addAttribute("errors",errors);
// 如果验证失败, 将请求重新转发到添加页面
// 当重新跳转时,我们的jsp页面上的值全都会存在request域中,直接取出来放到页面即可
// <input type="text" name="salary" value="${person.salary}"/>
// 就比如上面的 value="${person.salary}"
return "user/addPerson";
}
System.out.println(person);
return "showPerson";
}
}
3、跳转之前的页面
<h1>添加用户</h1>
<form action="${pageContext.request.contextPath}/addPerson" method="post">
<p>
id:<input type="text" name="id" value="${person.id}"/><span style="color: red; ">${errors.id}</span>
</p>
<p>
userName:<input type="text" name="userName" value="${person.userName}"/><span style="color: red; ">${errors.userName}</span>
</p>
<p>
birthday:<input type="text" name="birthday" value="${person.birthday}"/><span style="color: red; ">${errors.birthday}</span>
</p>
<p>
balance:<input type="text" name="balance" value="${person.balance}"/><span style="color: red; ">${errors.balance}</span>
</p>
<p>
salary:<input type="text" name="salary" value="${person.salary}"/><span style="color: red; ">${errors.salary}</span>
</p>
<p>
taskCount:<input type="text" name="taskCount" value="${person.taskCount}"/><span style="color: red; ">${errors.taskCount}</span>
</p>
<p>
hobbies:<input type="checkbox" name="hobbies" name="唱歌" checked="true"/>唱歌
<input type="checkbox" name="hobbies" name="跳舞" checked="true"/>跳舞
</p>
<p>
<input type="submit" value="提交"/>
</p>
</form>
4、跳转之后的页面
<body>
<p>
id:${person.id} <br/>
</p>
<p>
userName:${person.userName} <br/>
</p>
<p>
birthday: <spring:eval expression="person.birthday"></spring:eval><br/>
</p>
<p>
balance:<spring:eval expression="person.balance"></spring:eval> <br/>
</p>
<p>
salary:<spring:eval expression="person.salary"></spring:eval> <br/>
</p>
<p>
taskCount:<spring:eval expression="person.taskCount"></spring:eval> <br/>
</p>
<p>
hobbies: <spring:eval expression="person.hobbies"></spring:eval> <br/>
</p>
</body>
3.3、使用form标签实现
jsp中导入form的标签库
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
1、给所有的form表单前面加上form:
2、将表单内的属性改成如下样式:
<form:input path="id"></form:input><form:errors path="id"></form:errors>
3、在控制器类中添加一个显示jsp的处理方法,一定要传入一个空的Person对象到Model中。
4、在form标签上一定要加上modelAttribute标签,modelAttribute的值必须是第三步控制器中传入进来的。
1、Person实体类
@NotNull
@Min(1)
private Integer id;
@NotEmpty
private String userName;
@Past(message = "输入的日期不能大于当前日期。")
private Date birthday;
private Double balance;
@Range(min = 2000,max = 10000)
private Double salary;
@Range(min = 0,max = 1)
private Double taskCount;
private String[] hobbies;
2、控制器类
@GetMapping("/person/add")
public String addView(Person person){
return "/user/addPerson";
}
@RequestMapping("/formAddPerson")
public String formAdd(@Valid Person person, BindingResult result, Model model){
/*
将错误信息取出来,输出到jsp页面
*/
// 判断当前是否出现了错误
if(result.hasErrors()){
return "user/addPerson";
}
System.out.println(person);
return "showPerson";
}
3、跳转之前的页面
<h1>添加form用户</h1>
<form:form action="${pageContext.request.contextPath}/formAddPerson" method="post" modelAttribute="person">
<p>
id:<form:input path="id"></form:input><form:errors path="id"></form:errors>
</p>
<p>
userName:<form:input path="userName"></form:input><form:errors path="userName"></form:errors>
</p>
<p>
birthday:<form:input path="birthday"></form:input><form:errors path="birthday"></form:errors>
</p>
<p>
balance:<form:input path="balance"></form:input><form:errors path="balance"></form:errors>
</p>
<p>
salary:<form:input path="salary"></form:input><form:errors path="salary"></form:errors>
</p>
<p>
taskCount:<form:input path="taskCount"></form:input><form:errors path="taskCount"></form:errors>
</p>
<p>
hobbies:
<form:checkbox path="hobbies" value="唱歌"></form:checkbox>
<form:label path="hobbies">唱歌</form:label>
<form:checkbox path="hobbies" value="跳舞"></form:checkbox>
<form:label path="hobbies">跳舞</form:label>
</p>
<p>
<input type="submit" value="提交"/>
</p>
</form:form>
4、跳转之后的页面
<body>
<p>
id:${person.id} <br/>
</p>
<p>
userName:${person.userName} <br/>
</p>
<p>
birthday: <spring:eval expression="person.birthday"></spring:eval><br/>
</p>
<p>
balance:<spring:eval expression="person.balance"></spring:eval> <br/>
</p>
<p>
salary:<spring:eval expression="person.salary"></spring:eval> <br/>
</p>
<p>
taskCount:<spring:eval expression="person.taskCount"></spring:eval> <br/>
</p>
<p>
hobbies: <spring:eval expression="person.hobbies"></spring:eval> <br/>
</p>
</body>
特点:
1、支持全部http请求,比如method=“put” put\delete等提交方式,当服务器在编译form表单的时候,如果我们写了put或者delete,就会自动给我们加入隐藏的标签行。
2、数据自动回显:需要使用modelAttribute指定数据的对象。
3、使用path双向绑定属性。
4、Select、checkboxs、radiobottons、都可以使用Items指定数据源,可以是list(当List的泛型是JavaBean的时候,需要指定itemValue和itemLable),map(不需要指定itemValue和itemLable)。
5、初始化需要用数组或者List。
List和Map举例:
// 控制器
/*List list = Arrays.asList("唱歌","跳舞","打篮球");
model.addAttribute("list",list);*/
Map<String,String> map = new HashMap<String, String>();
map.put("1","唱歌");
map.put("2","跳舞");
map.put("3","打乒乓球");
model.addAttribute("list",map);
// jsp文件
<form:checkboxes path="hobbies" items="${list}"></form:checkboxes>