您的位置:首页 > 编程语言 > Java开发

Spring orm +Spring data jpa 入门

2017-12-21 20:20 471 查看

系统架构

使用 Spring orm 开发 JPA 数据持久层,用 Spring data jpa 简化 DAO实现,真的不用写 SQL 了

先导包:pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion>
<groupId>com.cheery.recruitment</groupId>
<artifactId>Recruitment-Webservice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Recruitment-Webservice</name>
<description>Recruitment-Webservice</description>

<dependencies>
<!-- spring-context:  spring 框架核心jars -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- spring-orm: 包含 orm 开发的jars,事务也会有 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<!-- spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.0.2.RELEASE</version>
</dependency>
<!-- hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.12.Final</version>
</dependency>
<!-- mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.45</version>
</dependency>
<!-- commons-dbcp2 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.1.1</version>
</dependency>

</dependencies>

</project>


架构一览:

Spring 核心,依赖注入,并用容器管理 JPA EntityManager …

JPA , 持久化API ,实现选择 Hibernate

MySQL ,数据库

DBCP, 连接池

Spring data jpa, 简化 DAO 实现

完整示例一个

招聘信息,公司发布招聘信息,查询相关信息。

1、 ORM 设计

很简单,两个 Entity ,在 domain 包下面:

Company: 公司类,name 唯一、非空 ,city非空(方便测试)

package com.cheery.recruitment.domain;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

