在本教程中,我们将使用基于注解的配置集成Spring和Hibernate。 我们将开发包含表单要求用户输入一个简单的CRUD为导向Web应用程序,使用Hibernate保存输入的数据到 MySQL 数据库,从数据库和更新检索记录或删除它们在事务中,全部采用注解配置。
使用以下技术:
  • Spring 4.0.6.RELEASE
  • Hibernate Core 4.3.6.Final
  • validation-api 1.1.0.Final
  • hibernate-validator 5.1.3.Final
  • MySQL Server 5.6
  • Maven 3
  • JDK 1.7
  • Tomcat 8.0.21
  • Eclipse JUNO Service Release 2
  • TestNG 6.9.4
  • Mockito 1.10.19
  • DBUnit 2.2
  • H2 Database 1.4.187

现在,让我们开始

第1步:创建目录结构
以下是最终的项目结构:

现在让我们来添加上每个细节上述结构中提到的内容。
第2步:更新 pom.xml,包括所需的依赖关系
  1. <?xml version="1.0"?>
  2. <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
  3. xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  4.  
  5. <modelVersion>4.0.0</modelVersion>
  6. <groupId>com.yiibai.springmvc</groupId>
  7. <artifactId>SpringHibernateExample</artifactId>
  8. <packaging>war</packaging>
  9. <version>1.0.0</version>
  10. <name>SpringHibernateExample</name>
  11.  
  12. <properties>
  13. <springframework.version>4.0.6.RELEASE</springframework.version>
  14. <hibernate.version>4.3.6.Final</hibernate.version>
  15. <mysql.connector.version>5.1.31</mysql.connector.version>
  16. <joda-time.version>2.3</joda-time.version>
  17. <testng.version>6.9.4</testng.version>
  18. <mockito.version>1.10.19</mockito.version>
  19. <h2.version>1.4.187</h2.version>
  20. <dbunit.version>2.2</dbunit.version>
  21. </properties>
  22.  
  23. <dependencies>
  24. <!-- Spring -->
  25. <dependency>
  26. <groupId>org.springframework</groupId>
  27. <artifactId>spring-core</artifactId>
  28. <version>${springframework.version}</version>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework</groupId>
  32. <artifactId>spring-web</artifactId>
  33. <version>${springframework.version}</version>
  34. </dependency>
  35. <dependency>
  36. <groupId>org.springframework</groupId>
  37. <artifactId>spring-webmvc</artifactId>
  38. <version>${springframework.version}</version>
  39. </dependency>
  40. <dependency>
  41. <groupId>org.springframework</groupId>
  42. <artifactId>spring-tx</artifactId>
  43. <version>${springframework.version}</version>
  44. </dependency>
  45. <dependency>
  46. <groupId>org.springframework</groupId>
  47. <artifactId>spring-orm</artifactId>
  48. <version>${springframework.version}</version>
  49. </dependency>
  50.  
  51. <!-- Hibernate -->
  52. <dependency>
  53. <groupId>org.hibernate</groupId>
  54. <artifactId>hibernate-core</artifactId>
  55. <version>${hibernate.version}</version>
  56. </dependency>
  57.  
  58. <!-- jsr303 validation -->
  59. <dependency>
  60. <groupId>javax.validation</groupId>
  61. <artifactId>validation-api</artifactId>
  62. <version>1.1.0.Final</version>
  63. </dependency>
  64. <dependency>
  65. <groupId>org.hibernate</groupId>
  66. <artifactId>hibernate-validator</artifactId>
  67. <version>5.1.3.Final</version>
  68. </dependency>
  69.  
  70. <!-- MySQL -->
  71. <dependency>
  72. <groupId>mysql</groupId>
  73. <artifactId>mysql-connector-java</artifactId>
  74. <version>${mysql.connector.version}</version>
  75. </dependency>
  76.  
  77. <!-- Joda-Time -->
  78. <dependency>
  79. <groupId>joda-time</groupId>
  80. <artifactId>joda-time</artifactId>
  81. <version>${joda-time.version}</version>
  82. </dependency>
  83.  
  84. <!-- To map JodaTime with database type -->
  85. <dependency>
  86. <groupId>org.jadira.usertype</groupId>
  87. <artifactId>usertype.core</artifactId>
  88. <version>3.0.0.CR1</version>
  89. </dependency>
  90.  
  91. <!-- Servlet+JSP+JSTL -->
  92. <dependency>
  93. <groupId>javax.servlet</groupId>
  94. <artifactId>javax.servlet-api</artifactId>
  95. <version>3.1.0</version>
  96. </dependency>
  97. <dependency>
  98. <groupId>javax.servlet.jsp</groupId>
  99. <artifactId>javax.servlet.jsp-api</artifactId>
  100. <version>2.3.1</version>
  101. </dependency>
  102. <dependency>
  103. <groupId>javax.servlet</groupId>
  104. <artifactId>jstl</artifactId>
  105. <version>1.2</version>
  106. </dependency>
  107.  
  108. <!-- Testing dependencies -->
  109. <dependency>
  110. <groupId>org.springframework</groupId>
  111. <artifactId>spring-test</artifactId>
  112. <version>${springframework.version}</version>
  113. <scope>test</scope>
  114. </dependency>
  115. <dependency>
  116. <groupId>org.testng</groupId>
  117. <artifactId>testng</artifactId>
  118. <version>${testng.version}</version>
  119. <scope>test</scope>
  120. </dependency>
  121. <dependency>
  122. <groupId>org.mockito</groupId>
  123. <artifactId>mockito-all</artifactId>
  124. <version>${mockito.version}</version>
  125. <scope>test</scope>
  126. </dependency>
  127. <dependency>
  128. <groupId>com.h2database</groupId>
  129. <artifactId>h2</artifactId>
  130. <version>${h2.version}</version>
  131. <scope>test</scope>
  132. </dependency>
  133. <dependency>
  134. <groupId>dbunit</groupId>
  135. <artifactId>dbunit</artifactId>
  136. <version>${dbunit.version}</version>
  137. <scope>test</scope>
  138. </dependency>
  139.  
  140. </dependencies>
  141.  
  142. <build>
  143. <pluginManagement>
  144. <plugins>
  145. <plugin>
  146. <groupId>org.apache.maven.plugins</groupId>
  147. <artifactId>maven-war-plugin</artifactId>
  148. <version>2.4</version>
  149. <configuration>
  150. <warSourceDirectory>src/main/webapp</warSourceDirectory>
  151. <warName>SpringHibernateExample</warName>
  152. <failOnMissingWebXml>false</failOnMissingWebXml>
  153. </configuration>
  154. </plugin>
  155. </plugins>
  156. </pluginManagement>
  157. <finalName>SpringHibernateExample</finalName>
  158. </build>
  159. </project>

