Spring 4 MVC+Hibernate 4+MySQL+Maven使用注解集成實例
轉自:通過注解的方式集成Spring 4 MVC+Hibernate 4+MySQL+Maven,開發項目樣例
2017-01-23
第1步:創建目錄結構
第2步:更新 pom.xml
第3步:配置hibernate
3.1 com.websystique.springmvc.configuration.HibernateConfiguration
3.2 /src/main/resources/application.properties
第4步:配置Spring MVC
4.1 com.websystique.springmvc.configuration.AppConfig
4.2 /src/main/resources/messages.properties
第5步:配置初始化類
5.1 com.websystique.springmvc.configuration.AppInitializer
第6步:添加控制器以處理請求
6.1 com.websystique.springmvc.controller.AppController
第7步:添加DAO層
7.1 com.websystique.springmvc.dao.AbstractDao
7.2 com.websystique.springmvc.dao.EmployeeDao
7.3 com.websystique.springmvc.dao.EmployeeDaoImpl
第8步:添加服務層
8.1 com.websystique.springmvc.service.EmployeeService
8.2 com.websystique.springmvc.service.EmployeeServiceImpl
第9步:創建領域對象(普通的java bean對象)
9.1 com.websystique.springmvc.model.Employee
第10步:添加JSP視圖 WEB-INF/views/allemployees.jsp
10.1 WEB-INF/views/allemployees.jsp [ 主頁包含所有已經存在的員工]
10.2 WEB-INF/views/registration.jsp [注冊頁面用來創建和保存員工信息到數據庫]
10.3 WEB-INF/views/success.jsp [成功頁面包含新員工創建成功的確認信息並重定向到員工列表頁面]
第11步:創建數據表
第12步:創建,部署和運行程序
源代碼 : SpringHibernateExample.zip
注意:若沒有springmvc基礎,在看此篇前可看下這篇文章Spring4 MVC HelloWord實例 ,這篇文章是主要講述MVC中的control層如何操作model和返回view,且以xml文件進行bean注入。
使用基於注解的配置集成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

