概述:
Spring的Web框架就是为了帮你解决这些关注点而设计的。SpringMVC基于模型-视图-控制器(Model-View-Controller,MVC)模式实现,它能够帮你构建像Spring框架那样灵活和松耦合的Web应用程序。
5.1 搭建SpringMVC
配置DispatcherServlet
这个不是基于web,而是通过java类来配置
package com.jack.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
/**
* 在Servlet3.0环境中,容器会在类路径中查询实现
* javax.servlet.ServletContainerInitializer 接口的类,如果发现的话,就会用它来配置Servlet容器
* @author Administrator
*
*/
public class SpittrWebAppInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer{
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[]{RootConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[]{WebConfig.class};
}
/*
* 将DispatchServlet映射到"/"
* (non-Javadoc)
* @see org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer#getRootConfigClasses()
*/
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
}
简单来说,tomcat会自动加载实现AbstractAnnotationConfigDispatcherServletInitializer 类
1.配置DispatcherServlet请求映射
2.配置ApplicationContext
2.配置webApplicationContext
package com.jack.config;总结:@EnableWebMvc 启动SpringMVC @ComponentScan 配置扫描bean,
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
/**加载Web相关的bean
*
* @author Administrator
*
*/
@Configuration
@EnableWebMvc //相当于<mvc:annotation-driven> 启用SpringMVC
@ComponentScan("com.jack") //启用组件扫描包名
public class WebConfig
extends WebMvcConfigurerAdapter{
/**
* 配置JSP视图解析器
* @return
* /WEB-INF/views/home.jsp
*/
@Bean
public ViewResolver viewResolver(){
InternalResourceViewResolver resolver =
new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
}
/**
* 新的WebConfig类还扩展了WebMvcConfigurerAdapter并重写了其configureDefaultServletHandling()方法。通过调用DefaultServlet-HandlerConfigurer的enable()方法,
* 我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,
* 而不是使用DispatcherServlet本身来处理此类请求。
* (non-Javadoc)
* @see org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter#configureDefaultServletHandling(org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer)
*/
@Override
public void configureDefaultServletHandling( DefaultServletHandlerConfigurer configurer){
configurer.enable();
}
}
在配置视图解析器和静态资源过滤给默认Servlet
package com.jack.config;开始写简单的控制类
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@Configuration
@ComponentScan(basePackages={"com.jack"},
excludeFilters={@Filter(type=FilterType.ANNOTATION, value=EnableWebMvc.class)})
public class RootConfig {
}
package com.jack.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller //声明为一个控制器
public class HomeController {
@RequestMapping(value={"/","/homepage"}, method=RequestMethod.GET) //处理"/"的GET请求
public String home(){
return "home"; //视图名为home
}
}
总结:
1.注意在类上写上@Controller
2.在方法写url路径的映射@RequestMapping(value={"/","homepage"}) 表示 "/" 和 "homepage" 都会被这个控制器处理
3.返回"home"会被视图解析器处理变成/WEB-INF/views/home.jsp
测试类:
package com.jack.controller;
import static org.junit.Assert.assertEquals;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
public class HomeControllerTest {
@Test
public void testHomePage() throws Exception{
HomeController controller = new HomeController();
assertEquals("home", controller.home());
}
/**
*
* 这里需要注意一下standaloneSetup是静态方法
* get("/") view() 抽象类中会有很多静态方法,虽然
* 抽象不能new,但是方法可以创建对象
* @throws Exception
*/
@Test
public void testHomePageRequest() throws Exception{
HomeController controller = new HomeController();
MockMvc mockMvc =
standaloneSetup(controller).build();
mockMvc.perform(get("/homepage"))
.andExpect(view().name("home"));
}
}
总结:
1.第一个方法是简单方法测试,第二个是模拟请求测试
2.注意standaloneSetup() 和 get() 以及view()都是静态方法
3.其实你发现它,模拟操作过程,
MockMvcBuilders(设置)——》MockMvcRequestBuilders(请求)--》MockMvcResultMatchers(匹配视图)
写个一个类模拟数据库数据
首先接口:
package com.jack.data;实现类
import java.util.List;
public interface SpittleRepository {
List<Spittle> findSpittles(long max, int count);
}
package com.jack.data.impl;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.springframework.stereotype.Component;
import com.jack.data.Spittle;
import com.jack.data.SpittleRepository;
@Component
public class SpittleRepositoryImpl implements SpittleRepository{
@Override
public List<Spittle> findSpittles(long max, int count) {
List<Spittle> list = new ArrayList<Spittle>();
Spittle sp1 = new Spittle("第一个信息", new Date(),100.00, 40.102);
Spittle sp2 = new Spittle("第二个信息", new Date());
Spittle sp3 = new Spittle("第三个信息", new Date());
Spittle sp4 = new Spittle("第四个信息", new Date());
list.add(sp4);
list.add(sp3);
list.add(sp1);
list.add(sp2);
return list;
}
}
控制类:
package com.jack.controller;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.jack.data.Spittle;
import com.jack.data.SpittleRepository;
@Controller
@RequestMapping("/spittles")
public class SpittleController {
private SpittleRepository spittleRepository;
@Autowired
public SpittleController(SpittleRepository spittleRepository){
this.spittleRepository = spittleRepository;
}
/*@RequestMapping(method=RequestMethod.GET)
public String spittles(Model model) {
//将spittle添加到模型中
//方式一
//注意这里没有key,它可以根据List<Spittle> 推断 key = spittleList
model.addAttribute(
spittleRepository.findSpittles(
Long.MAX_VALUE, 20));
//方式二
//显式指定key
model.addAttribute("spittleList", spittleRepository.findSpittles(Long.MAX_VALUE, 20));
//返回视图名
return "spittles";
}*/
//方式三
//它会根据请求/spittles,判断 视图为spittles
/*@RequestMapping(method=RequestMethod.GET)
public List<Spittle> spittles(){
return spittleRepository.findSpittles(Long.MAX_VALUE, 20);
}*/
//方法四
@RequestMapping(method=RequestMethod.GET)
public String spittles(Map model){
model.put("spittleList",
spittleRepository.findSpittles(Long.MAX_VALUE, 20));
return "spittles";
}
}
总结:
1.这么多方法可以表示说明它有依据
2.依据请求路径获取视图
3.根据返回数据推断key
4.model底层是Map数据格式
mock测试类
package com.jack.controller;
import static org.hamcrest.core.IsCollectionContaining.hasItems;
//这要引入新的mockito-all.jar
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.web.servlet.view.InternalResourceView;
import com.jack.data.Spittle;
import com.jack.data.SpittleRepository;
public class SpittleControllerTest {
@Test
public void shouldShowRecentSpittles() throws Exception{
//创建模拟数据
List<Spittle> expectedSpittles = createSpittleList(20);
//模拟的类
SpittleRepository mockRepository =
mock(SpittleRepository.class);
//模拟类中的方法,只要是调用findSpittles就返回 expectedSpittles数据
when(mockRepository.findSpittles(Long.MAX_VALUE, 20))
.thenReturn(expectedSpittles);
//往控制类注入数据类
SpittleController controller =
new SpittleController(mockRepository);
//设置模拟的controller
MockMvc mockMvc = standaloneSetup(controller)
.setSingleView( //表示不解析
new InternalResourceView("/WEB-INF/views/spittles.jsp"))
.build();
//请求路径/spittles
mockMvc.perform(get("/spittles"))
.andExpect(view().name("spittles")) //判断视图是否为spittles
.andExpect(model().attributeExists("spittleList")) //是否存在这个属性ID
.andExpect(model().attribute("spittleList",
hasItems(expectedSpittles.toArray()))); //判断数据是否一致
}
private List<Spittle> createSpittleList(int count) {
List<Spittle> spittleList = new ArrayList<Spittle>();
for(int i=0; i< count; i++) {
spittleList.add(new Spittle("Spittle" + i, new Date()));
}
return spittleList;
}
}
总结:
1.引用包Mockito
2.发现测试模拟都是静态类,不熟悉都不知道在哪个包下,很尴尬
import static org.hamcrest.core.IsCollectionContaining.hasItems;
//这要引入新的mockito-all.jar
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
编写spittles.jsp文件
<%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<%@ page language="java" import="java.util.*" 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>RecentSpittles</title>
<link rel="stylesheet"
type="text/css"
href="<c:url value="/resources/style.css"/>">
</head>
<body>
<h1>Recent Spittles</h1>
<c:forEach items="${spittleList }" var="spittle">
<li id="spittle_<c:out value="spittle.id"/>">
<div class="spittleMessage">
<c:out value="${spittle.message}"></c:out>
</div>
<div>
<span class="spittleTime"><c:out value="${spittle.time }"/></span>
<span class="spittleLocation">
(<c:out value="${spittle.latitude }"/>,
<c:out value="${spittle.longitude }"></c:out>)
</span>
</div>
</li>
</c:forEach>
</body>
</html>
总结:
1、这里要引用jstl-1.2.jar包
2、同时要添加这个一句话<%@ page language="java" import="java.util.*" pageEncoding="UTF-8" %>不然中文乱码
3、当要用外部包的标签的时候首先导入uri,设置前缀prefix 例如 <%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>
4、"" 里面可以设置标签能够识别,例如:<li id="spittle_<c:out value="spittle.id"/>">
5、对于forEach items="${spittleList}" 遍历的属性的key,而var="spittle"遍历处理的单个对象,注意${}是指在引号内
6、对于对象的属性直接可以用对象.属性的来获取值
7、对于jsp输出标签为<c:out value="输入内容"/>
效果为:
5.2 接受请求的输入
传入的方式:
- 查询参数(Query Paramter)
- 表单参数(Form Parameter)
- 路径变量(Path Variable)
5.2.1处理查询参数
测试类:
@Test总结:在路径后面 加上 ?+键值对 + 连接符(&)+键值对 例如 /spittles?max=238900&count=50
public void shouldShowPagedSpittles() throws Exception {
List<Spittle> expectedSpittles = createSpittleList(50);
SpittleRepository mockRepository = mock(SpittleRepository.class);
when(mockRepository.findSpittles(238900, 50))
.thenReturn(expectedSpittles);
SpittleController controller =
new SpittleController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller)
.setSingleView(
new InternalResourceView("/WEB-INF/views/spittles.jsp")
)
.build();
mockMvc.perform(get("/spittles?max=238900&count=50"))
.andExpect(view().name("spittles"))
.andExpect(model().attributeExists("spittleList"))
.andExpect(model().attribute("spittleList", hasItems(expectedSpittles.toArray())));
}
Controller类:
package com.jack.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import com.jack.data.SpittleRepository;
@Controller
@RequestMapping("/spittles")
public class SpittleController {
private SpittleRepository spittleRepository;
private static final String MAX_LONG_AS_STRING = Long.MAX_VALUE+"";
@Autowired
public SpittleController(SpittleRepository spittleRepository){
this.spittleRepository = spittleRepository;
}
@RequestMapping(method=RequestMethod.GET)
//@RequestParam("max") long max,@RequestParam("count") int count
public String spittles(Model model, @RequestParam(value="max", defaultValue=MAX_LONG_AS_STRING) long max,
@RequestParam(value="count", defaultValue="20") int count) {
//注意这里没有key,它可以根据List<Spittle> 推断 key = spittleList
model.addAttribute(
spittleRepository.findSpittles(
max, count));
//返回视图名
return "spittles";
}
}
总结:用注解 @RequestParam,可以指定默认值, defaultValue ,注意defaultValue是字符串,所以先转成字符串,再转成目标类型
5.1.2.路径传值:
测试方法:
@Test控制类的方法
public void testSpitte() throws Exception{
Spittle expectedSpittle = new Spittle("Hello", new Date());
SpittleRepository mockRepository = mock(SpittleRepository.class);
when (mockRepository.findOne(123456)).thenReturn(expectedSpittle);
SpittleController controller = new SpittleController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(get("/spittles/123456"))
.andExpect(view().name("spittle"))
.andExpect(model().attributeExists("spittle"))
.andExpect(model().attribute("spittle", expectedSpittle));
}
@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)
public String spittle(@PathVariable("spittleId") long spittleId,
Model model){
model.addAttribute(spittleRepository.findOne(spittleId));
return "spittle";
}
spittle.jsp
<%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>SpittleRepository.java 接口增加方法
<%@ page session="false" %>
<%@ page language="java" import="java.util.*" 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>RecentSpittles</title>
<link rel="stylesheet"
type="text/css"
href="<c:url value="/resources/style.css"/>">
</head>
<body>
<h1>Recent Spittle</h1>
<div class="spittleView">
<div class="spittleMessage">
<c:out value="${spittle.message }"></c:out>
</div>
<div>
<span class="spittleTime">
<c:out value="${spittle.time }"></c:out>
</span>
</div>
</div>
</body>
</html>
Spittle findOne(long i);
SpittleRepositoryImpl.java 实现接口方法
@Override结果:
public Spittle findOne(long i) {
return new Spittle("第一个微博" , new Date(), 100.0,100.0);
}
5.1.3.表单传递数据
测试类:
package com.jack.controller;总结:
//这要引入新的mockito-all.jar
import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view;
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
import org.junit.Test;
import org.springframework.test.web.servlet.MockMvc;
import com.jack.data.Spitter;
import com.jack.data.SpitterRepository;
public class SpittlerControllerTest {
@Test
public void shouldShowRegistration() throws Exception{
SpittlerController controller = new SpittlerController();
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(get("/spittler/register"))
.andExpect(view().name("registerForm"));
}
@Test
public void shouldProcessRegistration() throws Exception {
SpitterRepository mockRepository =
mock(SpitterRepository.class);
Spitter unsaved =
new Spitter("Jack", "Bauer", "jbauer", "24hours");
Spitter saved =
new Spitter(24L,"Jack", "Bauer", "jbauer", "24hours");
when(mockRepository.save(unsaved)).thenReturn(saved);
SpittlerController controller =
new SpittlerController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(post("/spitter/register")
.param("firstName", "Jack")
.param("lastName", "Bauer")
.param("username", "jbauer")
.param("password", "24hours"))
.andExpect(redirectedUrl("/spitter/jbauer"));
verify(mockRepository, atLeastOnce()).save(unsaved); //校验保存情况
}
}
1、总会发现老外首先写的测试类,然后才是写代码,测试驱动,可以学习一下
2、注册过程是,首先显示一个表单页(registerForm.jsp)——》处理表单请求控制器("/spitter/register")--》简短的呈现页 (profile.jsp)
3、测试类差不多就是静态方法,链式方法
4、redirectedUrl("/spitter/jbauer") 重定向防止重复提交
5、verify验证repository保存方法,是否正确
控制类
package com.jack.controller;总结:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import com.jack.data.Spitter;
import com.jack.data.SpitterRepository;
@Controller
@RequestMapping("/spitter")
public class SpittlerController {
private SpitterRepository spitterRepository;
public SpittlerController(){}
@Autowired
public SpittlerController(SpitterRepository spitterRepository){
this.spitterRepository = spitterRepository;
}
@RequestMapping(value = "/register", method=RequestMethod.GET)
public String showRegistrationForm(){
return "registerForm";
}
@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegistration(Spitter spitter){
spitterRepository.save(spitter);
return "redirect:/spitter/" + spitter.getUsername();
}
@RequestMapping(value="/{username}", method=RequestMethod.GET)
public String showSpitterProfile(
@PathVariable String username, Model model){
Spitter spitter = spitterRepository.findByUsername(username);
model.addAttribute(spitter);
return "profile";
}
}
1、虽然请求路径一样,请求方式不一样 ,例如两个register
2、redirect:/spitter/ 重定向方法
3、最后返回视图profile
package com.jack.data;
public interface SpitterRepository {
Spitter save(Spitter spitter);
Spitter findByUsername(String username);
}
package com.jack.data.impl;import org.springframework.stereotype.Component;import com.jack.data.Spitter;import com.jack.data.SpitterRepository;@Componentpublic class SpitterRepositoryImpl implements SpitterRepository{@Overridepublic Spitter save(Spitter spitter) {System.out.println("保存成功");return null;}@Overridepublic Spitter findByUsername(String username) {Spitter spitter =new Spitter("Jack", "Bauer", "jbauer", "24hours");return spitter;}}
总结:这里没有具体实现数据库交互
实体类:
package com.jack.data;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Spitter {
private long l;
private String firstName;
private String lastName;
private String username;
private String password;
public Spitter() {
super();
// TODO Auto-generated constructor stub
}
public Spitter(String firstName, String lastName, String username, String password) {
this.firstName = firstName;
this.lastName = lastName;
this.username = username;
this.password = password;
}
public Spitter(long l, String firstName, String lastName, String username, String password) {
this.l = l;
this.firstName = firstName;
this.lastName = lastName;
this.username = username;
this.password = password;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public String getUsername() {
return username;
}
public String getPassword() {
return password;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public long getL() {
return l;
}
public void setL(long l) {
this.l = l;
}
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, "firstName", "lastName");
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "firstName", "lastName");
}
@Override
public String toString() {
return "Spitter [l=" + l + ", firstName=" + firstName + ", lastName=" + lastName + ", username=" + username
+ ", password=" + password + "]";
}
}
profile.jsp
<%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<!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>Spittr</title>
<link rel="stylesheet"
type="text/css"
href="<c:url value="/resources/style.css"/>">
</head>
<body>
<h1>Your Profile</h1>
<c:out value="${spitter.username }"></c:out><br/>
<c:out value="${spitter.firstName }"></c:out>
<c:out value="${spitter.lastName }"></c:out>
</body>
</html>
<%@ tagliburi="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<%@ page language="java" import="java.util.*" 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>RegisterPage</title>
<link rel="stylesheet"
type="text/css"
href="<c:url value="/resources/style.css"/>">
</head>
<body>
<h1>注册</h1>
<form action="" method="POST">
First Name:<input type="text" name="firstName"/><br/>
Last Name:<input type="text" name="lastName" /> <br/>
UserName: <input type="text" name="username"/><br/>
Password: <input type="password" name="password"/><br/>
<input type="submit" value="Register" />
</form>
</body>
</html>
5.3校验表单
Spring 校验 Java Validation API 又称 JSR-303 Hibernate Validator Java校验API javax.validation.constraints包下- @AssertFalse 所注解的元素必须是Boolean类型,并且值为false
- @AssertTrue 所有注解的元素必须是Boolean类型, 并且值为true
- @DecimalMax 所有注解的元素必须是数字,并且它的值要小于或等于给定的BigDecimalString值
- @DecimalMin 所注解的元素必须是数字,并且它的值要大于或者等于给定的BigDecimalString值
- @Digits 所注解的元素必须是数字,并且它的值必须指定位数
- @Future 所注解的元素的值必须是一个将来的日期
- @Max 所注解的元素必须是数字,并且它的值要小于或等于给定的值
- @Min 所注解的元素必须是数字,并且它的值要大于或等于给定的值
- @NotNull 所注解元素的值必须不能为null
- @Null 所注解元素的值必须为null
- @Past 所注解的元素的值必须是一个已过去的日期
- @Pattern 所注解的元素的值必须匹配给定的正则表达式
- @Size 所注解的元素的值必须是String、集合或数组,并且它的长度要符合给定的范围
引入jar
<!-- https://mvnrepository.com/artifact/javax.validation/validation-api -->
<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.4.1.Final</version>
</dependency>
修改Spitter.java
@NotNull
@Size(min=2, max=30)
private String firstName;
@NotNull
@Size(min=2, max=30)
private String lastName;
@NotNull
@Size(min=5, max=16)
private String username;
@NotNull
@Size(min=5, max=25)
private String password;
修改控制类
//不满足要求自动跳转表单页
@RequestMapping(value="/register", method=RequestMethod.POST)
public String processRegistration( @Valid Spitter spitter,
Errors errors){
if(errors.hasErrors()) {
return "registerForm";
}
spitterRepository.save(spitter);
return "redirect:/spitter/" + spitter.getUsername();
}
总结:影响最深就是先写测试类,然后写代码。测试驱动
用例Demo