首先要注意这里是 maven-war-plugin 插件声明。由于我们使用的是全注解的配置,所以不包函 web.xml 文件在项目中,所以我们需要配置这个插件以避免 Maven 构建 war 包失败。因为在这个例子中,我们将用一个表单来接受来自用户的输入,我们也需要验证用户的输入。在这里我们将选择JSR303验证,所以我们包括验证,API 代表了规范,hibernate-validator它代表本规范的实现。hibernate-validator 还提供了一些它自己的注解(@Email,@NotEmpty等)不属于规范的一部分。

伴随着这一点,我们也包括 JSP/Servlet/Jstl 依赖关系,也将需要为使用的 servlet API和JSTL视图在代码中。在一般情况下,容器可能已经包含了这些库,从而在 pom.xml 中“提供”了我们可以设置的范围。

步骤3:配置Hibernate

com.yiibai.springmvc.configuration.HibernateConfiguration

  1. package com.yiibai.springmvc.configuration;
  2.  
  3. import java.util.Properties;
  4.  
  5. import javax.sql.DataSource;
  6.  
  7. import org.hibernate.SessionFactory;
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.context.annotation.Bean;
  10. import org.springframework.context.annotation.ComponentScan;
  11. import org.springframework.context.annotation.Configuration;
  12. import org.springframework.context.annotation.PropertySource;
  13. import org.springframework.core.env.Environment;
  14. import org.springframework.jdbc.datasource.DriverManagerDataSource;
  15. import org.springframework.orm.hibernate4.HibernateTransactionManager;
  16. import org.springframework.orm.hibernate4.LocalSessionFactoryBean;
  17. import org.springframework.transaction.annotation.EnableTransactionManagement;
  18.  
  19. @Configuration
  20. @EnableTransactionManagement
  21. @ComponentScan({ "com.yiibai.springmvc.configuration" })
  22. @PropertySource(value = { "classpath:application.properties" })
  23. public class HibernateConfiguration {
  24.  
  25. @Autowired
  26. private Environment environment;
  27.  
  28. @Bean
  29. public LocalSessionFactoryBean sessionFactory() {
  30. LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
  31. sessionFactory.setDataSource(dataSource());
  32. sessionFactory.setPackagesToScan(new String[] { "com.yiibai.springmvc.model" });
  33. sessionFactory.setHibernateProperties(hibernateProperties());
  34. return sessionFactory;
  35. }
  36.  
  37. @Bean
  38. public DataSource dataSource() {
  39. DriverManagerDataSource dataSource = new DriverManagerDataSource();
  40. dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName"));
  41. dataSource.setUrl(environment.getRequiredProperty("jdbc.url"));
  42. dataSource.setUsername(environment.getRequiredProperty("jdbc.username"));
  43. dataSource.setPassword(environment.getRequiredProperty("jdbc.password"));
  44. return dataSource;
  45. }
  46.  
  47. private Properties hibernateProperties() {
  48. Properties properties = new Properties();
  49. properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect"));
  50. properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql"));
  51. properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql"));
  52. return properties;
  53. }
  54.  
  55. @Bean
  56. @Autowired
  57. public HibernateTransactionManager transactionManager(SessionFactory s) {
  58. HibernateTransactionManager txManager = new HibernateTransactionManager();
  59. txManager.setSessionFactory(s);
  60. return txManager;
  61. }
  62. } 

@Configuration表示该类包含注解为 @Bean生产Bean管理是由Spring容器的一个或多个bean的方法。在我们的例子中,这个类代表hibernate配置。

@ComponentScan 相当于 context:component-scan base-package="..." 在xml文件中配置, 提供Spring在哪里寻找管理 beans/classes。

@EnableTransactionManagement 相当于 Spring’s tx:* XML 命名空间, 使Spring注解驱动事务管理能力。

@PropertySource 用于声明一组属性(在属性中定义的应用程序类路径文件)在Spring运行时 Environment, 提供了灵活性,可以在不同的应用环境的不同值。

下面是这篇文章中使用的属性文件。

