Spring实战第五章学习笔记————构建Spring Web应用程序

时间:2024-04-30 21:37:38

Spring实战第五章学习笔记————构建Spring Web应用程序

Spring MVC基于模型-视图-控制器(Model-View-Controller)模式实现,它能够构建像Spring框架那样灵活和松耦合的Web应用程序。

Spring MVC起步

跟踪Spring MVC的请求

aaarticlea/png;base64,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" alt="image">

请求的第一站是Spring的DispatcherServlet。与大多数基于Java的Web框架一样,Spring MVC所有的请求都会通过一个前端控制器(front controller)Servlet。前端控制器DispatcherServlet的任务是将请求发送给Spring MVC控制器。而控制器是一个用于处理请求的Spring组件。而DispatcherServlet会先查询一个或多个处理器映射来确定请求的下一站是哪儿。处理器映射会根据请求携带的URL信息来进行决策。一旦选择了合适的控制器,DispatcherServlet会将请求发送给选中的控制器。到了控制器,请求会卸下其负载(用户提交的信息)并耐心等待控制器处理这些信息。控制器在完成逻辑处理后,通常会产生一些信息,这些信息需要返回给用户并在浏览器上显示。这些信息被称为模型(model)。不过仅仅给用户返回原始的信息是不够的——这些信息需要以用户友好的方式进行格式化,一般会是HTML。所以,信息需要发送给一个视图 (view),通常会是JSP。控制器所做的最后一件事就是将模型数据打包,并且标示出用于渲染输出的视图名。它接下来会将请求连同模型和视图名发送回DispatcherServlet 。

 这样,控制器就不会与特定的视图相耦合,传递给DispatcherServlet的视图名并不直接表示某个特定的JSP。实际上,它甚至并不能确定视图就是JSP。相反,它仅仅传递了一个 逻辑名称,这个名字将会用来查找产生结果的真正视图。DispatcherServlet将会使用视图解析器(view resolver) 来将逻辑视图名匹配为一个特定的视图实现,它可能是也可能不是JSP。既然DispatcherServlet已经知道由哪个视图渲染结果,那请求的任务基本上也就完成了。它的最后一站是视图的实现(可能是JSP),在这里它交付模型数据。请求的任务就完成了。视图将使用模型数据渲染输出,这个输出会通过响应对象传递给客户端。

搭建Spring MVC

在本书中关于SpringMVC的配置都采用了Java注解的方法。配置DIspatcherServlet:

package main.java.com.wbw.spittr.config;

import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;

public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer
{
@Override //会验证@Override下面的方法名是否是你父类中所有的,如果没有则报错 protected String[] getServletMappings() {
return new String[] { "/" };//将DispatcherServlet映射到"/"
}
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { com.wbw.spittr.config.RootConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { com.wbw.spittr.config.WebConfig.class };//指定配置类
}
}

扩展AbstractAnnotationConfigDispatcherServletInitializer的任何类都会自动的配置DispatcherServlet和Spring应用上下文。该程序重写了三个方法。第一个方法是getRootConfigClasses(),它将一个和多个路径映射到DispatcherServlet上。在本例中,它映射的是“/”,这表示它会是应用的默认Servlet。它会处理进入应用的所有请求。当DispatcherServlet启动的时候,它会创建Spring应用上下文,并加载配置文件或配置类中所声明的bean。在程序清单5.1的getServletConfigClasses()方法中,我们要求DispatcherServlet加载应用上下文时,使用定义在WebConfig配置类(使用Java配置)中的bean。

  但是在Spring Web应用中,通常还会有另外一个应用上下文。另外的这个应用上下文是由ContextLoaderListener创建的。

  我们希望DispatcherServlet加载包含Web组件的bean,如控制器、视图解析器以及处理器映射,而ContextLoaderListener要加载应用中的其他bean。这些bean通常是驱动应后端的中间层和数据层组件。

  实际上,AbstractAnnotationConfigDispatcherServletInitializer会同时创建DispatcherServlet和ContextLoaderListener。GetServletConfigClasses()方法返回的带有@Configuration注解的类将会用来定义DispatcherServlet应用上下文中的bean。getRootConfigClasses()方法返回的带有@Configuration注解的类将会用来配置ContextLoaderListener创建的应用上下文中的bean。

最小但可用的Spring MVC:

package main.java.com.wbw.spittr.config;

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; @Configuration
@EnableWebMvc //启动spring mvc
@ComponentScan("spitter.web") // 启动组件扫描
public class WebConfig extends WebMvcConfigurerAdapter
{ // 配置JSP视图解析器
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB_INF/views/");
resolver.setSuffix(".jsp");
resolver.setExposeContextBeansAsAttributes(true);
return resolver;
} @Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();//配置静态资源的处理
}
}

