Spring MVC绑定 List 对象参数
2016-05-24 03:40
651 查看
最近做的一个小小的项目碰上了如何用 post 传递一整个 list 的问题,在解决这个问题的同时,也顺带升级一下 Spring 的版本,并精简一下代码,不过对新的用法没有时间去做太多的探索。
最近也在看 Spring Boot,但是部分配置还没来理解,暂时还没办法用到工程里面来。不多说,一点一点挤牙膏吧。
项目已放到 Github:https://github.com/gaussic/SpringDemo-List
转载请注明出处:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 。
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:
web.xml:
先把 package 建立好:
配置 mvc-dispatcher-servlet.xml,注意这里把数据库的配置也同样放了进来,所以就不需要 persistence.xml 了:
构造 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:
既然 entity 已经生成了,Persistence 就功德圆满了,可以删掉 resources 下的 persistence.xml 了。
新建 UserRepository:
新建 DemoController:
在 WEB-INF 下新建 pages 文件夹,把 index.jsp 拖到这个文件夹下:
修改 index.jsp:
配置 Tomcat,部署并运行(不再赘述):
首先,要找个方法把多个用户用列表封装起来。在 com.gaussic.model 下新建一个 UserListForm,这个类非常简单,只有一个 list 及其 get 和 set 方法:
在 DemoController 中添加方法,映射到批量添加用户页面:
在 pages 下新建页面 users.jsp:
注意以下几点,其中 name 中的参数要严格按照 UserListForm 的参数名:
看看效果:
这里多了一个挺好玩的小功能,就是在数量不够的手动添加。页面已经做好了,现在要实现它的 post 方法了:
在 DemoController 中添加如下方法:
然后,创建一个页面,返插入结果:
看看效果:
任务完成,其他的任务就不加进来了。按道理说,这个项目稍微改改就可以自己用了,可以省去不少配置的时间。
项目已放到 Github:https://github.com/gaussic/SpringDemo-List
转载请注明出处:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 。
最近也在看 Spring Boot,但是部分配置还没来理解,暂时还没办法用到工程里面来。不多说,一点一点挤牙膏吧。
项目已放到 Github:https://github.com/gaussic/SpringDemo-List
转载请注明出处:Gaussic(一个致力于AI研究却不得不兼顾项目的研究生) 。
一、开发环境
IntelliJ IDEA 2016.1.2JDK 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:
<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:
<?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 了:
<?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:
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:
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:
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:
<%@ 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 方法:
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 中添加方法,映射到批量添加用户页面:
// 指向批量添加用户页面 @RequestMapping("/users") public String users() { return "users"; }
在 pages 下新建页面 users.jsp:
<%@ 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 中添加如下方法:
// 添加用户,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"; }
然后,创建一个页面,返插入结果:
<%@ 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研究却不得不兼顾项目的研究生) 。
相关文章推荐
- 分享微信开发Html5轻游戏中的几个坑
- 一个jar包里的网站
- 一个jar包里的网站之文件上传
- 一个jar包里的网站之返回对媒体类型
- Spring和ThreadLocal
- Spring Boot 开发微服务
- Spring整合Quartz(JobDetailBean方式)
- Spring整合Quartz(JobDetailBean方式)
- 如何使用Visual Studio 2010在数据库中生成随机测试数据
- win2008 R2服务器下修改MySQL 5.5数据库data目录的方法
- Windows Server 2003下修改MySQL 5.5数据库data目录
- 对 jQuery 中 data 方法的误解分析
- C# MVC模式下商品抽奖功能实现
- Zend的MVC机制使用分析(二)
- ASP.NET MVC 4 捆绑和缩小实例介绍
- ASP.NET Mvc开发之查询数据
- ASP.NET MVC中将控制器分离到类库的实现
- asp.net实现在非MVC中使用Razor模板引擎的方法
- ASP.NET MVC中的AJAX应用