/src/main/resources/application.properties

  1. jdbc.driverClassName = com.mysql.jdbc.Driver
  2. jdbc.url = jdbc:mysql://localhost:3306/yiibai
  3. jdbc.username = root
  4. jdbc.password = passwd123
  5. hibernate.dialect = org.hibernate.dialect.MySQLDialect
  6. hibernate.show_sql = true
  7. hibernate.format_sql = true
第4步:配置Spring MVC

com.yiibai.springmvc.configuration.AppConfig

  1. package com.yiibai.springmvc.configuration;
  2.  
  3. import org.springframework.context.MessageSource;
  4. import org.springframework.context.annotation.Bean;
  5. import org.springframework.context.annotation.ComponentScan;
  6. import org.springframework.context.annotation.Configuration;
  7. import org.springframework.context.support.ResourceBundleMessageSource;
  8. import org.springframework.web.servlet.ViewResolver;
  9. import org.springframework.web.servlet.config.annotation.EnableWebMvc;
  10. import org.springframework.web.servlet.view.InternalResourceViewResolver;
  11. import org.springframework.web.servlet.view.JstlView;
  12.  
  13. @Configuration
  14. @EnableWebMvc
  15. @ComponentScan(basePackages = "com.yiibai.springmvc")
  16. public class AppConfig {
  17.  
  18. @Bean
  19. public ViewResolver viewResolver() {
  20. InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
  21. viewResolver.setViewClass(JstlView.class);
  22. viewResolver.setPrefix("/WEB-INF/views/");
  23. viewResolver.setSuffix(".jsp");
  24. return viewResolver;
  25. }
  26.  
  27. @Bean
  28. public MessageSource messageSource() {
  29. ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
  30. messageSource.setBasename("messages");
  31. return messageSource;
  32. }
  33. }
同样,@Configuration标志着这一类配置类如上所述与器件扫描是指包位置找到相关的Bean类。
@EnableWebMvc相当于mvc:annotation-driven 在XML文件中。
ViewResolver方法配置一个ViewResolver来找出真正的视图。

在这篇文章中,我们提交表单并验证用户输入(通过JSR303注解)。在校验失败后,默认的错误消息会显示。要通过自己的自定义覆盖默认的[国际化]从外部消息包的消息[.properties文件],我们需要配置一个ResourceBundleMessageSource。messageSource方法有同样的目的。请注意,以basename方法提供的参数(消息)。Spring将搜索应用程序类路径中一个名为 messages.properties 的文件。让我们添加的文件:

/src/main/resources/messages.properties

  1. Size.employee.name=Name must be between {2} and {1} characters long
  2. NotNull.employee.joiningDate=Joining Date can not be blank
  3. NotNull.employee.salary=Salary can not be blank
  4. Digits.employee.salary=Only numeric data with max 8 digits and with max 2 precision is allowed
  5. NotEmpty.employee.ssn=SSN can not be blank
  6. typeMismatch=Invalid format
  7. non.unique.ssn=SSN {0} already exist. Please fill in different value.
请注意,上述消息按照特定的模式:
  1. {ValidationAnnotationClass}.{modelObject}.{fieldName} 

此外,根据具体注解(如@Size),你也可以用传递参数给这些消息{0},{1},..{i}索引。

步骤5:配置初始化器类

com.yiibai.springmvc.configuration.AppInitializer

  1. package com.yiibai.springmvc.configuration;
  2.  
  3. import javax.servlet.ServletContext;
  4. import javax.servlet.ServletException;
  5. import javax.servlet.ServletRegistration;
  6.  
  7. import org.springframework.web.WebApplicationInitializer;
  8. import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
  9. import org.springframework.web.servlet.DispatcherServlet;
  10.  
  11. public class AppInitializer implements WebApplicationInitializer {
  12.  
  13. public void onStartup(ServletContext container) throws ServletException {
  14.  
  15. AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
  16. ctx.register(AppConfig.class);
  17. ctx.setServletContext(container);
  18.  
  19. ServletRegistration.Dynamic servlet = container.addServlet(
  20. "dispatcher", new DispatcherServlet(ctx));
  21.  
  22. servlet.setLoadOnStartup(1);
  23. servlet.addMapping("/");
  24. }
  25.  
  26. } 

上面的内容类似于web.xml,因为我们使用的是前端控制器 DispatcherServlet 的内容,分配映射(URL模式的XML),而不是提供给Spring配置文件(spring-servlet.xml)的路径,在这里我们正在注册的配置类。

更新:请注意,上面的类可以写成更加简洁[最佳方法],通过扩展 AbstractAnnotationConfigDispatcherServletInitializer 基类,如下所示:

  1. package com.yiibai.springmvc.configuration;
  2.  
  3. import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
  4.  
  5. public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
  6.  
  7. @Override
  8. protected Class<?>[] getRootConfigClasses() {
  9. return new Class[] { AppConfig.class };
  10. }
  11.  
  12. @Override
  13. protected Class<?>[] getServletConfigClasses() {
  14. return null;
  15. }
  16.  
  17. @Override
  18. protected String[] getServletMappings() {
  19. return new String[] { "/" };
  20. }
  21.  
  22. }
第6步:添加控制器来处理请求
添加控制器这将有助于处理 GET和POST请求。

