Spring MVC 数据绑定源码分享

时间:2018-11-07
本文章向大家介绍Spring MVC 数据绑定源码分享,需要的朋友可以参考一下

一、配置web.xml

<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
         version="4.0">

    <!-- 配置请求总控器 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:dispatcher-servlet.xml</param-value>
        </init-param>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
</web-app>
View Code

二、配置dispatcher-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<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"
       xmlns:mcv="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 启用注解并扫描 -->
    <context:component-scan base-package="edu.nf.ch04.controller"/>

    <!-- 启用mvc注解驱动,这个注解同时还注册了Springmvc内置的多种HttpMessageConverter(消息转换器),
    它主要用于将Http请求报文的字符串信息转换成用@ReqeustBody注解修饰的方法参数对象,
    同时基于@ResponseBody修饰的返回值进行数据转换然后响应客户端。如果请求处理方法的参数和方法的返回值
    没有使用@RequestBody和ResponseBody,那么spring将使用额外的Converter SPI来完成请求方法参数的类型转换-->

    <!-- 可以指定conversion-service来自定义Converter转换器。
     注意:自定义Converter和自定义HttpMessageConverter是两种不同的转换器,
     自定义Converter是实现Converter接口,而自定义HttpMessageConverter是
     实现HttpMessageConverter接口,如果需要自定义HttpMessageConverter可以在
     <mvc:annotation-driven>中加入配置<mvc:message-converters>-->
    <mvc:annotation-driven conversion-service="conversionService">
        <!-- 自定义一个消息转换器,register-defaults设置为true
        则同时注册默认的HttpMessageConverter和自定义的HttpMessageConverter,
        设置为false则只会注册自定义的HttpMessageConverter-->
        <!--<mvc:message-converters register-defaults="true">
            <ref bean="myMessageConverter"/>
        </mvc:message-converters>-->
    </mvc:annotation-driven>

    <!-- 指定Converter转换器,
    配置ConversionServiceFactoryBean来注册一个自定义Converter -->
    <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
        <property name="converters">
            <bean class="edu.nf.ch04.converter.MyConverter"/>
        </property>
    </bean>

    <!-- 处理静态资源-->
    <mcv:default-servlet-handler/>

    <!-- 配置视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/jsp/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

三、数据绑定controller(DemoController)

package edu.nf.ch04.controller;

import edu.nf.ch04.entity.Address;
import edu.nf.ch04.entity.Users;
import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.text.SimpleDateFormat;
import java.util.Date;

/**
 * @author wangl
 * @date 2018/10/29
 */
@Controller
public class DemoController {

    /**
     * 默认参数名对应<input name="名称"/>,
     * 如果名称不一致时,可以使用@RequestParam注解进行绑定
     * 而注解的value对应<input name="名称"/>
     * @param userName
     * @param age
     * @return
     */
    @PostMapping("/add")
    public ModelAndView add(@RequestParam("userName") String userName, @RequestParam("age") Integer age){
        System.out.println(userName);
        System.out.println(age);
        return new ModelAndView("index");
    }

    /**
     * 也可以映射成一个Bean对象,而对象的字段名对应<input name="名称"/>
     * ,也可以将要映射的集合对象定义在实体对象中,同样可以完成集合类型的映射
     * (注意:不能单独在controller的方法参数中声明List等集合类型,spring是不会自动映射的
     * @param user
     * @return
     */
    @PostMapping("/add2")
    public ModelAndView add2(Users user){
        System.out.println(user.getUserName());
        System.out.println(user.getAge());
        for (Address address : user.getAddress()) {
            System.out.println(address.getAddr());
        }
        return new ModelAndView("index");
    }

    /**
     * 通过请求url地址映射参数
     * 使用@PathVariable注解映射url地址中的变量名,
     * value属性值对应{userId}
     * @param uid
     * @return
     */
    @GetMapping("/user/{userId}")
    public ModelAndView getUser(@PathVariable("userId") Integer uid){
        ModelAndView mv = new ModelAndView("userinfo");
        if(uid == 1001){
            Users user = new Users();
            user.setUserName("user1");
            user.setAge(21);
            //类似于放入请求作用域
            mv.addObject("user", user);
        }
        return mv;
    }