接下来,我们添加了一个ViewResolver bean。更具体来讲,是InternalResourceViewResolver。我们将会在第6章更为详细地讨论视图解析器。我们只需要知道它会查找JSP文件,在查找的时候,它会在视图名称上加一个特定的前缀和后缀(例如,名为home的视图将会解析为WEB-INFviews/home.jsp)。

  最后,新的WebConfig类还扩展了WebMvcConfigurerAdapter并重写了其configureDefaultServletHandling()方法。通过调用DefaultServletHandlerConfigurer的enable()方法,我们要求DispatcherServlet将对静态资源的请求转发到Servlet容器中默认的Servlet上,而不是使用DispatcherServlet本身来处理此类请求。

RootConfig

package main.java.com.wbw.spittr.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 = { "spitter" }, excludeFilters = {
@Filter(type = FilterType.ANNOTATION, value = EnableWebMvc.class) })
public class RootConfig {
}

编写基本的控制器

在SpringMVC中,控制器只是方法上添加了@RequestMapping注解的类,这个注解声明了所处理的请求。

package main.java.com.wbw.spittr.web;

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 = "/", method = RequestMethod.GET) // 处理GET请求
public String home() {
return "home";
} }

可能注意到的第一件事情就是HomeController带有@Controller注解。很显然这个注解是用来声明控制器的,但实际上这个注解对Spring MVC本身的影响并不大。     HomeController是一个构造型(stereotype)的注解,它基于@Component注解。在这里,它的目的就是辅助实现组件扫描。因为HomeController带有@Controller注解,因此组件扫描器会自动找到HomeController,并将其声明为Spring应用上下文中的一个bean。

  其实,你也可以让HomeController带有@Component注解,它所实现的效果是一样的,但是在表意性上可能会差一些,无法确定HomeController是什么组件类型。

  HomeController唯一的一个方法,也就是home()方法,带有@RequestMapping注解。它的value属性指定了这个方法所要处理的请求路径,method属性细化了它所处理的HTTP方法。在本例中,当收到对“/”的HTTP GET请求时,就会调用home()方法。

  你可以看到,home()方法其实并没有做太多的事情:它返回了一个String类型的“home”。这个String将会被Spring MVC解读为要渲染的视图名称。DispatcherServlet会要求视图解析器将这个逻辑名称解析为实际的视图。

  鉴于我们配置InternalResourceViewResolver的方式,视图名“home”将会解析为“WEB-INFviews/home.jsp”路径的JSP。

<%--
Created by IntelliJ IDEA.
User: wbw
Date: 2018/8/16
Time: 2:51
To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Spitter</title>
<link rel="stylesheet"
type="text/css"
href="<c:url value="/css/style.css" />" >
</head>
<body>
<h1>Welcome to Spitter</h1> <a href="<c:url value="/spittles" />">Spittles</a> |
<a href="<c:url value="/spitter/register" />">Register</a>
</body>
</html>

测试控制器

package test.java.com.wbw.spittr.web;

import org.junit.Test;
import main.java.com.wbw.spittr.web.HomeController; import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders; public class HomeControllerTest { @Test
public void testHopackage com.wbw.spittr.data; import com.wbw.spittr.Spittle; import java.util.List; public interface SpittleRepository { List<Spittle> findSpittles(long max, int count); }
mePage() throws Exception {
HomeController controller = new HomeController();
// 设置MockMvc
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
mockMvc.perform(MockMvcRequestBuilders.get("/")).andExpect(MockMvcResultMatchers.view().name("home"));
} }

它首先传递一个HomeController实例到MockMvcBuilders.standaloneSetup()并调用build()来构建MockMvc实例。然后它使用MockMvc实例来执行针对“/”的GET请求并设置期望得到的视图名称。

传递模型数据到视图中

在spittr应用中,我们需要有一个页面展现最近提交的Spittle列表。因此我们需要一个新的方法来处理这个页面。

首先定义一个数据访问的Repository。此时我们只需将其定义为一个接口,使其能获取Spittle列表。

package com.wbw.spittr.data;

import com.wbw.spittr.Spittle;

import java.util.List;

public interface SpittleRepository {

    List<Spittle> findSpittles(long max, int count);

}

findSpittles()方法接受两个参数。其中max代表所返回的Spittle中,属性Spittle ID的最大值,count表明要返回多少个Spittle对象。

Spittle类