com.yiibai.springmvc.controller.AppController

  1. package com.yiibai.springmvc.controller;
  2.  
  3. import java.util.List;
  4. import java.util.Locale;
  5.  
  6. import javax.validation.Valid;
  7.  
  8. import org.springframework.beans.factory.annotation.Autowired;
  9. import org.springframework.context.MessageSource;
  10. import org.springframework.stereotype.Controller;
  11. import org.springframework.ui.ModelMap;
  12. import org.springframework.validation.BindingResult;
  13. import org.springframework.validation.FieldError;
  14. import org.springframework.web.bind.annotation.PathVariable;
  15. import org.springframework.web.bind.annotation.RequestMapping;
  16. import org.springframework.web.bind.annotation.RequestMethod;
  17.  
  18. import com.yiibai.springmvc.model.Employee;
  19. import com.yiibai.springmvc.service.EmployeeService;
  20.  
  21. @Controller
  22. @RequestMapping("/")
  23. public class AppController {
  24.  
  25. @Autowired
  26. EmployeeService service;
  27.  
  28. @Autowired
  29. MessageSource messageSource;
  30.  
  31. /*
  32. * This method will list all existing employees.
  33. */
  34. @RequestMapping(value = { "/", "/list" }, method = RequestMethod.GET)
  35. public String listEmployees(ModelMap model) {
  36.  
  37. List<Employee> employees = service.findAllEmployees();
  38. model.addAttribute("employees", employees);
  39. return "allemployees";
  40. }
  41.  
  42. /*
  43. * This method will provide the medium to add a new employee.
  44. */
  45. @RequestMapping(value = { "/new" }, method = RequestMethod.GET)
  46. public String newEmployee(ModelMap model) {
  47. Employee employee = new Employee();
  48. model.addAttribute("employee", employee);
  49. model.addAttribute("edit", false);
  50. return "registration";
  51. }
  52.  
  53. /*
  54. * This method will be called on form submission, handling POST request for
  55. * saving employee in database. It also validates the user input
  56. */
  57. @RequestMapping(value = { "/new" }, method = RequestMethod.POST)
  58. public String saveEmployee(@Valid Employee employee, BindingResult result,
  59. ModelMap model) {
  60.  
  61. if (result.hasErrors()) {
  62. return "registration";
  63. }
  64.  
  65. /*
  66. * Preferred way to achieve uniqueness of field [ssn] should be implementing custom @Unique annotation
  67. * and applying it on field [ssn] of Model class [Employee].
  68. *
  69. * Below mentioned peace of code [if block] is to demonstrate that you can fill custom errors outside the validation
  70. * framework as well while still using internationalized messages.
  71. *
  72. */
  73. if(!service.isEmployeeSsnUnique(employee.getId(), employee.getSsn())){
  74. FieldError ssnError =new FieldError("employee","ssn",messageSource.getMessage("non.unique.ssn", new String[]{employee.getSsn()}, Locale.getDefault()));
  75. result.addError(ssnError);
  76. return "registration";
  77. }
  78.  
  79. service.saveEmployee(employee);
  80.  
  81. model.addAttribute("success", "Employee " + employee.getName() + " registered successfully");
  82. return "success";
  83. }
  84.  
  85. /*
  86. * This method will provide the medium to update an existing employee.
  87. */
  88. @RequestMapping(value = { "/edit-{ssn}-employee" }, method = RequestMethod.GET)
  89. public String editEmployee(@PathVariable String ssn, ModelMap model) {
  90. Employee employee = service.findEmployeeBySsn(ssn);
  91. model.addAttribute("employee", employee);
  92. model.addAttribute("edit", true);
  93. return "registration";
  94. }
  95.  
  96. /*
  97. * This method will be called on form submission, handling POST request for
  98. * updating employee in database. It also validates the user input
  99. */
  100. @RequestMapping(value = { "/edit-{ssn}-employee" }, method = RequestMethod.POST)
  101. public String updateEmployee(@Valid Employee employee, BindingResult result,
  102. ModelMap model, @PathVariable String ssn) {
  103.  
  104. if (result.hasErrors()) {
  105. return "registration";
  106. }
  107.  
  108. if(!service.isEmployeeSsnUnique(employee.getId(), employee.getSsn())){
  109. FieldError ssnError =new FieldError("employee","ssn",messageSource.getMessage("non.unique.ssn", new String[]{employee.getSsn()}, Locale.getDefault()));
  110. result.addError(ssnError);
  111. return "registration";
  112. }
  113.  
  114. service.updateEmployee(employee);
  115.  
  116. model.addAttribute("success", "Employee " + employee.getName() + " updated successfully");
  117. return "success";
  118. }
  119.  
  120. /*
  121. * This method will delete an employee by it's SSN value.
  122. */
  123. @RequestMapping(value = { "/delete-{ssn}-employee" }, method = RequestMethod.GET)
  124. public String deleteEmployee(@PathVariable String ssn) {
  125. service.deleteEmployeeBySsn(ssn);
  126. return "redirect:/list";
  127. }
  128.  
  129. } 

这是一个非常直接的基于Spring的控制器。 @Controller表明这个类是一个控制器在处理与模式映射@RequestMapping请求。这里用“/”,它被作为默认的控制器。

listEmployees方法标注了@ RequestMethod.GET,同时处理默认的网址 “/” 和 ‘/list’。它充当处理应用初始页面,显示现有雇员的列表。

newEmployee方法处理新员工注册页面的GET请求, 表示通过模型 Employee 对象支持页面。

方法 saveEmployee 被注解为@ RequestMethod.POST,并且将处理新员工登记表单提交 POST 请求 (‘/new’)。注间这个方法的参数和它们的顺序。

