Beginning Spring学习笔记——第3章(二)表单处理

使用JSP处理表单


Spring MVC通过自定义JSP表单标签库提供了表单处理方法,要想使用该库内的标签,需要在JSP文件中添加该标签库的定义

<%@taglib uri="http://www.springframework.org/tags/form" prefix="mvc" %>

此处把mvc定义为标签库的前缀,使用标签库内标签时遵循的格式
下用一个处理用户注册表单的例子来示范这些标签的使用
首先使用maven创建webapp工程,将servlet版本调整至3.1,工程最终目录结构如下
Beginning Spring学习笔记——第3章(二)表单处理_第1张图片
pom.xml配置上一节已经讲过,现在继续先在web.xml中定义DispatcherServlet。

<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
      http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">

    <servlet>
        <servlet-name>springmvcservlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServletservlet-class>
        <load-on-startup>1load-on-startup>
    servlet>

    <servlet-mapping>
        <servlet-name>springmvcservlet-name>
        <url-pattern>*.mvcurl-pattern>
    servlet-mapping>

web-app>

然后在springmvc-servlet.xml文件中配置好DispatcherServlet


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.0.xsd
                           http://www.springframework.org/schema/mvc 
                           http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="com.lonelyquantum.wileybookch3" />
    <context:annotation-config />
    <mvc:annotation-driven />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp" />
    bean>
beans>

储存数据所用的User类以及存放性别数据使用的Gender枚举如下

public class User {

    private String name;
    private String lastname;
    private String password;
    private String detail;
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private LocalDate birthDate;
    private Gender gender;
    private String country;
    private boolean nonSmoking;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getDetail() {
        return detail;
    }

    public void setDetail(String detail) {
        this.detail = detail;
    }

    public LocalDate getBirthDate() {
        return birthDate;
    }

    public void setBirthDate(LocalDate birthDate) {
        this.birthDate = birthDate;
    }

    public Gender getGender() {
        return gender;
    }

    public void setGender(Gender gender) {
        this.gender = gender;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    public boolean isNonSmoking() {
        return nonSmoking;
    }

    public void setNonSmoking(boolean nonSmoking) {
        this.nonSmoking = nonSmoking;
    }
}


public enum Gender {
    Male,
    Female,
    Other,
    RefuseToAnswer;
}

此处为了照顾性少数者,性别栏添加了Other和RefuseToAnswer两项

然后就可以创建作为控制器的UserController类了。

@Controller
public class UserController {

    private static final String[] countries = { "Turkey", "United States", "Germany", "China", "Japan", "The United Kingdom" };


    @RequestMapping(value = "/form")
    public ModelAndView user() {
        ModelAndView modelAndView = new ModelAndView("userForm", "user", new User());
        modelAndView.addObject("genders", Gender.values());
        modelAndView.addObject("countries", countries);

        return modelAndView;
    }

    @RequestMapping(value = "/result")
    public ModelAndView processUser(User user) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.setViewName("userResult");

        modelAndView.addObject("u", user);

        return modelAndView;
    }
}

添加了几个国家~

两个方法分别返回注册界面和注册结果界面,下面就是这两个界面的JSP文件
注册界面userForm.jsp

<%@ page contentType="text/html; charset=ISO-8859-1" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="mvc" %>
<html>
<head>
    <title>Spring MVC Form Handlingtitle>
head>
<body>

<h2>User Registration Formh2>
<mvc:form modelAttribute="user" action="result.mvc">
    <table>
        <tr>
            <td><mvc:label path="name">Namemvc:label>td>
            <td><mvc:input path="name" />td>
        tr>
        <tr>
            <td><mvc:label path="lastname">Last Namemvc:label>td>
            <td><mvc:input path="lastname" />td>
        tr>
        <tr>
            <td><mvc:label path="password">Passwordmvc:label>td>
            <td><mvc:password path="password" />td>
        tr>
        <tr>
            <td><mvc:label path="detail">Detailmvc:label>td>
            <td><mvc:textarea path="detail" />td>
        tr>
        <tr>
            <td><mvc:label path="birthDate">Birth Datemvc:label>td>
            <td><mvc:input path="birthDate" />td>
        tr>
        <tr>
            <td><mvc:label path="gender">Gendermvc:label>td>
            <td><mvc:radiobuttons path="gender" items="${genders}" />td>
        tr>
        <tr>
            <td><mvc:label path="country">Countrymvc:label>td>
            <td><mvc:select path="country" items="${countries}" />td>
        tr>
        <tr>
            <td><mvc:label path="nonSmoking">Non Smokingmvc:label>td>
            <td><mvc:checkbox path="nonSmoking" />td>
        tr>
        <tr>
            <td colspan="2">
                <input type="submit" value="Submit" />
            td>
        tr>
    table>  