package com.wbw.spittr;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import java.util.Date; public class Spittle { private final Long id;
private final String message;
private final Date time;
private Double latitude;
private Double longitude; public Spittle(String message, Date time) {
this(message, time, null, null);
} public Spittle(String message, Date time, Double longitude, Double latitude) {
this.id = null;
this.message = message;
this.time = time;
this.longitude = longitude;
this.latitude = latitude;
} public long getId() {
return id;
} public String getMessage() {
return message;
} public Date getTime() {
return time;
} public Double getLongitude() {
return longitude;
} public Double getLatitude() {
return latitude;
} @Override
public boolean equals(Object that) {
return EqualsBuilder.reflectionEquals(this, that, "id", "time");
} @Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "id", "time");
} }

EqualsBuilder和HashCodeBuilder 作用是自动化hashCode()和equals()。现在编写控制器SpittrController:

package com.wbw.spittr.web;

import com.wbw.spittr.data.SpittleRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; @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) {
model.addAttribute(spittleRepository.findSpittles(Long.MAX_VALUE,20));
return "spittles";
} }

可以看到构造器SpittleController使用了@Autowired注解,用来注入SpittleRepository。

而在spittles方法中给定一个Model做参数这样spittleRepository将获得的Spittle列表填充到模型中。Model就是一个Map。

spittles.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="s" uri="http://www.springframework.org/tags"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> <html>
<head>
<title>Spitter</title>
<link rel="stylesheet" type="text/css" href="<c:url value="/resources/style.css" />" >
</head>
<body>
<div class="spittleForm">
<h1>Spit it out...</h1>
<form method="POST" name="spittleForm">
<input type="hidden" name="latitude">
<input type="hidden" name="longitude">
<textarea name="message" cols="80" rows="5"></textarea><br/>
<input type="submit" value="Add" />
</form>
</div>
<div class="listTitle">
<h1>Recent Spittles</h1>
<ul class="spittleList">
<c:forEach items="${spittleList}" var="spittle" >
<li id="spittle_<c:out value="spittle.id"/>">
<div class="spittleMessage"><c:out value="${spittle.message}" /></div>
<div>
<span class="spittleTime"><c:out value="${spittle.time}" /></span>
<span class="spittleLocation">(<c:out value="${spittle.latitude}" />, <c:out value="${spittle.longitude}" />)</span>
</div>
</li>
</c:forEach>
</ul>
<c:if test="${fn:length(spittleList) gt 20}">
<hr />
<s:url value="/spittles?count=${nextCount}" var="more_url" />
<a href="${more_url}">Show more</a>
</c:if>
</div>
</body>
</html>

然后测试SpittleController处理针对“、spittles”的请求对象

@Test
public void shouldShowRecentSpittles() throws Exception {
List<Spittle> expectedSpittles = createSpittleList(20);
SpittleRepository mockRepository = mock(SpittleRepository.class);
when(mockRepository.findSpittles(Long.MAX_VALUE, 20))
.thenReturn(expectedSpittles); SpittleController controller = new SpittleController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller)
.setSingleView(new InternalResourceView("/WEB-INF/views/spittles.jsp"))
.build(); mockMvc.perform(get("/spittles"))
.andExpect(view().name("spittles"))
.andExpect(model().attributeExists("spittleList"))
.andExpect(model().attribute("spittleList",
hasItems(expectedSpittles.toArray())));
}

这个测试先创建了SpittleRepository接口的mock实现。这个实现会从它的findSpittles()方法中返回20个Spittle对象。

接受请求的输入

SpringMVC允许以多种方式将客户端中的数据传送到控制器的处理器方法中:

  • 查询方式(Query Parameter)。
  • 表单参数(Form Parameter)。
  • 路径变量(PathVariable)。

处理查询参数

在Spittr应用中我们需要处理一件事就是展现分页的Spittle列表。如果要让用户可以每次得到一页的spittle记录,那么就需要让用户可以通过某种方式将他们想看的spittle记录的参数传递到后台。

在浏览spittle时,如果想要查看下一页的spittle,那么就需要传递比当前页的最后一个spittle的id小一位的id,也可以传递想要展示的spittle的数量。

为了实现分页,需要编写一个控制器满足:

  • before参数,结果中的spittle的id都要在这个参数之前;
  • count参数,结果中要包含的spittle的个数

下面我们对上面的spittles()方法进行小小的改动,让它可以使用before和count参数。首先对测试方法进行改动:

 @Test