@Valid要求Spring来验证相关的对象(Employee)。 BindingResult包含此验证,并可能在此验证过程中发生任何错误的结果。请注意,BindingResult必须出现在验证对象,否则Spring将无法验证并且抛出一个异常。 如果验证失败,自定义错误信息(因为我们已经配置在步骤4)中显示。

我们还包括代码检查SSN唯一性,因为它声明要在数据库中具有唯一必。保存/更新员工之前要检查,如果SSN是否独一无二。如果没有,我们生成验证错误和重定向到注册页面。 这个代码展示出一种方式来填充在自定义错误校验框架之外,同时仍使用国际化的信息。

第7步:添加DAO层

com.yiibai.springmvc.dao.AbstractDao

  1. package com.yiibai.springmvc.dao;
  2.  
  3. import java.io.Serializable;
  4.  
  5. import java.lang.reflect.ParameterizedType;
  6.  
  7. import org.hibernate.Criteria;
  8. import org.hibernate.Session;
  9. import org.hibernate.SessionFactory;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11.  
  12. public abstract class AbstractDao<PK extends Serializable, T> {
  13.  
  14. private final Class<T> persistentClass;
  15.  
  16. @SuppressWarnings("unchecked")
  17. public AbstractDao(){
  18. this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1];
  19. }
  20.  
  21. @Autowired
  22. private SessionFactory sessionFactory;
  23.  
  24. protected Session getSession(){
  25. return sessionFactory.getCurrentSession();
  26. }
  27.  
  28. @SuppressWarnings("unchecked")
  29. public T getByKey(PK key) {
  30. return (T) getSession().get(persistentClass, key);
  31. }
  32.  
  33. public void persist(T entity) {
  34. getSession().persist(entity);
  35. }
  36.  
  37. public void delete(T entity) {
  38. getSession().delete(entity);
  39. }
  40.  
  41. protected Criteria createEntityCriteria(){
  42. return getSession().createCriteria(persistentClass);
  43. }
  44.  
  45. } 

这个通用类是所有的DAO实现类的基类。它提供包装方法也是常见的hibernate 操作。

注意上面,我们已经在前面第3步创建了SessionFactory,在这里将自动装配。

com.yiibai.springmvc.dao.EmployeeDao

  1. package com.yiibai.springmvc.dao;
  2.  
  3. import java.util.List;
  4.  
  5. import com.yiibai.springmvc.model.Employee;
  6.  
  7. public interface EmployeeDao {
  8.  
  9. Employee findById(int id);
  10.  
  11. void saveEmployee(Employee employee);
  12.  
  13. void deleteEmployeeBySsn(String ssn);
  14.  
  15. List<Employee> findAllEmployees();
  16.  
  17. Employee findEmployeeBySsn(String ssn);
  18.  
  19. }

com.yiibai.springmvc.dao.EmployeeDaoImpl

  1. package com.yiibai.springmvc.dao;
  2.  
  3. import java.util.List;
  4.  
  5. import org.hibernate.Criteria;
  6. import org.hibernate.Query;
  7. import org.hibernate.criterion.Restrictions;
  8. import org.springframework.stereotype.Repository;
  9.  
  10. import com.yiibai.springmvc.model.Employee;
  11.  
  12. @Repository("employeeDao")
  13. public class EmployeeDaoImpl extends AbstractDao<Integer, Employee> implements EmployeeDao {
  14.  
  15. public Employee findById(int id) {
  16. return getByKey(id);
  17. }
  18.  
  19. public void saveEmployee(Employee employee) {
  20. persist(employee);
  21. }
  22.  
  23. public void deleteEmployeeBySsn(String ssn) {
  24. Query query = getSession().createSQLQuery("delete from Employee where ssn = :ssn");
  25. query.setString("ssn", ssn);
  26. query.executeUpdate();
  27. }
  28.  
  29. @SuppressWarnings("unchecked")
  30. public List<Employee> findAllEmployees() {
  31. Criteria criteria = createEntityCriteria();
  32. return (List<Employee>) criteria.list();
  33. }
  34.  
  35. public Employee findEmployeeBySsn(String ssn) {
  36. Criteria criteria = createEntityCriteria();
  37. criteria.add(Restrictions.eq("ssn", ssn));
  38. return (Employee) criteria.uniqueResult();
  39. }
  40. }
第8步:添加服务层

com.yiibai.springmvc.service.EmployeeService

  1. package com.yiibai.springmvc.service;
  2.  
  3. import java.util.List;
  4.  
  5. import com.yiibai.springmvc.model.Employee;
  6.  
  7. public interface EmployeeService {
  8.  
  9. Employee findById(int id);
  10.  
  11. void saveEmployee(Employee employee);
  12.  
  13. void updateEmployee(Employee employee);
  14.  
  15. void deleteEmployeeBySsn(String ssn);
  16.  
  17. List<Employee> findAllEmployees();
  18.  
  19. Employee findEmployeeBySsn(String ssn);
  20.  
  21. boolean isEmployeeSsnUnique(Integer id, String ssn);
  22.  
  23. }

