在开始之前,我们需要更新我们的Maven依赖项,因为我们现在将使用Hibernate和Spring。 将以下依赖项添加到pom.xml中 :
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-entitymanager</artifactId>
<version>3.6.8.Final</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<!-- spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
如果您是Maven的新手,您可能现在想知道-您怎么知道这些? 我在哪里可以买到? 好吧,只需转到http://mvnrepository.com/并输入您要搜索的啤酒。 您将获得有关Maven依赖项的完整代码。 如果您曾经尝试在不使用Maven的情况下自己组装Spring或Hibernate应用程序,那么您可能知道它是多么痛苦。 使用Maven,事情变得简单得多。
还要注意,我们包括了对MySQL连接器的依赖。 如果您决定使用其他数据库,请不要忘记更改它。
使用Hibernate,我们有2种选择如何将POJO变成实体。 我们要么使用XML并创建映射文件 ,要么将一些元信息放入我们的代码(java批注)中。 有些人对此感到恐惧,并认为这是与框架的结合。 的确,您在类路径中将需要javax.persistence批注,但我们不会实现接口或扩展框架类。 我们将只在代码中添加一些元信息,而POJO仍然只是带有一些额外信息的POJO。
现在,我们将POJO转换为实体。 我们将需要进行以下更改:
- 为Hibernate添加默认的无参数构造函数
- 为字段创建获取器和设置器
- 添加equals和hashCode方法。
- 添加持久性注释。 请注意,我们还使用@Table批注来区分Java和SQL命名约定。
- 添加ID字段。 这些将是我们关系数据库中的主键。
这是很多样板代码,因此让您的IDE帮您。 大多数现代IDE都会为您生成构造函数,getter,setter,equals和hashCode。
package org.timesheet.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = 'employee')
public class Employee {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
private String department;
public Employee() {
}
public Employee(String name, String department) {
this.name = name;
this.department = department;
}
public String getName() {
return name;
}
public String getDepartment() {
return department;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setDepartment(String department) {
this.department = department;
}
@Override
public String toString() {
return 'Employee [id=' + id + ', name=' + name + ', department='
+ department + ']';
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((department == null) ? 0 : department.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.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 (department == null) {
if (other.department != null) {
return false;
}
} else if (!department.equals(other.department)) {
return false;
}
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
}
package org.timesheet.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = 'manager')
public class Manager {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
private String name;
public Manager() {
}
public Manager(String name) {
this.name = name;
}
public String getName() {
return name;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Manager)) {
return false;
}
Manager other = (Manager) obj;
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
if (name == null) {
if (other.name != null) {
return false;
}
} else if (!name.equals(other.name)) {
return false;
}
return true;
}
@Override
public String toString() {
return 'Manager [id=' + id + ', name=' + name + ']';
}
}
package org.timesheet.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name='timesheet')
public class Timesheet {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = 'employee_id')
private Employee who;
@OneToOne
@JoinColumn(name = 'task_id')
private Task task;
private Integer hours;
public Timesheet() {
}
public Timesheet(Employee who, Task task, Integer hours) {
this.who = who;
this.task = task;
this.hours = hours;
}
public Employee getWho() {
return who;
}
public Task getTask() {
return task;
}
public Integer getHours() {
return hours;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public void setWho(Employee who) {
this.who = who;
}
public void setTask(Task task) {
this.task = task;
}
public void setHours(Integer hours) {
this.hours = hours;
}
/**
* Manager can alter hours before closing task
* @param hours New amount of hours
*/
public void alterHours(Integer hours) {
this.hours = hours;
}
@Override
public String toString() {
return 'Timesheet [id=' + id + ', who=' + who + ', task=' + task
+ ', hours=' + hours + ']';
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((hours == null) ? 0 : hours.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((task == null) ? 0 : task.hashCode());
result = prime * result + ((who == null) ? 0 : who.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Timesheet)) {
return false;
}
Timesheet other = (Timesheet) obj;
if (hours == null) {
if (other.hours != null) {
return false;
}
} else if (!hours.equals(other.hours)) {
return false;
}
if (id == null) {
if (other.id != null) {
return false;
}
} else if (!id.equals(other.id)) {
return false;
}
if (task == null) {
if (other.task != null) {
return false;
}
} else if (!task.equals(other.task)) {
return false;
}
if (who == null) {
if (other.who != null) {
return false;
}
} else if (!who.equals(other.who)) {
return false;
}
return true;
}
}
最后,这是我们需要同时使用@ManyToMany映射的Task实体。 这是因为一名雇员可以从事多个任务,而一项任务可以分配多个雇员。 我们使用@JoinTable和@JoinColumn批注定义了m:n的外观。
package org.timesheet.domain;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@Entity
@Table(name = 'task')
public class Task {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = 'task_employee',
joinColumns = {@JoinColumn(name = 'task_id')},
inverseJoinColumns = {@JoinColumn(name = 'employee_id')}
)
private List<Employee> assignedEmployees = new ArrayList<Employee>();
@OneToOne
@JoinColumn(name = 'manager_id')
private Manager manager;
private String description;
boolean completed;
public Task() {
}
public Task(String description, Manager manager, Employee... employees) {
this.description = description;
this.manager = manager;
assignedEmployees.addAll(Arrays.asList(employees));
completed = false;
}
public Manager getManager() {
return manager;
}
public List<Employee> getAssignedEmployees() {
return assignedEmployees;
}
public void addEmployee(Employee e) {
assignedEmployees.add(e);
}
public void removeEmployee(Employee e) {
assignedEmployees.remove(e);
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public boolean isCompleted() {
return completed;
}
public void setCompleted(boolean completed) {
this.completed = completed;
}
public void setAssignedEmployees(List<Employee> assignedEmployees) {
this.assignedEmployees = assignedEmployees;
}
public void setManager(Manager manager) {
this.manager = manager;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Task task = (Task) o;
if (completed != task.completed) {
return false;
}
if (description != null ? !description.equals(task.description) : task.description != null) {
return false;
}
if (id != null ? !id.equals(task.id) : task.id != null) {
return false;
}
if (manager != null ? !manager.equals(task.manager) : task.manager != null) {
return false;
}
return true;
}
@Override
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (manager != null ? manager.hashCode() : 0);
result = 31 * result + (description != null ? description.hashCode() : 0);
result = 31 * result + (completed ? 1 : 0);
return result;
}
@Override
public String toString() {
return 'Task{' +
'id=' + id +
', assignedEmployees=' + assignedEmployees +
', manager=' + manager +
', description='' + description + '\'' +
', completed=' + completed +
'}';
}
}
因此,我们实际上并没有做任何特别的建模。 如果您喜欢一些UML,请看下图,关系与以前相同。
好的,我们有实体,现在让我们创建数据库。 选择一些数据库管理工具(即使是普通终端也可以)并创建时间表数据库(默认情况下,mysql将在Mac OS X上安装到/ usr / local / mysql / bin / mysql):
$ mysql -u root
mysql > create database timesheet;
如果您可能在不了解之前就已经配置过Hibernate,那么在处理SessionFactory时就需要很多文件和样板代码。 使用Spring,这些事情要简单得多。
现在,我们将创建我们的第一个Spring Bean配置文件 -该文件在其中注册Spring容器的bean。 如果我不得不向根本不了解Spring的人解释这个文件是什么,那是Spring容器可以找到对象的神奇包。
现代IDE将帮助您正确使用所有XML名称空间,例如,您可以从STS向导中查看图片。 NetBeans具有类似的功能,IntelliJ可以动态解析名称空间。
命名配置文件persistence-beans.xml,然后将其放在src / main / resources文件夹下。
因此,设置Hibernate,事务,批注配置等就像在XML文件中创建几个bean一样简单。 另外,我们可以将Java Config用于Spring,但是XML config仍然使用更多,因此我们将坚持使用这些配置。 我不想阻止您使用Java Config! XML config 现在更受欢迎,但是我不能保证在接下来的几年中。
我已经评论了每个bean,以确保您在继续之前了解我们在这里所做的事情。 如果要直观地了解Bean之间的连接,则可以再次使用一些工具-在STS中将其称为Bean Graph,在IntelliJ中将其称为Dependencies。 您可以在下面的图片中看到依赖项示例。
<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns='http://www.springframework.org/schema/beans'
xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
xmlns:context='http://www.springframework.org/schema/context'
xmlns:tx='http://www.springframework.org/schema/tx'
xsi:schemaLocation='http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.1.xsd'>
<!-- we can use annotations -->
<context:annotation-config />
<!-- package to look for annotated classes -->
<context:component-scan base-package='org.timesheet.service.impl' />
<!-- we will manage transactions with annotations -->
<tx:annotation-driven />
<!-- data source for our database -->
<bean id='dataSource'
class='org.springframework.jdbc.datasource.DriverManagerDataSource'>
<property name='driverClassName'
value='com.mysql.jdbc.jdbc2.optional.MysqlDataSource' />
<property name='url' value='jdbc:mysql://localhost/timesheet' />
<property name='username' value='root' />
<property name='password' value='' />
</bean>
<!-- configure hibernate session factory -->
<bean id='sessionFactory'
class='org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean'>
<property name='dataSource' ref='dataSource' />
<property name='annotatedClasses' >
<list>
<value>org.timesheet.domain.Employee</value>
<value>org.timesheet.domain.Manager</value>
<value>org.timesheet.domain.Task</value>
<value>org.timesheet.domain.Timesheet</value>
</list>
</property>
<property name='hibernateProperties'>
<props>
<prop key='dialect'>org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key='hibernate.show_sql'>true</prop>
<prop key='hibernate.hbm2ddl.auto'>update</prop>
</props>
</property>
</bean>
</beans>
好的,那是很多配置,对吗? 不好的是,我们已经将实体的名称作为纯文本放置到XML中,因此它不是友好的重构形式。 但我认为对于本教程来说是可以接受的 让我们为Hibernate编写集成测试,以便我们知道一切都已正确设置。
package org.timesheet.integration;
import static org.junit.Assert.*;
import org.hibernate.SessionFactory;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
@ContextConfiguration(locations = '/persistence-beans.xml')
public class HibernateConfigurationTest extends AbstractJUnit4SpringContextTests {
@Autowired
private SessionFactory sessionFactory;
@Test
public void testHibernateConfiguration() {
// Spring IOC container instantiated and prepared sessionFactory
assertNotNull (sessionFactory);
}
}
我要你在这里注意两件事。 首先,我们扩展AbstractJUnit4SpringContextTests类。 我们告诉它应该在哪里寻找使用Spring bean的实际XML配置。 否则,我们将不得不自己创建Spring容器,这意味着需要更多样板代码。
其次,我们使用@Autowired批注。 这意味着我们不会使用新的运算符手动创建SessionFactory实例,而是将其通过Spring容器自动装配(注入)! 这是Spring容器最重要的目的之一-依赖于接口并注入实现而不是手工创建它们。
一切现在都应该正常工作,我认为这部分就足够了。
如果您愿意,可以检查普通的SQL,并在此处查看表,请按照以下步骤进行操作:
mysql> use timesheet;
mysql> show tables;
+---------------------+
| Tables_in_timesheet |
+---------------------+
| employee |
| manager |
| task |
| task_employee |
| timesheet |
+---------------------+
5 rows in set (0.00 sec)
参考: 第2部分–持久层–从vrtoonjava博客的JCG合作伙伴 Michal Vrtiak 编写实体并配置Hibernate 。
翻译自: https://www.javacodegeeks.com/2012/09/spring-persistence-layer-writing.html