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 Data JPA入门
- jpa学习3-spring data jpa 入门环境搭建
- Spring Data JPA入门
- Spring Data JPA 入门篇
- springboot 入门教程(6)--- 整合Spring data JPA实现CRUD(附源码)
- Spring Data JPA入门
- Spring Data JPA快速入门
- SpringData Jpa 入门(接口)
- Spring Data JPA入门(一)
- Spring Data JPA入门
- Spring Data JPA入门
- Spring Data JPA入门
- 第一章:Spring Data JPA入门
- SpringBoot入门(三)--数据库操作&&Spring-data-jpa的使用
- SpringDataJpa的简单入门使用
- Spring Data JPA入门
- spring data jpa 快速入门上手
- Spring Data Jpa基础入门(删改查)
- 【SpringDataJPA】——SpringDataJPA入门实例
- Spring Data JPA入门