public void shouldShowRecentSpittles() throws Exception {
List<Spittle> expectedSpittles = createSpittleList(20);
SpittleRepository mockRepository = Mockito.mock(SpittleRepository.class);
Mockito.when(mockRepository.findSpittles(238900, 50)).thenReturn(expectedSpittles); SpittleController controller = new SpittleController(mockRepository);
MockMvc mockMvc = MockMvcBuilders.standaloneSetup(controller)
.setSingleView(new InternalResourceView("/WEB_INF/views/spittles.jsp")).build(); mockMvc.perform(MockMvcRequestBuilders.get("/spittles?max=238900&count=50"))
.andExpect(MockMvcResultMatchers.view().name("spittles"))
.andExpect(MockMvcResultMatchers.model().attributeExists("spittleList"))// model():得到模型验证器;
.andExpect(MockMvcResultMatchers.model().attribute("spittleList", IsCollectionContaining.hasItems(expectedSpittles.toArray())));
}

这个测试方法与之前的测试区别在于他针对“/Spittles”发送Get请求,同时传入max和count参数。他测试了这些参数存在时的处理器方法。这样我们就能确定处理器能够处理有参数和没参数两种类型的请求。此时SpittlleController要同时处理有参数和没参数的场景。那我们需要使用@RequestParam注解对其修改。

@RequestMapping(method = RequestMethod.GET)
public List<Spittle> spittles(
@RequestParam(value = "max",defaultValue = MAX_LONG_AS_STRING) long max,
@RequestParam(value = "count",defaultValue = "20") int count) {
return spittleRepository.findSpittles(max,count);
} private static final String MAX_LONG_AS_STRING ="9223372036854775807";

现在如果max参数没给定的话它将是Long类型的最大值。而查询参数都是String类型的,但当绑定到方法的max参数时,它会转化成Long类型。

通过路径参数接受输入

假设我们要根据给定的ID来展现某一个Spittle记录,那么可以使用@RequestMapping,来编写一个处理器方法:

RequestMapping(method=RequestMethod.POST)//接受ID作为查询参数
public String saveSpittle(@RequestParam("spittleID") long spittleID,Model model){ model.addAttribute(spittleRepository.findOne(spittleID));
return "spittle";
}

这个方法从面向资源的角度来说并不理想。我们之前编写的控制器所有的方法都映射到了静态定义好的路径上。但是这次编写的方法需包含变量。为了实现这种路径变量,SpringMVC允许我们在@RequestMapping路径中添加占位符,占位符的名称要用{}括住。路径中其他部分要与请求完全匹配但占位符部分可以是任意值。此时我们在编写可以将Spittle ID作为路径的Spittles方法。

@RequestMapping(value="/{spittleId}", method=RequestMethod.GET)
public String spittle(
@PathVariable("spittleId") long spittleId,
Model model) {
model.addAttribute(spittleRepository.findOne(spittleId));
return "spittle";
}

最后编写测试,判断控制器是否面向职员请求的处理。:

@Test
public void testSpittle() throws Exception {
Spittle expectedSpittle = new Spittle("Hello", new Date());
SpittleRepository mockRepository = mock(SpittleRepository.class);
when(mockRepository.findOne(12345)).thenReturn(expectedSpittle); SpittleController controller = new SpittleController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller).build(); mockMvc.perform(get("/spittles/12345"))//通过路经请求资源
.andExpect(view().name("spittle"))
.andExpect(model().attributeExists("spittle"))
.andExpect(model().attribute("spittle", expectedSpittle));
}

处理表单

Web应用经常会允许用户填充表单并将数据提交到应用中,SpringMVC对表单处理也提供了良好的支持。现在编写一个展现注册表单的控制器。

package com.wbw.spittr.web;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import static org.springframework.web.bind.annotation.RequestMethod.GET; @Controller
@RequestMapping("/Spitter")
public class SpitterController {
@RequestMapping(value="/regester",method= GET)
public String showRegeistrationForm(){
return "registerForm";
} }

对这个控制器编写测试:

@Test
public void shouldShowRegistration() throws Exception {
SpitterController controller = new SpitterController();
MockMvc mockMvc = standaloneSetup(controller).build();
mockMvc.perform(get("/Spitter/register"))
.andExpect(view().name("registerForm"));
}

编写处理表单的控制器

当处理注册表单的POST请求时,控制器需要接受表单数据并将数据保存为Spitter对象,这时我们要对控制器新添加一个方法来处理所提交的表单,代码如下:

package com.wbw.spittr.web;