@Entity
@Table(name="company")
public class Company {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private int id;

@Column(nullable=false,unique=true)
private String name; // 名称:阿里巴巴
@Column(nullable=false)
private String city; // 城市: 杭州
private String address; // 公司地址
private String website;// 公司网站
private String industry;// 行业
private String description;// 简介

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public String getAddress() {
return address;
}

public void setAddress(String address) {
this.address = address;
}

public String getWebsite() {
return website;
}

public void setWebsite(String website) {
this.website = website;
}

public String getIndustry() {
return industry;
}

public void setIndustry(String industry) {
this.industry = industry;
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public int getId() {
return id;
}

public void setId(int id) {
this.id = id;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}
}


Recruitment :招聘信息类,外键关联 company_id(one-to-one), job+company 构成唯一性约束,城市和工资非空(方便测试)

package com.cheery.recruitment.domain;

import java.util.Date;

import javax.persistence.Column;
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;
import javax.persistence.UniqueConstraint;

@Entity
@Table(name = "recruitment", uniqueConstraints = { @UniqueConstraint(columnNames = { "job", "company_id" }) })
public class Recruitment {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@Column(nullable = false)
private String job; // 岗位:Java高级工程师
@OneToOne
@JoinColumn(name = "company_id", nullable = false)
private Company company; // 公司:阿里巴巴
private String city;// 工作地点:杭州
private int salary;// 薪酬,月薪:20000
private String education;// 学历要求:小学
private short experience;// 工作经验:5, 0(应届生)
private Date publishTime;// 发布时间:2017-12-25
private Date deadline;// 有效期至:201s7-12-16, null(长期有效)
private String industry; // 行业:IT
private String responsibility; // 岗位职责:1.2.3...
private String requirement;// 岗位要求:1.2.3...
private String welfare;// 福利:五险一金,100个月年终奖...

public Long getId() {
return id;
}

public void setId(Long id) {
this.id = id;
}

public String getJob() {
return job;
}

public void setJob(String job) {
this.job = job;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public int getSalary() {
return salary;
}

public void setSalary(int salary) {
this.salary = salary;
}

public Company getCompany() {
return company;
}

public void setCompany(Company company) {
this.company = company;
}

public String getEducation() {
return education;
}

public void setEducation(String education) {
this.education = education;
}

public short getExperience() {
return experience;
}

public void setExperience(short experience) {
this.experience = experience;
}

public Date getPublishTime() {
return publishTime;
}

public void setPublishTime(Date publishTime) {
this.publishTime = publishTime;
}

public Date getDeadline() {
return deadline;
}

public void setDeadline(Date deadline) {
this.deadline = deadline;
}

public String getIndustry() {
return industry;
}

public void setIndustry(String industry) {
this.industry = industry;
}

public String getResponsibility() {
return responsibility;
}

public void setResponsibility(String responsibility) {
this.responsibility = responsibility;
}

public String getRequirement() {
return requirement;
}

public void setRequirement(String requirement) {
this.requirement = requirement;
}

public String getWelfare() {
return welfare;
}

public void setWelfare(String welfare) {
this.welfare = welfare;
}

}


2. DAO 实现

使用 spring data jpa 实现 dao 不要太简单

核心原理:继承 JpaRepository 的接口后,框架会自动生成对应的实现类,并实现了一系列的方法,CRUD 根本没问题。要启用这个功能,必须进行配置,注解实现是这样的:

@EnableJpaRepositories(basePackages="com.cheery.recruitment.repository")


package com.cheery.recruitment.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.cheery.recruitment.domain.Company;

public interface CompanyRepo extends JpaRepository<Company, Integer>{

//注意哦,这个方法 spring data jpa 也会动态生成实现的哦!
public List<Company> readByCity(String city);
public Company findCompanyByName(String name);

}


package com.cheery.recruitment.repository;

import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;

import com.cheery.recruitment.domain.Recruitment;

public interface RecruitmentRepo extends JpaRepository<Recruitment, Long> {

// 指定城市工资超过多少的指定工作, 这个方法也会动态实现的哦!
public List<Recruitment> readByJobLikeAndCityAndSalaryGreaterThanEqual(String job,String city,int salary);

}


说明:

上面两个接口都实现了 JpaRepository , spring data jpa 会在 Spring application context 创建之后创建实现类,默认情况下,实现类名=接口类名+Impl 。也就是说,会创建两个实现类, CompanyRepoImpl 和 RecruitmentRepoImpl 。

JpaRepository 接口及其父接口定义的方法,实现类都会自动实现,同时,Spring data jpa 还支持定制的查询方法,如 “readByJobLikeAndCityAndSalaryGreaterThanEqual”,这个方法符合,这些方法称为 “Repository methods”。

他们的格式是:查询动词+查询对象(可省略)+By+查询条件

这里 read 是查询动词,与 get和find作用相同,还有一个查询动词 count 。这个方法省略了对象声明 “Recruitments”,所以 readRecruitments… 效果一样。

“JobLikeAndCityAndSalaryGreaterThanEqual”是查询条件,多个条件用 And 或 Or 组合,条件可以是 SQL支持的多种之一,这里用到的是,Like (job 模糊查询), =(city =‘杭州’),>=(salary >=30000)

如果 Repository methods ,还不能满足需求,可以再定义一个DAO 接口,如 CompanyCustRepo , 在其中声明定制的方法。然后让实现类实现该接口,如 CompanyRepoImpl , 你只要在该类中实现 CompanyCustRepo 的方法,CompanyRepo 中的方法自动合并到这个类实现中,前提是,这个类名只能是CompanyRepo +Impl 不能随便改了。

JPA 配置

由于该 demo 用 java app 测试,所以配置相对简单,使用java 注解的配置方式

RepoConfig:Dao 配置

package com.cheery.recruitment.configure;

import java.util.HashMap;
import java.util.Map;

import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;

import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
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.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@ComponentScan(basePackages="com.cheery.recruitment.repository")
@EnableJpaRepositories(basePackages="com.cheery.recruitment.repository")
@EnableTransactionManagement
public class RepoConfig {

@Bean(destroyMethod = "close")
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql:///recruitment");
dataSource.setUsername("XXX");
dataSource.setPassword("XXX");
return dataSource;
}

@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPersistenceProviderClass(HibernatePersistenceProvider.class);
factoryBean.setDataSource(dataSource());
factoryBean.setPackagesToScan("com.cheery.recruitment.domain");
factoryBean.setJpaPropertyMap(jpaProperties());
return factoryBean;
}

@Bean
@Autowired
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}