com.yiibai.springmvc.service.EmployeeServiceImpl

  1. package com.yiibai.springmvc.service;
  2.  
  3. import java.util.List;
  4.  
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.stereotype.Service;
  7. import org.springframework.transaction.annotation.Transactional;
  8.  
  9. import com.yiibai.springmvc.dao.EmployeeDao;
  10. import com.yiibai.springmvc.model.Employee;
  11.  
  12. @Service("employeeService")
  13. @Transactional
  14. public class EmployeeServiceImpl implements EmployeeService {
  15.  
  16. @Autowired
  17. private EmployeeDao dao;
  18.  
  19. public Employee findById(int id) {
  20. return dao.findById(id);
  21. }
  22.  
  23. public void saveEmployee(Employee employee) {
  24. dao.saveEmployee(employee);
  25. }
  26.  
  27. /*
  28. * Since the method is running with Transaction, No need to call hibernate update explicitly.
  29. * Just fetch the entity from db and update it with proper values within transaction.
  30. * It will be updated in db once transaction ends.
  31. */
  32. public void updateEmployee(Employee employee) {
  33. Employee entity = dao.findById(employee.getId());
  34. if(entity!=null){
  35. entity.setName(employee.getName());
  36. entity.setJoiningDate(employee.getJoiningDate());
  37. entity.setSalary(employee.getSalary());
  38. entity.setSsn(employee.getSsn());
  39. }
  40. }
  41.  
  42. public void deleteEmployeeBySsn(String ssn) {
  43. dao.deleteEmployeeBySsn(ssn);
  44. }
  45.  
  46. public List<Employee> findAllEmployees() {
  47. return dao.findAllEmployees();
  48. }
  49.  
  50. public Employee findEmployeeBySsn(String ssn) {
  51. return dao.findEmployeeBySsn(ssn);
  52. }
  53.  
  54. public boolean isEmployeeSsnUnique(Integer id, String ssn) {
  55. Employee employee = findEmployeeBySsn(ssn);
  56. return ( employee == null || ((id != null) && (employee.getId() == id)));
  57. }
  58.  
  59. } 

上面最有趣的部分是 @Transactional 它开始在每个方法启动一个事务,并提交其上的每个方法退出(或回滚,如果方法失败,会发生是一个错误)。 注意,因为该事务是在方法范围,和内部的方法,我们将使用DAO,DAO方法将在同一事务内执行。

第9步:创建域实体类(POJO)
让我们创建实际的员工实体数据表。

com.yiibai.springmvc.model.Employee

  1. package com.yiibai.springmvc.model;
  2.  
  3. import java.math.BigDecimal;
  4.  
  5. import javax.persistence.Column;
  6. import javax.persistence.Entity;
  7. import javax.persistence.GeneratedValue;
  8. import javax.persistence.GenerationType;
  9. import javax.persistence.Id;
  10. import javax.persistence.Table;
  11. import javax.validation.constraints.Digits;
  12. import javax.validation.constraints.NotNull;
  13. import javax.validation.constraints.Size;
  14.  
  15. import org.hibernate.annotations.Type;
  16. import org.hibernate.validator.constraints.NotEmpty;
  17. import org.joda.time.LocalDate;
  18. import org.springframework.format.annotation.DateTimeFormat;
  19.  
  20. @Entity
  21. @Table(name="EMPLOYEE")
  22. public class Employee {
  23.  
  24. @Id
  25. @GeneratedValue(strategy = GenerationType.IDENTITY)
  26. private int id;
  27.  
  28. @Size(min=3, max=50)
  29. @Column(name = "NAME", nullable = false)
  30. private String name;
  31.  
  32. @NotNull
  33. @DateTimeFormat(pattern="dd/MM/yyyy")
  34. @Column(name = "JOINING_DATE", nullable = false)
  35. @Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDate")
  36. private LocalDate joiningDate;
  37.  
  38. @NotNull
  39. @Digits(integer=8, fraction=2)
  40. @Column(name = "SALARY", nullable = false)
  41. private BigDecimal salary;
  42.  
  43. @NotEmpty
  44. @Column(name = "SSN", unique=true, nullable = false)
  45. private String ssn;
  46.  
  47. public int getId() {
  48. return id;
  49. }
  50.  
  51. public void setId(int id) {
  52. this.id = id;
  53. }
  54.  
  55. public String getName() {
  56. return name;
  57. }
  58.  
  59. public void setName(String name) {
  60. this.name = name;
  61. }
  62.  
  63. public LocalDate getJoiningDate() {
  64. return joiningDate;
  65. }
  66.  
  67. public void setJoiningDate(LocalDate joiningDate) {
  68. this.joiningDate = joiningDate;
  69. }
  70.  
  71. public BigDecimal getSalary() {
  72. return salary;
  73. }
  74.  
  75. public void setSalary(BigDecimal salary) {
  76. this.salary = salary;
  77. }
  78.  
  79. public String getSsn() {
  80. return ssn;
  81. }
  82.  
  83. public void setSsn(String ssn) {
  84. this.ssn = ssn;
  85. }
  86.  
  87. @Override
  88. public int hashCode() {
  89. final int prime = 31;
  90. int result = 1;
  91. result = prime * result + id;
  92. result = prime * result + ((ssn == null) ? 0 : ssn.hashCode());
  93. return result;
  94. }
  95.  
  96. @Override
  97. public boolean equals(Object obj) {
  98. if (this == obj)
  99. return true;
  100. if (obj == null)
  101. return false;
  102. if (!(obj instanceof Employee))
  103. return false;
  104. Employee other = (Employee) obj;
  105. if (id != other.id)
  106. return false;
  107. if (ssn == null) {
  108. if (other.ssn != null)
  109. return false;
  110. } else if (!ssn.equals(other.ssn))
  111. return false;
  112. return true;
  113. }
  114.  
  115. @Override
  116. public String toString() {
  117. return "Employee [id=" + id + ", name=" + name + ", joiningDate="
  118. + joiningDate + ", salary=" + salary + ", ssn=" + ssn + "]";
  119. }
  120.  
  121. }