mvc:form>
body>
html>

首先通过标签创建一个表单,在其中定义表单内的元素.该标签的modelAttribute特性向内部标签公开了一个绑定路径,该特性所指定的模型类将向视图公开,表单内标签的path特性将指向该模型类的属性,如name,lastname,gender等。而它的action特性则表示表单提交后跳转至的URL。
表单中用标签定义了输入框,用于姓名、密码、生日的输入。
标签定义了输入文本区域,用于详细介绍的输入。
定义了选择性别的一系列单选按钮,与User中的gender属性对应,接受名为genders的数据作为选项的输入。
定义了选择国家的下拉栏,与User中的country属性对应,接受名为countries的数据作为选项输入。
定义的复选框用于勾选是否吸烟。
以上标签之前都有标签来给栏目进行说明。
最后用(HTML的标签)定义了表单提交的按钮。

接下来,类似地创建userResult.jsp来显示用户输入的注册信息

<%@ page contentType="text/html; charset=ISO-8859-1" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="mvc" %>
<html>
<head>
    <title>Spring MVC Form Handlingtitle>
head>
<body>
    <h2>User Registration Resulth2>
    <table>
        <tr>
            <td>Nametd>
            <td>${u.name}td>
        tr>
        <tr>
            <td>Last nametd>
            <td>${u.lastname}td>
        tr>
        <tr>
            <td>Passwordtd>
            <td>${u.password}td>
        tr>
        <tr>
            <td>Detailtd>
            <td>${u.detail}td>
        tr>
        <tr>
            <td>Birth Datetd>
            <td>${u.birthDate}td>
        tr>
        <tr>
            <td>Gendertd>
            <td>${u.gender}td>
        tr>
        <tr>
            <td>Countrytd>
            <td>${u.country}td>
        tr>
        <tr>
            <td>Non-Smokingtd>
            <td>${u.nonSmoking}td>
        tr>
    table>
body>
html>

注意此时从UserController传入视图的是一个被命名为“u”的User实例,在视图中通过${u.xxx}来获得其属性。
将项目部署到Tomcat服务器并运行,在浏览器中输入http://localhost:8080/FormRegister/form.mvc得到如下页面
Beginning Spring学习笔记——第3章(二)表单处理_第2张图片
单击Submit按钮跳转至信息显示页面
Beginning Spring学习笔记——第3章(二)表单处理_第3张图片

使用注解的强大功能


刚才的例子中已经用到了一系列注解,此处将解释他们的作用

  • @Controller:表示被注解的类为MVC框架的一个Controller,DispatcherServlet扫描被@Controller注解的类并将Web请求映射到其被相应@RequestMapping注解的方法上
  • @RequestMapping:标记用来将用户请求映射到处理器的类或者方法,可在类或方法级别使用,Value属性代表被映射的URL值的一部分
  • @ModelAttribute:使用一个向视图公开的键将一个返回值和一个参数绑定,可以在方法或方法参数级别使用
  • @PathVariable:将一个方法参数绑定到一个URL模板
  • @ControllerAdvice:将代码集中,一遍跨控制器共享代码。使用该注解的类可以包含带有@ExceptionHandler、@InitBinder和@ModelAttribute注解的方法
  • @InitBinder:确定用来初始化WebDataBinder的方法
  • @ExceptionHandler:确定处理控制器类中发生的异常的方法

验证用户输入


在域类的属性上添加如下注解可以定义他们应当通过的验证:

  • @Size注解定义长度
  • @Email注解根据e-mail的正则表达式来验证输入
  • @CreditCardNumber注解根据Luhn算法验证输入数字
  • @Pattern注解根据其regexp属性定义的正则表达式来验证输入

我们在User类中用以上注解来规定几个属性的限制条件

public class User {

    @Size(min=3, max=20,message = "error.username")
    String username;
    @Email
    String email;
    @CreditCardNumber(message = "error.ccNumber")
    String ccNumber;
    @Pattern(regexp = "^[a-zA-Z]\\w{3,14}$",message = "error.password")
    String password;
    //getters and setters
}

