前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring MVC绑定 List 对象参数 原

Spring MVC绑定 List 对象参数 原

作者头像
Gaussic
发布2018-08-17 15:27:12
1.1K0
发布2018-08-17 15:27:12
举报
文章被收录于专栏:GaussicGaussic

       最近做的一个小小的项目碰上了如何用 post 传递一整个 list 的问题,在解决这个问题的同时,也顺带升级一下 Spring 的版本,并精简一下代码,不过对新的用法没有时间去做太多的探索。

       最近也在看 Spring Boot,但是部分配置还没来理解,暂时还没办法用到工程里面来。不多说,一点一点挤牙膏吧。

项目已放到 Github:https://github.com/gaussic/SpringDemo-List

转载请注明出处:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 。

一、开发环境

IntelliJ IDEA 2016.1.2

JDK 1.8.0_92

Tomcat 8.0.35

Maven 3.0.5

Spring 4.2.6.RELEASE

Hibernate 5.1.0.Final

Spring Data JPA 1.10.1.RELEASE

二、配置项目

具体的创建步骤不多说了。

贴出 pom.xml:

代码语言:javascript
复制
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.gaussic</groupId>
    <artifactId>springdemo-list</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>springdemo-list Maven Webapp</name>
    <url>http://maven.apache.org</url>

    <properties>
        <spring.version>4.2.6.RELEASE</spring.version>
        <hibernate.version>5.1.0.Final</hibernate.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>${spring.version}</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-jpa</artifactId>
            <version>1.10.1.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>${hibernate.version}</version>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.39</version>
        </dependency>


    </dependencies>
    <build>
        <finalName>springdemo-list</finalName>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

web.xml:

代码语言:javascript
复制
<?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_3_1.xsd"
         version="3.1">

    <display-name>SpringDemo-List Web Application</display-name>

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <filter>
        <filter-name>encodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

</web-app>

先把 package 建立好:

配置 mvc-dispatcher-servlet.xml,注意这里把数据库的配置也同样放了进来,所以就不需要 persistence.xml 了:

代码语言:javascript
复制
<?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:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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 http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <context:component-scan base-package="com.gaussic.controller"/>

    <mvc:default-servlet-handler/>

    <mvc:annotation-driven/>

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

    <!-- 表示JPA Repository所在的包 -->
    <jpa:repositories base-package="com.gaussic.repository"/>

    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
        <property name="persistenceUnitName" value="defaultPersistenceUnit"/>
        <property name="packagesToScan" value="com.gaussic.model"/>
        <property name="jpaVendorAdapter">
            <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"/>
        </property>
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
                <prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/springdemo-list?useSSL=false</prop>
                <prop key="hibernate.connection.username">root</prop>
                <prop key="hibernate.connection.password">111111</prop>
                <prop key="hibernate.show_sql">false</prop>
                <prop key="hibernate.connection.useUnicode">true</prop>
                <prop key="hibernate.connection.characterEncoding">UTF-8</prop>
                <prop key="hibernate.format_sql">true</prop>
                <prop key="hibernate.use_sql_comments">true</prop>
                <prop key="hibernate.hbm2ddl.auto">update</prop>
                <prop key="hibernate.connection.autoReconnect">true</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
                <prop key="connection.autoReconnectForPools">true</prop>
                <prop key="connection.is-connection-validation-required">true</prop>
            </props>
        </property>
    </bean>

    <!-- 事务管理 -->
    <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
        <property name="entityManagerFactory" ref="entityManagerFactory"/>
    </bean>

    <!-- 开启事务管理注解 -->
    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

三、数据库配置

创建数据库 springdemo-list,utf-8 格式,演示比较简单,只有一张表(主键 id 一定要设置为自增):

构造 UserEntity。

这一步有一点小 trick。因为直接在mvc-dispatcher-servlet.xml里面配置数据库,没有添加 Java EE Persistence 这个 Framework,所以在左下的 Toolbar 无法看到 Persistence 这个选项。怎么做才能把它给调出来呢?

简单的做法是右击项目,添加 Framework:

下拉找到 Java EE Persistence,直接 OK,其他不用配置。

可以发现,resources里面多了 persistence.xml,而左下角多了 Persistence:

这个时候就可以正常地生成 Entity 了:

在 com.gaussic.model 中生成了 UserEntity:

代码语言:javascript
复制
package com.gaussic.model;

import javax.persistence.*;

/**
 * Created by dzkan on 2016/5/24.
 */
@Entity
@Table(name = "user", schema = "springdemo-list", catalog = "")
public class UserEntity {
    private int id;
    private String firstName;
    private String lastName;

    @Id
    @Column(name = "id", nullable = false)
    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    @Basic
    @Column(name = "first_name", nullable = true, length = 45)
    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    @Basic
    @Column(name = "last_name", nullable = true, length = 45)
    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        UserEntity that = (UserEntity) o;