这是注明使用JPA注解@Entity,@Table,@Column 使用 hibernate的具体注释@Type,我们正在使用提供数据库中的数据类型和LocalDate之间的映射标准的实体类。
@DateTimeFormat是一个 Spring 的具体注解声明,字段应该使用一个给定格式格式化日期时间。
第10步:添加视图/JSP

WEB-INF/views/allemployees.jsp [主页包含所有现有员工列表]

  1. <%@ page language="java" contentType="text/html; charset=utf-8"
  2. pageEncoding="uft-8"%>
  3. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  4. <html>
  5. <head>
  6. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  7. <title>University Enrollments</title>
  8.  
  9. <style>
  10. tr:first-child{
  11. font-weight: bold;
  12. background-color: #C6C9C4;
  13. }
  14. </style>
  15.  
  16. </head>
  17.  
  18. <body>
  19. <h2>List of Employees</h2>
  20. <table>
  21. <tr>
  22. <td>NAME</td><td>Joining Date</td><td>Salary</td><td>SSN</td><td></td>
  23. </tr>
  24. <c:forEach items="${employees}" var="employee">
  25. <tr>
  26. <td>${employee.name}</td>
  27. <td>${employee.joiningDate}</td>
  28. <td>${employee.salary}</td>
  29. <td><a href="<c:url value='/edit-${employee.ssn}-employee' />">${employee.ssn}</a></td>
  30. <td><a href="<c:url value='/delete-${employee.ssn}-employee' />">delete</a></td>
  31. </tr>
  32. </c:forEach>
  33. </table>
  34. <br/>
  35. <a href="<c:url value='/new' />">Add New Employee</a>
  36. </body>
  37. </html>

WEB-INF/views/registration.jsp [注册页面用来创建和保存在数据库中的新员工]

  1. <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
  2. pageEncoding="ISO-8859-1"%>
  3. <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%>
  4. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  5.  
  6. <html>
  7.  
  8. <head>
  9. <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
  10. <title>Employee Registration Form</title>
  11.  
  12. <style>
  13.  
  14. .error {
  15. color: #ff0000;
  16. }
  17. </style>
  18.  
  19. </head>
  20.  
  21. <body>
  22.  
  23. <h2>Registration Form</h2>
  24.  
  25. <form:form method="POST" modelAttribute="employee">
  26. <form:input type="hidden" path="id" id="id"/>
  27. <table>
  28. <tr>
  29. <td><label for="name">Name: </label> </td>
  30. <td><form:input path="name" id="name"/></td>
  31. <td><form:errors path="name" cssClass="error"/></td>
  32. </tr>
  33.  
  34. <tr>
  35. <td><label for="joiningDate">Joining Date: </label> </td>
  36. <td><form:input path="joiningDate" id="joiningDate"/></td>
  37. <td><form:errors path="joiningDate" cssClass="error"/></td>
  38. </tr>
  39.  
  40. <tr>
  41. <td><label for="salary">Salary: </label> </td>
  42. <td><form:input path="salary" id="salary"/></td>
  43. <td><form:errors path="salary" cssClass="error"/></td>
  44. </tr>
  45.  
  46. <tr>
  47. <td><label for="ssn">SSN: </label> </td>
  48. <td><form:input path="ssn" id="ssn"/></td>
  49. <td><form:errors path="ssn" cssClass="error"/></td>
  50. </tr>
  51.  
  52. <tr>
  53. <td colspan="3">
  54. <c:choose>
  55. <c:when test="${edit}">
  56. <input type="submit" value="Update"/>
  57. </c:when>
  58. <c:otherwise>
  59. <input type="submit" value="Register"/>
  60. </c:otherwise>
  61. </c:choose>
  62. </td>
  63. </tr>
  64. </table>
  65. </form:form>
  66. <br/>
  67. <br/>
  68. Go back to <a href="<c:url value='/list' />">List of All Employees</a>
  69. </body>
  70. </html>

WEB-INF/views/success.jsp [包括成功页面新员工创建一个确认,并链接回员工列表]

  1. <%@ page language="java" contentType="text/html; charset=utf-8"
  2. pageEncoding="utf-8"%>
  3. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
  4.  
  5. <html>
  6. <head>
  7. <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  8. <title>Registration Confirmation Page</title>
  9. </head>
  10. <body>
  11. message : ${success}
  12. <br/>
  13. <br/>
  14. Go back to <a href="<c:url value='/list' />">List of All Employees</a>
  15.  
  16. </body>
  17.  
  18. </html>
第11步:在数据库创建模式
  1. CREATE TABLE EMPLOYEE(
  2. id INT NOT NULL auto_increment,
  3. name VARCHAR(50) NOT NULL,
  4. joining_date DATE NOT NULL,
  5. salary DOUBLE NOT NULL,
  6. ssn VARCHAR(30) NOT NULL UNIQUE,
  7. PRIMARY KEY (id)
  8. );
第12步:构建,部署和运行应用程序

现在构建(参考提到的前面Eclipse教程)或通过Maven的命令行( mvn clean install). 部署War到Servlet3.0容器。

