Spring 5 MVC + Hibernate 5
Spring 5 MVC + Hibernate 5示例
创建Spring 5 MVC Web应用程序,处理表单提交,集成hibernate 5连接到后端数据库,并为输入表单字段验证添加hibernate验证器。
创建一个简单的屏幕,可以在其中添加用户字段(名称和电子邮件)。首先验证这些细节,然后使用hibernate将其存储在Mysql数据库中。该页面还将列出所有存储的用户。
目录
开发环境
- Eclipse Oxygen.3a Release (4.7.3a)
- JDK 1.8
- Spring 5.0.0.RELEASE
- Hibernate 5.2.11.Final
- Hibernate验证器5.4.1.Final
- Servlets 3.1.0
- Mysql 8.0.11
- Tomcat 7 maven plugin 2.2
项目结构
该项目具有典型的maven Web应用程序结构。
Maven依赖
查找用于在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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ibm.moses.spring5</groupId>
<artifactId>spring5-mvc-hibernate</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
<spring.version>5.0.0.RELEASE</spring.version>
<hibernate.version>5.2.11.Final</hibernate.version>
<hibernate.validator>5.4.1.Final</hibernate.validator>
<c3p0.version>0.9.5.2</c3p0.version>
<jstl.version>1.2.1</jstl.version>
<tld.version>1.1.2</tld.version>
<servlets.version>3.1.0</servlets.version>
<jsp.version>2.3.1</jsp.version>
<hsqldb.version>1.8.0.10</hsqldb.version>
<mysql.version>8.0.11</mysql.version>
</properties>
<dependencies>
<!-- Spring MVC Dependency -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Spring ORM -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- Hibernate ORM -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- Hibernate-C3P0 Integration -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>${hibernate.version}</version>
</dependency>
<!-- c3p0 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>${c3p0.version}</version>
</dependency>
<!-- Hibernate Validator -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>${hibernate.validator}</version>
</dependency>
<!-- JSTL Dependency -->
<dependency>
<groupId>javax.servlet.jsp.jstl</groupId>
<artifactId>javax.servlet.jsp.jstl-api</artifactId>
<version>${jstl.version}</version>
</dependency>
<dependency>
<groupId>taglibs</groupId>
<artifactId>standard</artifactId>
<version>${tld.version}</version>
</dependency>
<!-- Servlet Dependency -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlets.version}</version>
<scope>provided</scope>
</dependency>
<!-- JSP Dependency -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>${jsp.version}</version>
<scope>provided</scope>
</dependency>
<!-- HSQL Dependency -->
<dependency>
<groupId>hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<version>${hsqldb.version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/java</sourceDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.5.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<!-- Embedded Apache Tomcat required for testing war -->
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
</project>
DispatcherServlet配置
随着Servlet 3.0规范的发布,可以配置(几乎)没有xml的Servlet容器。为此ServletContainerInitializer
,Servlet规范中有。在这个类中,您可以像在传统方式中那样注册过滤器,监听器,servlet等web.xml
。
Spring提供了SpringServletContainerInitializer
,知道如何处理WebApplicationInitializer
类。AbstractAnnotationConfigDispatcherServletInitializer
类实现WebMvcConfigurer,
内部实现WebApplicationInitializer
。它注册一个ContextLoaderlistener
(可选)和一个DispatcherServlet
并允许您轻松添加配置类以加载这两个类,并将过滤器应用于DispatcherServlet并提供servlet映射。
AppInitializer.java
package com.ibm.mose.demo.config;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { HibernateConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] { WebMvcConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
Spring WebMVC配置
下面给出了使用注释配置的 Spring MVC配置。
WebMvcConfig.java
package com.ibm.mose.demo.config;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;
@Configuration
@EnableWebMvc
@ComponentScan(basePackages = { "com.ibm.mose.demo"})
public class WebMvcConfig implements WebMvcConfigurer {
@Bean
public InternalResourceViewResolver resolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setViewClass(JstlView.class);
resolver.setPrefix("/WEB-INF/views/");
resolver.setSuffix(".jsp");
return resolver;
}
@Bean
public MessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages");
return source;
}
@Override
public Validator getValidator() {
LocalValidatorFactoryBean validator = new LocalValidatorFactoryBean();
validator.setValidationMessageSource(messageSource());
return validator;
}
}
-
WebMvcConfigurer
定义用于自定义或添加到通过使用启用的默认Spring MVC配置的选项@EnableWebMvc
。 -
@EnableWebMvc
启用默认的Spring MVC配置并注册所期望的Spring MVC基础架构组件DispatcherServlet
。 -
@Configuration
表示一个类声明了一个或多个@Bean
方法,并且可以由Spring容器处理,以便在运行时为这些bean生成bean定义和服务请求。 -
@ComponentScan
注释用于指定要扫描的基础包。将扫描使用@Component和@Configuration注释的任何类。 -
InternalResourceViewResolver
有助于将逻辑视图名称映射到直接查看某个预配置目录下的文件。 -
ResourceBundleMessageSource
使用指定的基本名称访问资源包(这里是消息)。 -
LocalValidatorFactoryBean
bootstraps ajavax.validation.ValidationFactory
并通过SpringValidator
接口以及JSR-303Validator
接口和ValidatorFactory
接口本身公开它。
休眠配置
示例中使用的Hibernate配置基于基于hibernate Java的配置。
HibernateConfig.java
package com.ibm.mose.demo.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.hibernate5.HibernateTransactionManager;
import org.springframework.orm.hibernate5.LocalSessionFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.ibm.mose.demo.model.User;
@Configuration
@EnableTransactionManagement
@ComponentScans(value = { @ComponentScan("com.ibm.mose.demo")})
public class HibernateConfig {
@Autowired
private ApplicationContext context;
@Bean
public LocalSessionFactoryBean getSessionFactory() {
LocalSessionFactoryBean factoryBean = new LocalSessionFactoryBean();
factoryBean.setConfigLocation(context.getResource("classpath:hibernate.cfg.xml"));
factoryBean.setAnnotatedClasses(User.class);
return factoryBean;
}
@Bean
public HibernateTransactionManager getTransactionManager() {
HibernateTransactionManager transactionManager = new HibernateTransactionManager();
transactionManager.setSessionFactory(getSessionFactory().getObject());
return transactionManager;
}
}
-
LocalSessionFactoryBean
创建一个HibernateSessionFactory
。这是在Spring应用程序上下文中设置共享Hibernate SessionFactory的常用方法。 -
EnableTransactionManagement
支持Spring的注释驱动的事务管理功能。 -
HibernateTransactionManager
将Hibernate Session从指定的工厂绑定到线程,可能允许每个工厂一个线程绑定的Session。此事务管理器适用于使用单个HibernateSessionFactory
进行事务性数据访问的应用程序,但它也支持DataSource
在事务内直接访问,即纯JDBC。
hibernate.cfg.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="connection.password">123456</property>
<property name="connection.username">root</property>
<property name="connection.url">jdbc:mysql://localhost:3306/test?serverTimezone=UTC</property>
<property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
<property name="hibernate.archive.autodetection">class,hbm</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="hibernate.c3p0.min_size">5</property>
<property name="hibernate.c3p0.max_size">20</property>
<property name="hibernate.c3p0.acquire_increment">2</property>
<property name="hibernate.c3p0.acquire_increment">1800</property>
<property name="hibernate.c3p0.max_statements">150</property>
</session-factory>
</hibernate-configuration>
Spring Controller和REST映射
控制器类有两个简单的REST映射为GET
和POST
操作。如果未验证输入字段,则返回相同的表单bean以显示错误消息。否则返回刷新视图。
UserController.java
package com.ibm.mose.demo.controller;
import java.util.Locale;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import com.ibm.mose.demo.model.User;
import com.ibm.mose.demo.service.UserService;
@Controller
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/")
public String userForm(Locale locale, Model model) {
model.addAttribute("users", userService.list());
return "editUsers";
}
@ModelAttribute("user")
public User formBackingObject() {
return new User();
}
@PostMapping("/addUser")
public String saveUser(@ModelAttribute("user") @Valid User user, BindingResult result, Model model) {
if (result.hasErrors()) {
model.addAttribute("users", userService.list());
return "editUsers";
}
userService.save(user);
return "redirect:/";
}
}
服务和DAO层
服务和DAO层是带有加注解的正常服务组件@Service
和@Repository
注释。@Transactional
在服务层应用注释以获得事务支持。
UserService接口和Impl
package com.ibm.mose.demo.service;
import java.util.List;
import com.ibm.mose.demo.model.User;
public interface UserService {
void save(User user);
List<User> list();
}
package com.ibm.mose.demo.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ibm.mose.demo.dao.UserDao;
import com.ibm.mose.demo.model.User;
@Service
public class UserServiceImp implements UserService {
@Autowired
private UserDao userDao;
@Transactional
public void save(User user) {
userDao.save(user);
}
@Transactional(readOnly = true)
public List<User> list() {
return userDao.list();
}
}
UserDao接口和Impl
package com.ibm.mose.demo.dao;
import java.util.List;
import com.ibm.mose.demo.model.User;
public interface UserDao {
void save(User user);
List<User> list();
}
package com.ibm.mose.demo.dao;
import java.util.List;
import javax.persistence.TypedQuery;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.ibm.mose.demo.model.User;
@Repository
public class UserDaoImp implements UserDao {
@Autowired
private SessionFactory sessionFactory;
@Override
public void save(User user) {
sessionFactory.getCurrentSession().save(user);
}
@Override
public List<User> list() {
@SuppressWarnings("unchecked")
TypedQuery<User> query = sessionFactory.getCurrentSession().createQuery("from User");
return query.getResultList();
}
}
User.java
package com.ibm.mose.demo.model;
import static javax.persistence.GenerationType.IDENTITY;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.validation.constraints.Size;
import org.hibernate.validator.constraints.Email;
import org.hibernate.validator.constraints.NotEmpty;
/**
* User entity. @author Moses modify Persistence Tools
*/
@Entity
@Table(name = "user", catalog = "test")
public class User implements java.io.Serializable {
// Fields
private Long id;
private Integer age;
private String email;
private String name;
// Constructors
/** default constructor */
public User() {
}
/** full constructor */
public User(Integer age, String email, String name) {
this.age = age;
this.email = email;
this.name = name;
}
// Property accessors
@Id
@GeneratedValue(strategy = IDENTITY)
@Column(name = "id", unique = true, nullable = false)
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "age")
public Integer getAge() {
return this.age;
}
public void setAge(Integer age) {
this.age = age;
}
@Column(name = "email", length = 50, unique = true)
@Email(message = "{user.email.invalid}")
@NotEmpty(message = "Please Enter your email")
public String getEmail() {
return this.email;
}
public void setEmail(String email) {
this.email = email;
}
@Column(name = "name", length = 30)
@Size(max = 20, min = 3, message = "{user.name.invalid}")
@NotEmpty(message = "Please Enter your name")
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
查看和消息资源
最后,使用JSP文件和消息资源包使用。
editUsers.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Spring5 MVC Hibernate Demo</title>
<style type="text/css">
.error {
color: red;
}
table {
width: 50%;
border-collapse: collapse;
border-spacing: 0px;
}
table td {
border: 1px solid #565454;
padding: 20px;
}
</style>
</head>
<body>
<h1>Input Form</h1>
<form:form action="addUser" method="post" modelAttribute="user">
<table>
<tr>
<td>Name</td>
<td><form:input path="name" /> <br /> <form:errors
path="name" cssClass="error" /></td>
</tr>
<tr>
<td>Email</td>
<td><form:input path="email" /> <br /> <form:errors
path="email" cssClass="error" /></td>
</tr>
<tr>
<td colspan="2"><button type="submit">Submit</button></td>
</tr>
</table>
</form:form>
<h2>Users List</h2>
<table>
<tr>
<td><strong>Name</strong></td>
<td><strong>Email</strong></td>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.name}</td>
<td>${user.email}</td>
</tr>
</c:forEach>
</table>
</body>
</html>
messages.properties
user.name.invalid = Name entered is invalid. It must be between {2} and {1} characters.
user.email.invalid = Invalid email! Please enter valid email.
演示
让我们使用maven tomcat7插件运行应用程序。执行maven目标:mvn tomcat7:run
。
网址: http://localhost:8080
初始屏幕
输入验证无效
有效表格提交
检查服务器日志。
Hibernate: insert into test.user (age, email, name) values (?, ?, ?)
Hibernate: select user0_.id as id1_0_, user0_.age as age2_0_, user0_.email as e
mail3_0_, user0_.name as name4_0_ from test.user user0_