private Map<String, ?> jpaProperties() {
Map<String, String> jpaPropertiesMap = new HashMap<String, String>();
jpaPropertiesMap.put("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect");
jpaPropertiesMap.put("hibernate.hbm2ddl.auto", "update");
return jpaPropertiesMap;
}

}


@Configuration : 声明这是配置类

@ComponentScan(basePackages=”com.cheery.recruitment.repository”) : 启用基于注解的 bean 定义

@EnableJpaRepositories(basePackages=”com.cheery.recruitment.repository”) :启用 Spring data jpa JpaRepositories 功能

@EnableTransactionManagement:启用事务管理

ServiceConfig : Service 层配置

package com.cheery.recruitment.configure;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.annotation.EnableTransactionManagement;

@Configuration
@ComponentScan(basePackages="com.cheery.recruitment.service")
@EnableTransactionManagement
public class ServiceConfig {

}


4.Service 层

package com.cheery.recruitment.service;

import java.util.List;

import com.cheery.recruitment.domain.Company;

public interface CompanyService {

public boolean saveCompany(Company company);
public Company getCompanyByName(String name);
public List<Company> findAllCompanies();
public List<Company> findCompaniesByCity(String city);

}


package com.cheery.recruitment.service;

import java.util.List;

import javax.transaction.Transactional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cheery.recruitment.domain.Company;
import com.cheery.recruitment.repository.CompanyRepo;

@Service
@Transactional
public class CompanyServiceImpl implements CompanyService {

@Autowired
private CompanyRepo companyDao;

@Override
public boolean saveCompany(Company company) {
if (companyDao.save(company) == null) {
return false;
} else {
return true;
}
}

@Override
public List<Company> findAllCompanies() {
return companyDao.findAll();
}

@Override
public List<Company> findCompaniesByCity(String city) {
return companyDao.readByCity(city);
}

@Override
public Company getCompanyByName(String name) {
return companyDao.findCompanyByName(name);
}

}


package com.cheery.recruitment.service;

import java.util.List;

import com.cheery.recruitment.domain.Recruitment;

public interface RecruitmentService {

public boolean saveRecruitment(Recruitment recruitment);
public List<Recruitment> findAllRecruitments();
public List<Recruitment> findRecruitmentsByCriteria(String job,String city,int salary);

}


package com.cheery.recruitment.service;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.cheery.recruitment.domain.Recruitment;
import com.cheery.recruitment.repository.RecruitmentRepo;

@Service
public class RecruitmentServiceImpl implements RecruitmentService {

@Autowired
private RecruitmentRepo recruitmentDao;

@Override
public boolean saveRecruitment(Recruitment recruitment) {
if (recruitmentDao.save(recruitment) == null) {
return false;
} else {
return true;
}
}

@Override
public List<Recruitment> findAllRecruitments() {
return this.recruitmentDao.findAll();
}

@Override
public List<Recruitment> findRecruitmentsByCriteria(String job, String city, int salary) {
String jobCriteria="%"+job+"%";
return this.recruitmentDao.readByJobLikeAndCityAndSalaryGreaterThanEqual(jobCriteria, city, salary);
}

}


5. 应用层

package com.cheery.recruitment;

import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.cheery.recruitment.configure.RepoConfig;
import com.cheery.recruitment.configure.ServiceConfig;
import com.cheery.recruitment.domain.Company;
import com.cheery.recruitment.domain.Recruitment;
import com.cheery.recruitment.service.CompanyService;
import com.cheery.recruitment.service.RecruitmentService;

public class Main {

public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(RepoConfig.class,
ServiceConfig.class);

CompanyService companyService = (CompanyService) applicationContext.getBean("companyServiceImpl");
RecruitmentService recruitService=(RecruitmentService) applicationContext.getBean("recruitmentServiceImpl");

//加几个公司试试
initCompanyInfo(companyService);

System.out.println("系统当前的公司列表:");
printCompanies(companyService.findAllCompanies());

System.out.println("系统当前的杭州公司列表:");
printCompanies(companyService.findCompaniesByCity("杭州"));

//加几条招聘信息试试
initReruitmentInfo(companyService, recruitService);

//查找杭州工资超过30000的Java相关工作
printRecruitments(recruitService.findRecruitmentsByCriteria("Java", "杭州", 30000));

}