    /**
     * 方式一:
     * 日期转换方法,@InitBinder标注的方法会在执行controller方法之前先执行
     * ,并且需要传入一个WebDataBinder参数,这个参数用于注册日期类型转换器
     * @param binder
     * @return
     */
    @InitBinder
    public void convert(WebDataBinder binder){
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    /**
     * 日期类型的转换处理,先会执行上面@InitBinder标注的方法注册一个日期转换器,
     * 再调用当前的controller方法将转换的值赋值到user实体中的birth字段
     * @param user
     * @return
     */
    @PostMapping("/add3")
    public ModelAndView convertDate(Users user){
        System.out.println(user.getBirth());
        return new ModelAndView("index");
    }

    /**
     * 传入ServletAPI的原生对象
     * @param request
     * @param session
     * @return
     */
    @GetMapping("/api")
    public ModelAndView servletApi(HttpServletRequest request, HttpSession session){
        System.out.println(request);
        System.out.println(session);
        return new ModelAndView("index");
    }
}

前端请求页面:(adduser.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <form method="post" action="add3">
     Username:<input type="text" name="userName"/><br/>
     Age:<input type="text" name="age"/><br/>
     Birth:<input type="text" name="birth"><br/>
     <!-- 映射集合类型(普通类型) -->
     <!--Addr1:<input type="text" name="address"/><br/>
     Addr2:<input type="text" name="address"/><br/>-->
     <!-- 映射集合(实体对象)-->
     Addr1:<input type="text" name="address[0].addr"/><br/>
     Addr2:<input type="text" name="address[1].addr"/><br/>
     <input type="submit" value="add"/>
 </form>
</body>
</html>
View Code

前端请求页面:(getuser.html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <a href="user/1001">获取用户信息</a>
</body>
</html>
View Code

四、自定义类型转换 (ConverterController)

package edu.nf.ch04.controller;

import edu.nf.ch04.entity.People;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.servlet.ModelAndView;

/**
 * @author wangl
 * @date 2018/10/31
 */
@Controller
public class ConverterController {

    /**
     * 自定义类型转换
     * @param people
     * @return
     */
    @PostMapping("/convert")
    public ModelAndView convert(People people){
        System.out.println(people.getName());
        System.out.println(people.getAge());
        return new ModelAndView("index");
    }
}

自定义类型转换器:

package edu.nf.ch04.converter;

import edu.nf.ch04.entity.People;
import org.springframework.core.convert.converter.Converter;

/**
 * @author wangl
 * @date 2018/10/31
 * 自定义类型转换器,需要实现Converter接口,
 * 这个转换器将name-age格式的字符串转换成People对象
 */
public class MyConverter implements Converter<String, People> {

    @Override
    public People convert(String s) {
        People p = new People();
        if(s != null && !"".equals(s)){
            String[] array = s.split("-");
            if(array.length == 2){
                p.setName(array[0]);
                p.setAge(Integer.valueOf(array[1]));
            }
        }
        return p;
    }
}

实体类:

Address:

package edu.nf.ch04.entity;

/**
 * @author wangl
 * @date 2018/10/29
 */
public class Address {

    private String addr;

    public String getAddr() {
        return addr;
    }

    public void setAddr(String addr) {
        this.addr = addr;
    }
}
View Code

People:

package edu.nf.ch04.entity;

/**
 * @author wangl
 * @date 2018/10/31
 */
public class People {

    private String name;
    private Integer age;

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
View Code

Users:

package edu.nf.ch04.entity;

import org.springframework.format.annotation.DateTimeFormat;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * @author wangl
 * @date 2018/10/29
 */
public class Users {

    private String userName;
    private Integer age;
    /**
     * 方式二:
     * 在实体中使用@DateTimeFormat完成日期的类型转换
     */
    //@DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date birth;
    /**
     * 映射集合(集合中是普通的类型,如String)
     */
    //private List<String> address = new ArrayList<>();

    /**
     * 映射集合(集合中是实体对象类型)
     */
    private List<Address> address = new ArrayList<>();

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    /*public List<String> getAddress() {
        return address;
    }

    public void setAddress(List<String> address) {
        this.address = address;
    }*/

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public List<Address> getAddress() {
        return address;
    }

    public void setAddress(List<Address> address) {
        this.address = address;
    }
}
View Code