<?xml version="1.0"?> <project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <modelVersion>4.0.0</modelVersion> <groupId>com.websystique.springmvc</groupId> <artifactId>SpringHibernateExample</artifactId> <packaging>war</packaging> <version>1.0.0</version> <name>SpringHibernateExample</name> <properties> <springframework.version>4.0.6.RELEASE</springframework.version> <hibernate.version>4.3.6.Final</hibernate.version> <mysql.version>5.1.31</mysql.version> <joda-time.version>2.3</joda-time.version> <testng.version>6.9.4</testng.version> <mockito.version>1.10.19</mockito.version> <h2.version>1.4.187</h2.version> <dbunit.version>2.2</dbunit.version> </properties> <dependencies> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${springframework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${springframework.version}</version> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <!-- jsr303 validation --> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>1.1.0.Final</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.1.3.Final</version> </dependency> <!-- MySQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>${mysql.version}</version> </dependency> <!-- Joda-Time --> <dependency> <groupId>joda-time</groupId> <artifactId>joda-time</artifactId> <version>${joda-time.version}</version> </dependency> <!-- To map JodaTime with database type --> <dependency> <groupId>org.jadira.usertype</groupId> <artifactId>usertype.core</artifactId> <version>3.0.0.CR1</version> </dependency> <!-- Servlet+JSP+JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>2.3.1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Testing dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${springframework.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.testng</groupId> <artifactId>testng</artifactId> <version>${testng.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>${mockito.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>${h2.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>dbunit</groupId> <artifactId>dbunit</artifactId> <version>${dbunit.version}</version> <scope>test</scope> </dependency> </dependencies> <build> <pluginManagement> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-war-plugin</artifactId> <version>2.4</version> <configuration> <warSourceDirectory>src/main/webapp</warSourceDirectory> <warName>SpringHibernateExample</warName> <failOnMissingWebXml>false</failOnMissingWebXml> </configuration> </plugin> </plugins> </pluginManagement> <finalName>SpringHibernateExample</finalName> </build> </project>
注意:
- maven的war包插件(maven-war-plugin)的聲明:由於我們使用全注解方式進行配置。甚至在我們的工程當中沒有包含web.xml文件。所以我們要配置這個插件,以避免maven在構建war包的時候失敗。
- 驗證用戶的輸入:在這個樣例工程中,由於使用表單接受用戶的輸入。所以需要驗證用戶的輸入。這里將選擇JSR303 進行驗證。所以我們要引入驗證接口(validation-api)來說明這種規范。hibernate驗證(hibernate-validator)正好是這種規范的一種實現。hibernate驗證(hibernate-validator)同時也通過了他特有的注解校驗(@Email, @NotEmpty等),這些並不是規范所囊括的。
- 其他依賴:我們也包含了(JSP/Servlet/Jstl)依賴。在我們代碼中使用servelet api和jstl視圖的時候需要。總而驗證,容器需要包含這些jar包。所以我們在pom.xml文件當中去設置,這樣maven才能下載他們。我們同時也需要測試依賴。測試部分將在下面的章節中討論。剩下的部分是Spring,hibernate和Joda-Time等的依賴了。
第3步:配置hibernate
3.1 com.websystique.springmvc.configuration.HibernateConfiguration

package com.websystique.springmvc.configuration; import java.util.Properties; import javax.sql.DataSource; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; import org.springframework.core.env.Environment; import org.springframework.jdbc.datasource.DriverManagerDataSource; import org.springframework.orm.hibernate4.HibernateTransactionManager; import org.springframework.orm.hibernate4.LocalSessionFactoryBean; import org.springframework.transaction.annotation.EnableTransactionManagement; @Configuration @EnableTransactionManagement @ComponentScan({ "com.websystique.springmvc.configuration" }) @PropertySource(value = { "classpath:application.properties" }) public class HibernateConfiguration { @Autowired private Environment environment; @Bean public LocalSessionFactoryBean sessionFactory() { LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean(); sessionFactory.setDataSource(dataSource()); sessionFactory.setPackagesToScan(new String[] { "com.websystique.springmvc.model" }); sessionFactory.setHibernateProperties(hibernateProperties()); return sessionFactory; } @Bean public DataSource dataSource() { DriverManagerDataSource dataSource = new DriverManagerDataSource(); dataSource.setDriverClassName(environment.getRequiredProperty("jdbc.driverClassName")); dataSource.setUrl(environment.getRequiredProperty("jdbc.url")); dataSource.setUsername(environment.getRequiredProperty("jdbc.username")); dataSource.setPassword(environment.getRequiredProperty("jdbc.password")); return dataSource; } private Properties hibernateProperties() { Properties properties = new Properties(); properties.put("hibernate.dialect", environment.getRequiredProperty("hibernate.dialect")); properties.put("hibernate.show_sql", environment.getRequiredProperty("hibernate.show_sql")); properties.put("hibernate.format_sql", environment.getRequiredProperty("hibernate.format_sql")); return properties; } @Bean @Autowired public HibernateTransactionManager transactionManager(SessionFactory s) { HibernateTransactionManager txManager = new HibernateTransactionManager(); txManager.setSessionFactory(s); return txManager; } }
注意:
- @Configuration 注解表示這個類包含一個或多個使用了 @Bean 注解了的方法。將被spring容器所管理以產生beans。在這里。這個類代表hibernate配置。
- @ComponentScan 注解等同於XML配置文件中的context:component-scan base-package="..." 聲明。用它來表示去哪里查找spring管理的beans/classes
- @EnableTransactionManagement 注解等同於SpringXMl中的tx:*命名空間聲明。它將啟用Spring注解驅動的事務管理功能。
- @PropertySource注解用於聲明一組屬性(在程序的classpath路徑下的properties文件中定義),在spring運行環境下。通過他可以在不同運行環境下進行變更以提供不同的值。
- 由於@PropertySource注解提供的便利,我們可以在properties文件中提供具體的值,通過Spring’s Environment來提取這些值。
方法sessionFactory() 將創建LocalSessionFactoryBean,它映射配置:dataSource和hibernate屬性文件配置(就像hibernate.properties文件)。
一旦SessionFactory創建,它將被注入bean方法transactionManager 中,最終可能對sessionFactory所創建的sesstions提供事務支持。
3.2 /src/main/resources/application.properties
jdbc.driverClassName = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localhost:3306/websystique jdbc.username = myuser jdbc.password = mypassword hibernate.dialect = org.hibernate.dialect.MySQLDialect hibernate.show_sql = true hibernate.format_sql = true
第4步:配置Spring MVC
4.1 com.websystique.springmvc.configuration.AppConfig

package com.websystique.springmvc.configuration; 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.web.servlet.ViewResolver; import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.view.InternalResourceViewResolver; import org.springframework.web.servlet.view.JstlView; @Configuration @EnableWebMvc @ComponentScan(basePackages = "com.websystique.springmvc") public class AppConfig { @Bean public ViewResolver viewResolver() { InternalResourceViewResolver viewResolver = new InternalResourceViewResolver(); viewResolver.setViewClass(JstlView.class); viewResolver.setPrefix("/WEB-INF/views/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Bean public MessageSource messageSource() { ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource(); messageSource.setBasename("messages"); return messageSource; } }
注意:
- @Configuration注解標示着這個類被配置后的作用,就像上面提到的那樣(表示這個類包含一個或多個使用了 @Bean 注解了的方法。將被spring容器所管理以產生beans。),
- @ComponentScan注解指出了可以在這些包路徑下找到相關聯的beans類。
- @EnableWebMvc注解相當於XML文件中的mvc:annotation-driven(啟用web的MVC控制)。方法viewResolver配置了一個視圖解析器。以定位到具體的視圖頁面。
4.2 /src/main/resources/messages.properties
在這篇文章中,我們使用表單進行提交,通過JSR303規范驗證用戶的輸入。在驗證失敗的情況下,默認的錯誤信息將顯示。你可以通過國際化的方式在其他消息綁定文件(以.properties結尾的文件)中定義適用於你語言環境的消息。在basename方法中。spring會程序運行的class路徑中檢索一個叫messages.properties的文件。讓我們添加這個文件吧:
Size.employee.name=Name must be between {2} and {1} characters long NotNull.employee.joiningDate=Joining Date can not be blank NotNull.employee.salary=Salary can not be blank Digits.employee.salary=Only numeric data with max 8 digits and with max 2 precision is allowed NotEmpty.employee.ssn=SSN can not be blank typeMismatch=Invalid format non.unique.ssn=SSN {0} already exist. Please fill in different value.
注意:上面的消息采用了下面的規范格式
{ValidationAnnotationClass}.{modelObject}.{fieldName}
{驗證注解類名}.{模塊對象名}.{字段名}
此外,基於特定的注解(例如@Size)你甚至可以通過使用{0},{1},..{i}占位索引的方式來傳遞參數。
第5步:配置初始化類
5.1 com.websystique.springmvc.configuration.AppInitializer

package com.websystique.springmvc.configuration; import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import org.springframework.web.WebApplicationInitializer; import org.springframework.web.context.support.AnnotationConfigWebApplicationContext; import org.springframework.web.servlet.DispatcherServlet; public class AppInitializer implements WebApplicationInitializer { public void onStartup(ServletContext container) throws ServletException { AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext(); ctx.register(AppConfig.class); ctx.setServletContext(container); ServletRegistration.Dynamic servlet = container.addServlet( "dispatcher", new DispatcherServlet(ctx)); servlet.setLoadOnStartup(1); servlet.addMapping("/"); } }
注意:
上面的代碼類似於web.xml文件的內容。由於我們使用了前端控制器(DispatherServler),分配這些映射(就像xml文件中的url-pattern那樣)。通過上面的方法,我們就不用在spring-servlet.xml文件中去配置路徑了。這里我們注冊了這個配置類。
第6步:添加控制器以處理請求
添加這個控制器,可以對get和post請求提供服務。
6.1 com.websystique.springmvc.controller.AppController

package com.websystique.springmvc.controller; import java.util.List; import java.util.Locale; import javax.validation.Valid; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.MessageSource; import org.springframework.stereotype.Controller; import org.springframework.ui.ModelMap; import org.springframework.validation.BindingResult; import org.springframework.validation.FieldError; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import com.websystique.springmvc.model.Employee; import com.websystique.springmvc.service.EmployeeService; @Controller @RequestMapping("/") public class AppController { @Autowired EmployeeService service; @Autowired MessageSource messageSource; /* * This method will list all existing employees. */ @RequestMapping(value = { "/", "/list" }, method = RequestMethod.GET) public String listEmployees(ModelMap model) { List<Employee> employees = service.findAllEmployees(); model.addAttribute("employees", employees); return "allemployees"; } /* * This method will provide the medium to add a new employee. */ @RequestMapping(value = { "/new" }, method = RequestMethod.GET) public String newEmployee(ModelMap model) { Employee employee = new Employee(); model.addAttribute("employee", employee); model.addAttribute("edit", false); return "registration"; } /* * This method will be called on form submission, handling POST request for * saving employee in database. It also validates the user input */ @RequestMapping(value = { "/new" }, method = RequestMethod.POST) public String saveEmployee(@Valid Employee employee, BindingResult result, ModelMap model) { if (result.hasErrors()) { return "registration"; } /* * Preferred way to achieve uniqueness of field [ssn] should be implementing custom @Unique annotation * and applying it on field [ssn] of Model class [Employee]. * * Below mentioned peace of code [if block] is to demonstrate that you can fill custom errors outside the validation * framework as well while still using internationalized messages. * */ if(!service.isEmployeeSsnUnique(employee.getId(), employee.getSsn())){ FieldError ssnError =new FieldError("employee","ssn",messageSource.getMessage("non.unique.ssn", new String[]{employee.getSsn()}, Locale.getDefault())); result.addError(ssnError); return "registration"; } service.saveEmployee(employee); model.addAttribute("success", "Employee " + employee.getName() + " registered successfully"); return "success"; } /* * This method will provide the medium to update an existing employee. */ @RequestMapping(value = { "/edit-{ssn}-employee" }, method = RequestMethod.GET) public String editEmployee(@PathVariable String ssn, ModelMap model) { Employee employee = service.findEmployeeBySsn(ssn); model.addAttribute("employee", employee); model.addAttribute("edit", true); return "registration"; } /* * This method will be called on form submission, handling POST request for * updating employee in database. It also validates the user input */ @RequestMapping(value = { "/edit-{ssn}-employee" }, method = RequestMethod.POST) public String updateEmployee(@Valid Employee employee, BindingResult result, ModelMap model, @PathVariable String ssn) { if (result.hasErrors()) { return "registration"; } if(!service.isEmployeeSsnUnique(employee.getId(), employee.getSsn())){ FieldError ssnError =new FieldError("employee","ssn",messageSource.getMessage("non.unique.ssn", new String[]{employee.getSsn()}, Locale.getDefault())); result.addError(ssnError); return "registration"; } service.updateEmployee(employee); model.addAttribute("success", "Employee " + employee.getName() + " updated successfully"); return "success"; } /* * This method will delete an employee by it's SSN value. */ @RequestMapping(value = { "/delete-{ssn}-employee" }, method = RequestMethod.GET) public String deleteEmployee(@PathVariable String ssn) { service.deleteEmployeeBySsn(ssn); return "redirect:/list"; } }
注意:
- @Controller。這個注解表明這個類是用來處理請求的控制類。通過注解@RequestMapping提供將要處理的請求URL路徑。這里我們配置的是根目錄'/'。它將作為默認的控制器。
- 方法listEmployees,被@RequestMethod.GET所注解。將處理來自'/'和'/list'的請求。它接管了程序初始化頁面的處理,並響應所有存在的員工列表。
- 方法newEmployee 處理來着新員工注冊頁面的請求。顯示頁面由一個Employee對象模型。
- 方法saveEmployee 被@RequestMethod.POST所注解。它將處理表單提交的post請求(在進行新員工注冊的時候,提交請求道url路徑:/new)。注意這個方法的參數和這些參數在方法中的順序。@Valid 注解將要求spring去驗證這些關聯的對象(Employee)。參數 BindingResult包含了這個驗證的結果和任何在驗證過程中報出的錯誤信息。請注意這個參數 BindingResult 必須緊跟在被驗證的對象之后。否則spring無法進行驗證並且有異常被拋出。在驗證出錯的情況下。響應的錯誤消息將會顯示(我們在第4步配置的那些消息)。我們同時也包含了對SSN唯一性進行核對的校驗。因為他在數據庫中被聲明為唯一的。在保存和更新一個員工之前。我們要核對這個SSN是否是唯一的。如果不是。我們將生成校驗錯誤的信息並且重定向到注冊頁面。這段代碼演示了在校驗框架之外填寫客戶錯誤信息的情況,不過還是用message.properties文件中配置的信息(你可以通過國際化的方式進行定制)。
- 方法editEmployee 將定位到注冊頁面,並把員工的詳細信息填充 到頁面的控件當中。在你點擊頁面的更新按鈕進行更新而出發的更新員工資料請求的時候。
- 方法deleteEmployee 處理根據員工SSN值刪除員工數據的請求。注意@PathVariable注解,他表示這個參數將被在uri模板中綁定(我們這里就是SSN的值)
第7步:添加DAO層
隨着基於注釋的配置,這是我們需要做的。為了進一步完善程序。我們添加服務層,dao層。視圖層。領域對象層和一個簡單的數據庫模式。最后運行這個程序吧。
7.1 com.websystique.springmvc.dao.AbstractDao

package com.websystique.springmvc.dao; import java.io.Serializable; import java.lang.reflect.ParameterizedType; import org.hibernate.Criteria; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.springframework.beans.factory.annotation.Autowired; public abstract class AbstractDao<PK extends Serializable, T> { private final Class<T> persistentClass; @SuppressWarnings("unchecked") public AbstractDao(){ this.persistentClass =(Class<T>) ((ParameterizedType) this.getClass().getGenericSuperclass()).getActualTypeArguments()[1]; } @Autowired private SessionFactory sessionFactory; protected Session getSession(){ return sessionFactory.getCurrentSession(); } @SuppressWarnings("unchecked") public T getByKey(PK key) { return (T) getSession().get(persistentClass, key); } public void persist(T entity) { getSession().persist(entity); } public void delete(T entity) { getSession().delete(entity); } protected Criteria createEntityCriteria(){ return getSession().createCriteria(persistentClass); } }
這個泛型抽象類是所有DAO實現類的父類。它提供了所有hibernate操作的通用方法。請注意上面。我們在第3步創建的SessionFactory對象將會被Spring容器自動裝載。
7.2 com.websystique.springmvc.dao.EmployeeDao

package com.websystique.springmvc.dao; import java.util.List; import com.websystique.springmvc.model.Employee; public interface EmployeeDao { Employee findById(int id); void saveEmployee(Employee employee); void deleteEmployeeBySsn(String ssn); List<Employee> findAllEmployees(); Employee findEmployeeBySsn(String ssn); }
7.3 com.websystique.springmvc.dao.EmployeeDaoImpl

package com.websystique.springmvc.dao; import java.util.List; import org.hibernate.Criteria; import org.hibernate.Query; import org.hibernate.criterion.Restrictions; import org.springframework.stereotype.Repository; import com.websystique.springmvc.model.Employee; @Repository("employeeDao") public class EmployeeDaoImpl extends AbstractDao<Integer, Employee> implements EmployeeDao { public Employee findById(int id) { return getByKey(id); } public void saveEmployee(Employee employee) { persist(employee); } public void deleteEmployeeBySsn(String ssn) { Query query = getSession().createSQLQuery("delete from Employee where ssn = :ssn"); query.setString("ssn", ssn); query.executeUpdate(); } @SuppressWarnings("unchecked") public List<Employee> findAllEmployees() { Criteria criteria = createEntityCriteria(); return (List<Employee>) criteria.list(); } public Employee findEmployeeBySsn(String ssn) { Criteria criteria = createEntityCriteria(); criteria.add(Restrictions.eq("ssn", ssn)); return (Employee) criteria.uniqueResult(); } }
第8步:添加服務層
8.1 com.websystique.springmvc.service.EmployeeService

package com.websystique.springmvc.service; import java.util.List; import com.websystique.springmvc.model.Employee; public interface EmployeeService { Employee findById(int id); void saveEmployee(Employee employee); void updateEmployee(Employee employee); void deleteEmployeeBySsn(String ssn); List<Employee> findAllEmployees(); Employee findEmployeeBySsn(String ssn); boolean isEmployeeSsnUnique(Integer id, String ssn); }
8.2 com.websystique.springmvc.service.EmployeeServiceImpl

package com.websystique.springmvc.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.websystique.springmvc.dao.EmployeeDao; import com.websystique.springmvc.model.Employee; @Service("employeeService") @Transactional public class EmployeeServiceImpl implements EmployeeService { @Autowired private EmployeeDao dao; public Employee findById(int id) { return dao.findById(id); } public void saveEmployee(Employee employee) { dao.saveEmployee(employee); } /* * Since the method is running with Transaction, No need to call hibernate update explicitly. * Just fetch the entity from db and update it with proper values within transaction. * It will be updated in db once transaction ends. */ public void updateEmployee(Employee employee) { Employee entity = dao.findById(employee.getId()); if(entity!=null){ entity.setName(employee.getName()); entity.setJoiningDate(employee.getJoiningDate()); entity.setSalary(employee.getSalary()); entity.setSsn(employee.getSsn()); } } public void deleteEmployeeBySsn(String ssn) { dao.deleteEmployeeBySsn(ssn); } public List<Employee> findAllEmployees() { return dao.findAllEmployees(); } public Employee findEmployeeBySsn(String ssn) { return dao.findEmployeeBySsn(ssn); } public boolean isEmployeeSsnUnique(Integer id, String ssn) { Employee employee = findEmployeeBySsn(ssn); return ( employee == null || ((id != null) && (employee.getId() == id))); } }
注意:
- @Transactional注解了。它將在每個方法調用的時候開啟事務。在每個方法結束的時候提交事務(或者在方法執行失敗並產生錯誤的時候回滾他)。請注意,由於transaction注解是基於方法領域的。在方法里面我們使用DAO對象。dao方法將在同一個事務當中執行。
第9步:創建領域對象(普通的java bean對象)
讓我們創建這個實際的雇員實體對象。在數據里面有一張與之對應的。這個對象用於實例化這些數據。
9.1com.websystique.springmvc.model.Employee

package com.websystique.springmvc.model; import java.math.BigDecimal; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Table; import javax.validation.constraints.Digits; import javax.validation.constraints.NotNull; import javax.validation.constraints.Size; import org.hibernate.annotations.Type; import org.hibernate.validator.constraints.NotEmpty; import org.joda.time.LocalDate; import org.springframework.format.annotation.DateTimeFormat; @Entity @Table(name="EMPLOYEE") public class Employee { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private int id; @Size(min=3, max=50) @Column(name = "NAME", nullable = false) private String name; @NotNull @DateTimeFormat(pattern="dd/MM/yyyy") @Column(name = "JOINING_DATE", nullable = false) @Type(type="org.jadira.usertype.dateandtime.joda.PersistentLocalDate") private LocalDate joiningDate; @NotNull @Digits(integer=8, fraction=2) @Column(name = "SALARY", nullable = false) private BigDecimal salary; @NotEmpty @Column(name = "SSN", unique=true, nullable = false) private String ssn; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public LocalDate getJoiningDate() { return joiningDate; } public void setJoiningDate(LocalDate joiningDate) { this.joiningDate = joiningDate; } public BigDecimal getSalary() { return salary; } public void setSalary(BigDecimal salary) { this.salary = salary; } public String getSsn() { return ssn; } public void setSsn(String ssn) { this.ssn = ssn; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; result = prime * result + ((ssn == null) ? 0 : ssn.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (!(obj instanceof Employee)) return false; Employee other = (Employee) obj; if (id != other.id) return false; if (ssn == null) { if (other.ssn != null) return false; } else if (!ssn.equals(other.ssn)) return false; return true; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", joiningDate=" + joiningDate + ", salary=" + salary + ", ssn=" + ssn + "]"; } }
注意:
- @Entity, @Table, @Column 和hibernate 特有的注解
- @Type 所標注(我們將是通過他來映射Joda-Time的LocalDate對象和數據庫的date type)。
- @DateTimeFormat是spring所特有的注解,用於聲明一個字段應該被給定的時間格式來格式化。
- 余下的注解是JSR303相關的驗證。回調第四步我們已經配置好的屬性文件(messages.properties)。在驗證失敗的情況下提供相應的消息。
第10步:添加JSP視圖 WEB-INF/views/allemployees.jsp
10.1 WEB-INF/views/allemployees.jsp [ 主頁包含所有已經存在的員工]

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>University Enrollments</title> <style> tr:first-child{ font-weight: bold; background-color: #C6C9C4; } </style> </head> <body> <h2>List of Employees</h2> <table> <tr> <td>NAME</td><td>Joining Date</td><td>Salary</td><td>SSN</td><td></td> </tr> <c:forEach items="${employees}" var="employee"> <tr> <td>${employee.name}</td> <td>${employee.joiningDate}</td> <td>${employee.salary}</td> <td><a href="<c:url value='/edit-${employee.ssn}-employee' />">${employee.ssn}</a></td> <td><a href="<c:url value='/delete-${employee.ssn}-employee' />">delete</a></td> </tr> </c:forEach> </table> <br/> <a href="<c:url value='/new' />">Add New Employee</a> </body> </html>
10.2 WEB-INF/views/registration.jsp [注冊頁面用來創建和保存員工信息到數據庫]

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Employee Registration Form</title> <style> .error { color: #ff0000; } </style> </head> <body> <h2>Registration Form</h2> <form:form method="POST" modelAttribute="employee"> <form:input type="hidden" path="id" id="id"/> <table> <tr> <td><label for="name">Name: </label> </td> <td><form:input path="name" id="name"/></td> <td><form:errors path="name" cssClass="error"/></td> </tr> <tr> <td><label for="joiningDate">Joining Date: </label> </td> <td><form:input path="joiningDate" id="joiningDate"/></td> <td><form:errors path="joiningDate" cssClass="error"/></td> </tr> <tr> <td><label for="salary">Salary: </label> </td> <td><form:input path="salary" id="salary"/></td> <td><form:errors path="salary" cssClass="error"/></td> </tr> <tr> <td><label for="ssn">SSN: </label> </td> <td><form:input path="ssn" id="ssn"/></td> <td><form:errors path="ssn" cssClass="error"/></td> </tr> <tr> <td colspan="3"> <c:choose> <c:when test="${edit}"> <input type="submit" value="Update"/> </c:when> <c:otherwise> <input type="submit" value="Register"/> </c:otherwise> </c:choose> </td> </tr> </table> </form:form> <br/> <br/> Go back to <a href="<c:url value='/list' />">List of All Employees</a> </body> </html>
10.3 WEB-INF/views/success.jsp [成功頁面包含新員工創建成功的確認信息並重定向到員工列表頁面]

<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Registration Confirmation Page</title> </head> <body> message : ${success} <br/> <br/> Go back to <a href="<c:url value='/list' />">List of All Employees</a> </body> </html>
第11步:創建數據表
CREATE TABLE EMPLOYEE( id INT NOT NULL auto_increment, name VARCHAR(50) NOT NULL, joining_date DATE NOT NULL, salary DOUBLE NOT NULL, ssn VARCHAR(30) NOT NULL UNIQUE, PRIMARY KEY (id) );
第12步:創建,部署和運行程序
現在開始打war包(既可以通過eclipse) 或者通過maven命令行(mvn clean install).將war包部署到servlet3.0容器當中。由於這里我使用的是tomcat容器。我就直接將war包放在tomcat的webapps文件夾下。並點擊start.bat腳本啟動tomcat(在tomcat的bin目錄下面)。 打開瀏覽器輸入網址:http://localhost:8080/SpringHibernateExample/