private static void initCompanyInfo(CompanyService companyService) {
// 新增三个公司
Company alibaba = new Company();
alibaba.setName("阿里巴巴");
alibaba.setCity("杭州");
Company neteasy = new Company();
neteasy.setCity("杭州");
neteasy.setName("网易");
Company tencent = new Company();
tencent.setCity("深圳");
tencent.setName("腾讯");

companyService.saveCompany(alibaba);
companyService.saveCompany(neteasy);
companyService.saveCompany(tencent);
}

private static void initReruitmentInfo(CompanyService companyService, RecruitmentService recruitService) {
// 阿里巴巴发布两条招聘信息
Recruitment ali_recruit1 = new Recruitment();
ali_recruit1.setJob("Java初级工程师");
ali_recruit1.setCity("杭州");
ali_recruit1.setCompany(companyService.getCompanyByName("阿里巴巴"));
ali_recruit1.setSalary(20000);
recruitService.saveRecruitment(ali_recruit1);

Recruitment ali_recruit2 = new Recruitment();
ali_recruit2.setJob("Java高级工程师");
ali_recruit2.setCity("杭州");
ali_recruit2.setCompany(companyService.getCompanyByName("阿里巴巴"));
ali_recruit2.setSalary(40000);
recruitService.saveRecruitment(ali_recruit2);

// 网易发布两条招聘信息
Recruitment neteasy_recruit1 = new Recruitment();
neteasy_recruit1.setJob("Java高级工程师");
neteasy_recruit1.setCity("杭州");
neteasy_recruit1.setCompany(companyService.getCompanyByName("网易"));
neteasy_recruit1.setSalary(30000);
recruitService.saveRecruitment(neteasy_recruit1);

Recruitment neteasy_recruit2 = new Recruitment();
neteasy_recruit2.setJob("Python高级工程师");
neteasy_recruit2.setCity("杭州");
neteasy_recruit2.setCompany(companyService.getCompanyByName("网易"));
neteasy_recruit2.setSalary(35000);
recruitService.saveRecruitment(neteasy_recruit2);

// 腾讯发布两条招聘信息
Recruitment tencent_recruit1 = new Recruitment();
tencent_recruit1.setJob("Java开发工程师");
tencent_recruit1.setCity("深圳");
tencent_recruit1.setCompany(companyService.getCompanyByName("腾讯"));
tencent_recruit1.setSalary(20000);
recruitService.saveRecruitment(tencent_recruit1);

Recruitment tencent_recruit2 = new Recruitment();
tencent_recruit2.setJob("Java高级工程师");
tencent_recruit2.setCity("深圳");
tencent_recruit2.setCompany(companyService.getCompanyByName("腾讯"));
tencent_recruit2.setSalary(40000);
recruitService.saveRecruitment(tencent_recruit2);
}

private static void printCompanies(List<Company> companies) {
for (Company c : companies) {
System.out.println(c.getName());
}
}

private static void printRecruitments(List<Recruitment> recruitments) {
for (Recruitment r : recruitments) {
String name=r.getJob()+"("+r.getCompany().getName()+")"; //招聘信息名称:job(companyName)
String salary=r.getSalary()+"元/月";
System.out.println(name+"--"+r.getCity()+"--"+salary);
}
}
}


总结

在以业务为中心的应用中,使用 orm 框架还是很有优势的,而使用 orm框架,则使用JPA设计不依赖与特定提供商的代码很有必要,这样能轻易在供应商之间切换。就 JPA 实现来说,Hibernate 是不错的选择,也是 Spring orm 默认的选择。

使用 spring data jpa 可以轻松实现 dao ,再也不用什么泛型啊,反射啊,功能很强大!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  spring orm jpa dao java