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

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

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

Spring MVC起步

跟踪Spring MVC的请求

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的应用有三种方式读取数据:查询参数、路径参数和表单输入。本章用两节介绍了这些内容,并给出了类似错误处理和参数验证等关键知识点。

posted on 2018-08-23 00:30  手挥死一片  阅读(177)  评论(0)    收藏  举报

导航