import com.wbw.spittr.Spitter;
import com.wbw.spittr.data.SpitterRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping; import javax.validation.Valid; import static org.springframework.web.bind.annotation.RequestMethod.GET;
import static org.springframework.web.bind.annotation.RequestMethod.POST; @Controller
@RequestMapping("/Spitter")
public class SpitterController { private SpitterRepository spitterRepository; @Autowired
public SpitterController(SpitterRepository spitterRepository) {
this.spitterRepository = spitterRepository;
} @RequestMapping(value="/register", method=POST)
public String processRegistration(
@Valid Spitter spitter) { spitterRepository.save(spitter);
return "redirect:/spitter/" + spitter.getUsername();
} @RequestMapping(value="/register",method= GET)
public String showRegeistrationForm(){
return "registerForm";
} }

值得注意的是processRegistration()方法最后返回了一个String类型,用来指定视图。不仅返回了视图的名称而且返回的值还带有重定向的格式。当InternalResourceViewResover看到“redirect:”前缀时它会将其解析为重定向的规则。而当重定向到用户基本界面时,我们应该在添加一个处理器方法处理对基本信息页面的请求。

@RequestMapping(value="/{username}", method=GET)
public String showSpitterProfile(@PathVariable String username, Model model) {
Spitter spitter = spitterRepository.findByUsername(username);
model.addAttribute(spitter);
return "profile";
}

最后返回的profile视图代码如下:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
<title>Spitter</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}" /><br/>
<c:out value="${spitter.firstName}" /> <c:out value="${spitter.lastName}" /><br/>
</body>
</html>

然后对控制器进行测试:

@Test
public void shouldProcessRegistration() throws Exception {
SpitterRepository mockRepository = mock(SpitterRepository.class);
Spitter unsaved = new Spitter("jbauer", "24hours", "Jack", "Bauer");
Spitter saved = new Spitter(24L, "jbauer", "24hours", "Jack", "Bauer");
when(mockRepository.save(unsaved)).thenReturn(saved); SpitterController controller = new SpitterController(mockRepository);
MockMvc mockMvc = standaloneSetup(controller).build(); mockMvc.perform(post("/Spitter/register")
.param("firstName", "Jack")
.param("lastName", "Bauer")
.param("username", "jbauer")
.param("password", "24hours")
.param("email", "jbauer@ctu.gov"))
.andExpect(redirectedUrl("/Spitter/jbauer")); verify(mockRepository, atLeastOnce()).save(unsaved);
}

校验表单

从Spring3.0开始,Spring支持Java校验api,从而可以从而可以不需要添加其他配置,仅仅需要有一个Java API 的实现,如Hibernate Validator。

Java Validation API定义了许多注解,可以使用这些注解来约束参数的值,所有的注解都在包javax.validation.constraints中。

注解 描述
@AssertFalse(@AssertTrue) 对象必须是布尔类型,并且必须为false(true)
@DecimalMax(value)、@DecimalMin(value) 限制对象必须是一个数字,其值不大于(不小于)指定的BigDecimalString值
@Digits(integer,fraction) 对象必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 必须是一个将来的日期
@Max(value)、@Min(value) 必须为一个不大于(不小于)指定值的数字
@NotNull 限制对象不能为空
@Null 限制对象必须为空
@Past 必须是一个过去的日期
@Pattern(value) 必须符合指定的正则表达式
@Size(min,max) 限制字符长度必须在min到max之间

以此实现Spitter:

package com.wbw.spittr;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder; import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size; public class Spitter { private Long id; @NotNull
@Size(min=5, max=16)
private String username; @NotNull
@Size(min=5, max=25)
private String password; @NotNull
@Size(min=2, max=30)
private String firstName; @NotNull
@Size(min=2, max=30)
private String lastName; public Spitter() {} public Spitter(String username, String password, String firstName, String lastName) {
this(null, username, password, firstName, lastName);
} public Spitter(Long id, String username, String password, String firstName, String lastName) {
this.id = id;
this.username = username;
this.password = password;
this.firstName = firstName;
this.lastName = lastName; } 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;
} public Long getId() {
return id;
} public void setId(Long id) {
this.id = id;
} public String getFirstName() {
return firstName;
} public void setFirstName(String firstName) {
this.firstName = firstName;
} public String getLastName() {
return lastName;
} public void setLastName(String lastName) {
this.lastName = lastName;
} @Override
public boolean equals(Object that) {
return EqualsBuilder.reflectionEquals(this, that, "firstName", "lastName", "username", "password");
} @Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, "firstName", "lastName", "username", "password");
} }

小结

本章可以作为SpringMVC入门。基于Spring MVC的应用有三种方式读取数据:查询参数、路径参数和表单输入。本章用两节介绍了这些内容,并给出了类似错误处理和参数验证等关键知识点。