        if (id != that.id) return false;
        if (firstName != null ? !firstName.equals(that.firstName) : that.firstName != null) return false;
        if (lastName != null ? !lastName.equals(that.lastName) : that.lastName != null) return false;

        return true;
    }

    @Override
    public int hashCode() {
        int result = id;
        result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
        result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
        return result;
    }
}

既然 entity 已经生成了,Persistence 就功德圆满了,可以删掉 resources 下的 persistence.xml 了。

四、添加 Repository

刚配置完数据库,现在要配 Repository 了。稍微提一下,JPA 是一种规范,基于这种规范可以非常方便地进行数据库操作,而 Hibernate JPA 实现了这一规范,这也是我们为什么要导入 Hibernate JPA 的原因,导入归导入,但使用的还是 Spring Data JPA 的语法。

新建 UserRepository:

代码语言:javascript
复制
package com.gaussic.repository;

import com.gaussic.model.UserEntity;
import org.springframework.data.jpa.repository.JpaRepository;

/**
 * Created by dzkan on 2016/5/24.
 */
public interface UserRepository extends JpaRepository<UserEntity, Integer> {

    // 由于后面要实现一个简单的查重,需要这个方法,查询指定姓和名的人的个数
    Long countByFirstNameAndLastName(String firstName, String lastName);
}

五、添加 Controller

1、首页

我们想在首页先试一下数据库中有多少个用户。

新建 DemoController:

代码语言:javascript
复制
package com.gaussic.controller;

import com.gaussic.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * Created by dzkan on 2016/5/24.
 */
@Controller
public class DemoController {

    @Autowired
    UserRepository userRepository;

    // 首页
    @RequestMapping("/")
    public String index(ModelMap model) {
        model.addAttribute("user_cnt", userRepository.count());
        return "index";
    }
}

在 WEB-INF 下新建 pages 文件夹,把 index.jsp 拖到这个文件夹下:

修改 index.jsp:

代码语言:javascript
复制
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>用户导入系统首页</title>

    <!-- Bootstrap -->
    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="http://cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
</head>
<body>

<div class="container">
    <h3>用户导入系统首页</h3>
    <hr style="border-color: steelblue"/>
    <h4>数据库中已有 <span style="color: red">${user_cnt}</span> 名用户 。</h4>
    <br/>
    <br/>
    <a href="${pageContext.request.contextPath}/users" type="button" class="btn btn-success">进入用户系统</a>
</div>

<script src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script src="http://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</body>
</html>

配置 Tomcat,部署并运行(不再赘述):

2、批量输入数据

接下来就要完成我的下一个目标,如何批量的输入数据,即一次性输入多个用户。

首先,要找个方法把多个用户用列表封装起来。在 com.gaussic.model 下新建一个 UserListForm,这个类非常简单,只有一个 list 及其 get 和 set 方法:

代码语言:javascript
复制
package com.gaussic.model;

import java.util.List;

/**
 * Created by dzkan on 2016/5/24.
 */
public class UserListForm {

    private List<UserEntity> users;

    public List<UserEntity> getUsers() {
        return users;
    }

    public void setUsers(List<UserEntity> users) {
        this.users = users;
    }
}

在 DemoController 中添加方法,映射到批量添加用户页面:

代码语言:javascript
复制
    // 指向批量添加用户页面
    @RequestMapping("/users")
    public String users() {
        return "users";
    }

在 pages 下新建页面 users.jsp:

代码语言:javascript
复制
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>用户输入</title>

    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="http://cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
</head>
<body>

<div class="container">
    <h3>请输入用户姓名</h3>
    <hr style="border-color: steelblue"/>

    <form class="form-horizontal" action="${pageContext.request.contextPath}/addUser" method="post">
        <div class="question-list panel panel-success" style="padding:10px; font-size: 16px;">
            <c:forEach var="i" begin="1" end="3">
                <div class="form-group">
                    <label for="firstName${i}" class="col-md-2 control-label">First Name ${i}:</label>
                    <div class="col-md-10">
                        <input type="text" class="form-control" id="firstName${i}" name="users[${i-1}].firstName"
                               required="required">
                    </div>
                </div>
                <div class="form-group">
                    <label for="lastName${i}" class="col-md-2 control-label">Last Name ${i}:</label>
                    <div class="col-md-10">
                        <input type="text" class="form-control required" id="lastName${i}" name="users[${i-1}].lastName"
                               required="required">
                    </div>
                </div>
            </c:forEach>
        </div>

        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="button" class="btn btn-info" id="addBtn">
                    <span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
                </button>
            </div>
        </div>
        
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" class="btn btn-success">提交</button>
            </div>
        </div>
    </form>
</div>