启动验证需要在pom.xml中添加如下依赖


<dependency>
    <groupId>org.hibernategroupId>
    <artifactId>hibernate-validatorartifactId>
    <version>6.0.2.Finalversion>
dependency>

为了在输入注册信不满足条件的时候返回注册界面显示错误信息,processUser方法需要进行修改

@Controller
public class UserController {

    @RequestMapping(value = "/form")
    public ModelAndView user() {
            return new ModelAndView("userForm", "user", new User());
    }

    @RequestMapping(value = "/result", method= RequestMethod.POST)
    public ModelAndView processUser(@Valid User user, BindingResult result) {
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("u", user);

        if (result.hasErrors()) {
            modelAndView.setViewName("userForm");
        }
        else {
            modelAndView.setViewName("userResult");
        }

        return modelAndView;
    }
}

其中的@Valid注解用于触发对user参数的验证,且方法接受一个BindingResult实例作为输入参数来检查验证是否有误,有误则返回添加了错误信息的注册界面
为了配置验证,还要在Web上下文中添加LocalValidatorFactoryBean和ReloadableResourceBundleMessageSource的定义,以及在mvc命名空间的annotation-driven标签中定义验证程序


<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
        xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
                           http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context-4.0.xsd
                           http://www.springframework.org/schema/mvc 
                           http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd">

    <context:component-scan base-package="com.lonelyquantum.wileybookch3" />
    <context:annotation-config />
    <mvc:annotation-driven validator="validator" />

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/" />
        <property name="suffix" value=".jsp" />
    bean>

    <bean id="messageSource"
          class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
        <property name="basename" value="classpath:messages" />
    bean>

    <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
        <property name="validationMessageSource" ref="messageSource"/>
    bean>
beans>

加入了Bean验证后的userForm.jsp文件如下

<%@ page contentType="text/html; charset=ISO-8859-1" %>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="mvc" %>
<html>
<head>
    <title>Spring MVC Form Validationtitle>
    <style type="text/css">
        .formFieldError { background-color: #FFC; }
    style>
head>
<body>

<h2>User Registration Formh2>
<mvc:form modelAttribute="user" action="result.mvc">
    <table>
        <tr>
            <td><mvc:label path="username">User Namemvc:label>td>
            <td><mvc:input path="username" cssErrorClass="formFieldError" />td>
            <td><mvc:errors path="username" />td>
        tr>
        <tr>
            <td><mvc:label path="email">E-Mailmvc:label>td>
            <td><mvc:input path="email" cssErrorClass="formFieldError" />td>
            <td><mvc:errors path="email" />td>
        tr>
        <tr>
            <td><mvc:label path="ccNumber">Credit Card Numbermvc:label>td>
            <td><mvc:input path="ccNumber" cssErrorClass="formFieldError" />td>
            <td><mvc:errors path="ccNumber" />td>
        tr>
        <tr>
            <td><mvc:label path="password">Passwordmvc:label>td>
            <td><mvc:password path="password" cssErrorClass="formFieldError" />td>
            <td><mvc:errors path="password" />td>
        tr>
        <tr>
            <td colspan="3">
                <input type="submit" value="Submit" />
            td>
        tr>
    table>  
mvc:form>
body>
html>

其中每一个样式的errors标签的path都被设置为模型类的属性名称,不设置则看不到相关输入字段的错误消息,想要在一个地方显示所有错误可将path值设置为*。例子中还定义了样式表类formFieldError,并将每个输入字段的cssErrorClass特性设置为该类,开头通过style标签将该类字段背景设置为黄色。
验证注解中使用message属性返回对应的错误消息,消息所在位置由ReloadableResourceBundleMessageSource设定,此处为src/main/resource文件夹下的message.property文件。

Pattern.user.password=Password should meet the requirements.
Size.user.username=Size must be between 3 and 20.
CreditCardNumber.user.ccNumber=invalid credit card number.

不难发现message.property文件中定义错误消息的格式为 注解名.实例名.属性名 = 错误消息内容
在浏览器中输入http://localhost:8080/BeanValidator/result.mvc,直接提交空表单可以获得如下结果
Beginning Spring学习笔记——第3章(二)表单处理_第4张图片
可看到未通过验证的输入栏背景变成黄色,旁边出现错误信息

你可能感兴趣的:(Beginning,Spring学习笔记,Web基础)