• Spring4 MVC+Hibernate4+MySQL+Maven使用注解集成实例


    在本教程中,我们将使用基于注解的配置集成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.yiibai.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.connector.version>5.1.31</mysql.connector.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.connector.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-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

    package com.yiibai.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.yiibai.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.yiibai.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生产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

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

    com.yiibai.springmvc.configuration.AppConfig

    package com.yiibai.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.yiibai.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类。
    @EnableWebMvc相当于mvc:annotation-driven 在XML文件中。
    ViewResolver方法配置一个ViewResolver来找出真正的视图。

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

    /src/main/resources/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:配置初始化器类

    com.yiibai.springmvc.configuration.AppInitializer

    package com.yiibai.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,因为我们使用的是前端控制器 DispatcherServlet 的内容,分配映射(URL模式的XML),而不是提供给Spring配置文件(spring-servlet.xml)的路径,在这里我们正在注册的配置类。

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

    package com.yiibai.springmvc.configuration;
    
    import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
    
    public class AppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    
    	@Override
    	protected Class<?>[] getRootConfigClasses() {
    		return new Class[] { AppConfig.class };
    	}
     
    	@Override
    	protected Class<?>[] getServletConfigClasses() {
    		return null;
    	}
     
    	@Override
    	protected String[] getServletMappings() {
    		return new String[] { "/" };
    	}
    
    }
    
    第6步:添加控制器来处理请求
    添加控制器这将有助于处理 GET和POST请求。

    com.yiibai.springmvc.controller.AppController

    package com.yiibai.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.yiibai.springmvc.model.Employee;
    import com.yiibai.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";
    	}
    
    } 

    这是一个非常直接的基于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

    package com.yiibai.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,在这里将自动装配。

    com.yiibai.springmvc.dao.EmployeeDao

    package com.yiibai.springmvc.dao;
    
    import java.util.List;
    
    import com.yiibai.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);
    
    }
    

    com.yiibai.springmvc.dao.EmployeeDaoImpl

    package com.yiibai.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.yiibai.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步:添加服务层

    com.yiibai.springmvc.service.EmployeeService

    package com.yiibai.springmvc.service;
    
    import java.util.List;
    
    import com.yiibai.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);
    	
    }
    

    com.yiibai.springmvc.service.EmployeeServiceImpl

    package com.yiibai.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.yiibai.springmvc.dao.EmployeeDao;
    import com.yiibai.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 它开始在每个方法启动一个事务,并提交其上的每个方法退出(或回滚,如果方法失败,会发生是一个错误)。 注意,因为该事务是在方法范围,和内部的方法,我们将使用DAO,DAO方法将在同一事务内执行。

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

    com.yiibai.springmvc.model.Employee

    package com.yiibai.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 + "]";
    	}
    	
    }
    
    这是注明使用JPA注解@Entity,@Table,@Column 使用 hibernate的具体注释@Type,我们正在使用提供数据库中的数据类型和LocalDate之间的映射标准的实体类。
    @DateTimeFormat是一个 Spring 的具体注解声明,字段应该使用一个给定格式格式化日期时间。
    第10步:添加视图/JSP

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

    <%@ page language="java" contentType="text/html; charset=utf-8"
        pageEncoding="uft-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <html>
    <head>
    	<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    	<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>
    

    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>
    

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

    <%@ page language="java" contentType="text/html; charset=utf-8"
        pageEncoding="utf-8"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    
    <html>
    <head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <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步:构建,部署和运行应用程序

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

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

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

    现在填写详细信息

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

    点击列表,进入列表:

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

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

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

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

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

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

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

  • 相关阅读:
    快来使用Portainer让测试环境搭建飞起来吧
    ReviewBoard安装记录(CentOS5)
    awk中的NR,FNR ,NF,$NF,RS,ORS,FS,OFS
    Argument list too long解决办法
    Jenkins插件开发(6.3)—— 追踪jenkinscli.jar
    AWK中如何按列求和
    JIRA中显示中文显示为乱码“口口口”的解决方式(CentOS)
    Jenkins常用插件记录
    Jenkins插件开发(6.4)—— 分析CLI源码
    Jenkins插件开发(6.2)—— 如何自定义CLI命令
  • 原文地址:https://www.cnblogs.com/borter/p/9519808.html
Copyright © 2020-2023  润新知