<script src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script src="http://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
<script>
    $("#addBtn").click(function () {
        var user_num = $(".question-list .form-group").length / 2;
        if (user_num < 5) {
            var firstName = "<div class=\"form-group\">"
                    + "<label for=\"firstName" + (user_num + 1) + "\" class=\"col-md-2 control-label\">First Name " + (user_num + 1) + ":</label>"
                    + "<div class=\"col-md-10\">"
                    + "<input type=\"text\" class=\"form-control\" id=\"firstName" + (user_num + 1) + "\" name=\"users[" + (user_num) + "].firstName\" required=\"required\">"
                    + "</div></div>";

            var lastName = "<div class=\"form-group\">"
                    + "<label for=\"lastName" + (user_num + 1) + "\" class=\"col-md-2 control-label\">Last Name " + (user_num + 1) + ":</label>"
                    + "<div class=\"col-md-10\">"
                    + "<input type=\"text\" class=\"form-control\" id=\"lastName" + (user_num + 1) + "\" name=\"users[" + (user_num) + "].lastName\" required=\"required\">"
                    + "</div></div>";

            $(".question-list").append(firstName + lastName);
        } else {
            alert("最多只能输入 5 个用户,若想输入更多,请在提交本页后重新进入。");
        }
    });
</script>
</body>
</html>

注意以下几点,其中 name 中的参数要严格按照 UserListForm 的参数名:

看看效果:

这里多了一个挺好玩的小功能,就是在数量不够的手动添加。页面已经做好了,现在要实现它的 post 方法了:

在 DemoController 中添加如下方法:

代码语言:javascript
复制
    // 添加用户,post 请求
    @RequestMapping(value = "/addUser", method = RequestMethod.POST)
    public String addUser(UserListForm userListForm, ModelMap model) {

        List<UserEntity> succeedList = new ArrayList<>();  // 添加成功
        List<UserEntity> failList = new ArrayList<>();     // 添加不成功
        for(UserEntity user : userListForm.getUsers()) {
            // 基本查重
            if(userRepository.countByFirstNameAndLastName(user.getFirstName(), user.getLastName()) == 0) {
                userRepository.saveAndFlush(user);
                succeedList.add(user);
            } else {
                failList.add(user);
            }
        }
        
        model.addAttribute("succeedList", succeedList);
        model.addAttribute("failList", failList);
        return "user_list";
    }

然后,创建一个页面,返插入结果:

代码语言:javascript
复制
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>用户输入结果</title>

    <link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/3.3.6/css/bootstrap.min.css">
    <link rel="stylesheet" href="${pageContext.request.contextPath}/css/custome.css">

    <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
    <script src="http://cdn.bootcss.com/html5shiv/3.7.2/html5shiv.min.js"></script>
    <script src="http://cdn.bootcss.com/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->
</head>
<body>

<div class="container">
    <h3>用户输入结果列表</h3>
    <hr style="border-color: steelblue"/>

    <div class="question-list panel panel-success" style="padding:10px;">
        <h3>以下是输入成功的用户,数量 <span style="color: red">${succeedList.size()}</span></h3>
        <c:forEach var="i" begin="1" end="${succeedList.size()}">
            <h4 style="padding: 5px;">First Name ${i}: ${succeedList[i-1].firstName}</h4>
            <h4 style="padding: 5px;">Last Name ${i}: ${succeedList[i-1].lastName}</h4>
        </c:forEach>
    </div>

    <div class="question-list panel panel-success" style="padding:10px;">
        <h3>以下用户库中已存在,数量 <span style="color: red">${failList.size()}</span></h3>
        <c:forEach var="i" begin="1" end="${failList.size()}">
            <h4 style="padding: 5px;">First Name ${i}: ${failList[i-1].firstName}</h4>
            <h4 style="padding: 5px;">Last Name ${i}: ${failList[i-1].lastName}</h4>
        </c:forEach>
    </div>

    <div class="row" style="margin-bottom: 50px;">
        <div class="col-sm-offset-5 col-sm-7">
            <a type="button" href="${pageContext.request.contextPath}/users" class="btn btn-info"
               style="font-weight: bold; margin-bottom: 5px;">继续输入</a>
            <a type="button" href="${pageContext.request.contextPath}/" class="btn btn-info"
            style="font-weight: bold; margin-bottom: 5px;">返回首页</a>
        </div>
    </div>
</div>

<script src="http://cdn.bootcss.com/jquery/1.11.3/jquery.min.js"></script>
<script src="http://cdn.bootcss.com/bootstrap/3.3.6/js/bootstrap.min.js"></script>
</body>
</html>

看看效果:

任务完成,其他的任务就不加进来了。按道理说,这个项目稍微改改就可以自己用了,可以省去不少配置的时间。

项目已放到 Github:https://github.com/gaussic/SpringDemo-List

转载请注明出处:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2016/05/24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、开发环境
  • 二、配置项目
  • 三、数据库配置
  • 四、添加 Repository
  • 五、添加 Controller
    • 1、首页
      • 2、批量输入数据
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档