打开浏览器,浏览: http://localhost:8080/SpringHibernateExample/

现在,点击“Add New Employee”,并点击注册按钮但不填写任何信息:

现在填写详细信息

点击注册(Register),应该得到类似的东西:

点击列表,进入列表:

现在添加几个记录和以前一样:

现在点击第二记录的删除链接,它应该被删除了,如下图:

现在点击SSN链接(这是一个更新),第二要记录要更新:

现在,编辑一些字段,此外SSN值更改为现有的记录中的值:

尝试更新,你应该得到验证错误的SSN:

修正了错误,通过改变SSN以唯一值更新,然后查看记录的完整列表,看到更新有了变化(这里修改SSN为:123456):

最后,查看数据库在这时是:

Spring4 MVC+Hibernate4+MySQL+Maven使用注解集成实例的更多相关文章

  1. Spring 4 MVC+Hibernate 4+MySQL+Maven使用注解集成实例

    Spring 4 MVC+Hibernate 4+MySQL+Maven使用注解集成实例 转自:通过注解的方式集成Spring 4 MVC+Hibernate 4+MySQL+Maven,开发项目样例 ...

  2. Spring4 MVC Hibernate4集成 Annotation

    Spring4 MVC Hibernate4集成 Annotation 一.本文所用环境 二.工程目录 三.Maven添加依赖 四.新建数据库表 五.配置文件 六.Model层 七.DAO层 八.Se ...

  3. Spring4 MVC Hibernate4集成

      Spring4 MVC Hibernate4集成 一.    本文所用环境 Spring4.0.3.RELEASE Hibernate4.3.5.Final Mysql 二.    工程目录 三. ...

  4. Spring4 MVC+Hibernate4 Many-to-many连接表+MySQL+Maven实例

    这篇文章显示 Hibernate 的多对多实例,在 Spring MVC CRUD Web应用程序中连接表.我们将同时讨论管理多对多关系在视图和后端. 我们将使用应用程序的Web界面创建,更新,删除和 ...

  5. Spring4 MVC Hibernate4 maven集成

    http://www.cnblogs.com/leiOOlei/p/3727859.html

  6. 使用maven纯注解集成ssm

    1.配置springMVC框架 第一步:导入包依赖 <!--配置springMVC--> <dependency> <groupId>javax.servlet.j ...

  7. spring4.x hibernate4.x 整合 ehcache 注解 annotate

    [From] http://my.oschina.net/alexgaoyh/blog/348188

  8. spring4+springmvc+hibernate4 demo

    来自 CSDN . 其实下面的更好:加入了maven集成.Spring4 MVC Hibernate4集成 下面也是一篇讲的很详细的文章: hibernate4无法保存数据 而自己遇到的hiberna ...

  9. 【译】Spring 4 + Hibernate 4 + Mysql + Maven集成例子(注解 + XML)

    前言 译文链接:http://websystique.com/spring/spring4-hibernate4-mysql-maven-integration-example-using-annot ...

随机推荐

  1. nginx 实现 ajax 跨域请求

    原文:http://www.nginx.cn/4314.html   AJAX从一个域请求另一个域会有跨域的问题.那么如何在nginx上实现ajax跨域请求呢?要在nginx上启用跨域请求,需要添加a ...

  2. [SpringMVC+redis]自定义aop注解实现控制器访问次数限制

    原文:http://www.cnblogs.com/xiaoyangjia/p/3762150.html?utm_source=tuicool 我们需要根据IP去限制用户单位时间的访问次数,防止刷手机 ...

  3. ORACLE 数据库名、实例名、ORACLE_SID的区别

    数据库名(DB_NAME).实例名(Instance_name).以及操作系统环境变量(ORACLE_SID) 在ORACLE7.8数据库中只有数据库名(db_name)和数据库实例名(instanc ...

  4. MacBook安装office

    已更新至最新版Microsoft Office 2016 v16.13.18052304,完美支持macOS High Sierra 10.13.4,破解方法很简单,先安装Microsoft_Offi ...

  5. Druid对比Hadoop

    Druid对比Hadoop Hadoop 向世界证明, 花费很少的钱实现典型的解决方案, 将数据保存在一般的商用机器的数据仓库里是可行的. 当人们将自己的数据保存在Hadoop, 他们发现两个问题   ...

  6. Quartz与Spring的整合使用

    之前说到过Quartz的基本使用(猛戳这里看文章).在实际使用中,我们一般会将定时任务交由spring容器来管理.所以今天我们来说说Quartz与spring的整合. 咱们还是依照Quartz的三大元 ...

  7. java 方法传参方式: 按值调用

    程序设计语言中将参数传递给方法的几种方式: 按名调用(call by name): Algol 语言采用此方式, 已成为历史; 按值调用(call by value): 方法接收到的是调用者提供的 变 ...

  8. 关于Java异常java.lang.OutOfMemoryError: PermGen space

    内容来源: http://blog.csdn.net/fengyie007/article/details/1780375 PermGen space的全称是Permanent Generation ...

  9. 【DB2】DB2中rank(),dense_rank(),row_number()的用法

    1.准备测试数据 DROP TABLE oliver_1; ),SUB_NO ),SCORE int); ,,); ,,); ,,); ,,); ,,); ,,); 2.详解rank(),dense_ ...

  10. sql server 循环

    declare @i int declare @a int declare @b int set @i=0 while(@i<=20) begin set @a=@i*1000+1; set @ ...