Spring Data JPA是Spring基于Hibernate开发的一个JPA框架。如果用过Hibernate或者MyBatis的话,就会知道对象关系映射(ORM)框架有多么方便。但是Spring Data JPA框架功能更进一步,为我们做了 一个数据持久层框架几乎能做的任何事情。
这里总结一下我的整合流程的一个简单例子
详细代码见我的github仓库 https://github.com/29DCH/Imitation-nowcoder-questionbank-background-system 欢迎star+fork
首先快速构建一个springboot项目我就不说了,这个比较简单。
项目架构
1.pom.xml文件加上Spring Data JPA的依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-jpaartifactId>
dependency>
2.application.properties配置文件中加入如下配置信息:
# jdbc连接配置
spring.datasource.url=jdbc:mysql://localhost/questionbank?useSSL=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
#jpa hibernate 配置
spring.jpa.show-sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.database-platform=org.hibernate.dialect.MySQL5Dialect
spring.jpa.generate-ddl=true
#最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),
#以后加载hibernate时根据model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。
#要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
spring.jpa.hibernate.ddl-auto=update
实体层entity(和数据库表相对应):
package olcp.entity;
import javax.persistence.*;
import java.io.Serializable;
import java.util.Date;
/**
* 题目
*/
@Entity
@Table(name="question")
public class question implements Serializable{
private static final long serialVersionUID = 1L;
/**
* 题目Id
*/
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column
private Integer id;
/**
* 题目内容
*/
@Column
private String content;
/**
* 题目选项
*/
@Column
private String option;
/**
* 题目图片地址
*/
@Column
private String imgurl;
/**
* 题目类型
*/
@Column
private Integer type;
/**
* 难度
*/
@Column
private Integer difficulty;
/**
* 题目创建时间
*/
@Column
private Date creation_time;
/**
* 题目方向
*/
@Column
private String direction;
/**
* 题目热度
*/
@Column
private Integer hot;
@Column
@Transient
private question question;
public question getQuestion() {
return question;
}
public void setQuestion(question question) {
this.question = question;
}
public question(){
}
public question(String content, String option, String imgurl, Integer type, Integer difficulty, Date
creation_time, String direction, Integer hot) {
this.content = content;
this.option = option;
this.imgurl = imgurl;
this.type = type;
this.difficulty = difficulty;
this.creation_time = creation_time;
this.direction = direction;
this.hot = hot;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getOption() {
return option;
}
public void setOption(String option) {
this.option = option;
}
public String getImgurl() {
return imgurl;
}
public void setImgurl(String imgurl) {
this.imgurl = imgurl;
}
public Integer getType() {
return type;
}
public void setType(Integer type) {
this.type = type;
}
public Integer getDifficulty() {
return difficulty;
}
public void setDifficulty(Integer difficulty) {
this.difficulty = difficulty;
}
public Date getCreation_time() {
return creation_time;
}
public void setCreation_time(Date creation_time) {
this.creation_time = creation_time;
}
public String getDirection() {
return direction;
}
public void setDirection(String direction) {
this.direction = direction;
}
public Integer getHot() {
return hot;
}
public void setHot(Integer hot) {
this.hot = hot;
}
}
dao层(主要作用是定义一系列的接口):
package olcp.dao;
import olcp.entity.question;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.query.Param;
import java.util.List;
public interface questionDao extends JpaRepository<question, Integer>{
//分页查询对应方向的所有题目
Page<question> findByDirection(@Param("direction") String direction, Pageable pageable);
question findById(int id);
//获取对应方向的题目总数
int countByDirection(String direction);
}
注意这里方法命名的格式,JPA对命名格式要求比较严格,一旦不符合标准将很有可能报错。比如这里的findByDirection方法的含义是每次查找对应direction(数据库中的字段名)的所有数据(类似select语句)。我们只要继承它提供的接口,然后按照命名规则定义相应的查询方法。Spring就会自动创建实现了该接口和查询方法的对象,我们直接使用就可以了。也就是说,Spring Data JPA连查询方法都可以帮我们完成(不用写sql语句,但是可以扩展sql语句,使用Query注解)。
public interface UserRepository extends JpaRepository<User, Long> {
@Query("select u from User u where u.emailAddress = ?1")
User findByEmailAddress(String emailAddress);
}
基本的方法如下:
关键字 | 方法命名 | sql where字句 |
And | findByNameAndPwd | where name= ? and pwd =? |
Or | findByNameOrSex | where name= ? or sex=? |
Is,Equals | findById,findByIdEquals | where id= ? |
Between | findByIdBetween | where id between ? and ? |
LessThan | findByIdLessThan | where id < ? |
LessThanEquals | findByIdLessThanEquals | where id <= ? |
GreaterThan | findByIdGreaterThan | where id > ? |
GreaterThanEquals | findByIdGreaterThanEquals | where id > = ? |
After | findByIdAfter | where id > ? |
Before | findByIdBefore | where id < ? |
IsNull | findByNameIsNull | where name is null |
isNotNull,NotNull | findByNameNotNull | where name is not null |
Like | findByNameLike | where name like ? |
NotLike | findByNameNotLike | where name not like ? |
StartingWith |
findByNameStartingWith | where name like '?%' |
EndingWith | findByNameEndingWith | where name like '%?' |
Containing | findByNameContaining | where name like '%?%' |
OrderBy | findByIdOrderByXDesc | where id=? order by x desc |
Not | findByNameNot | where name <> ? |
In | findByIdIn(Collection> c) | where id in (?) |
NotIn | findByIdNotIn(Collection> c) | where id not in (?) |
True | findByAaaTue |
where aaa = true |
False | findByAaaFalse | where aaa = false |
IgnoreCase | findByNameIgnoreCase | where UPPER(name)=UPPER(?) |
<S extends T> S save(S entity); // 保存并返回(修改后的)实体
<S extends T> Iterable<S> save(Iterable<S> entities); // 保存并返回(修改后的)实体集合
T findOne(ID id); // 根据ID获取实体
boolean exists(ID id); // 判断指定ID的实体是否存在
Iterable<T> findAll(); // 查询所有实体
Iterable<T> findAll(Iterable<ID> ids); // 根据ID集合查询实体
long count(); // 获取实体的数量
void delete(ID id); // 删除指定ID的实体
void delete(T entity); // 删除实体
void delete(Iterable<? extends T> entities); // 删除实体集合
void deleteAll(); // 删除所有实体
Iterable<T> findAll(Sort sort); // 查询所有实体并排序
Page<T> findAll(Pageable pageable); // 分页查询实体
void flush(); // 提交事务
<S extends T> S saveAndFlush(S entity); // 保存实体并立即提交事务
void deleteInBatch(Iterable<T> entities); // 批量删除实体集合
void deleteAllInBatch();// 批量删除所有实体
T getOne(ID id); // 根据ID查询实体
service层(定义一系列的接口)
package olcp.service;
import olcp.entity.question;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import java.util.List;
public interface questionService {
/**
* 根据id查询
*
* @param id
* @return question
*/
question findById(int id);
/**
* 分页查询所有题目
*
* @param pageable
* @return
*/
Page<question> findAll(Pageable pageable);
List<question> findAll();
/**
* 按条件查询
*
* @param example
* @return
*/
List<question> findAllExample(Example<question> example);
/**
* 更新
*
* @param question1
* @return
*/
void update(question question1);
/**
* 创建
*
* @param question1
* @return
*/
int create(question question1);
void save(question question1);
/**
* 根据id删除
*
* @param id
* @return
*/
void delById(int id);
/**
* 根据方向查询
* @param direction
* @return
*/
Page<question> findByDirection(String direction,Pageable pageable);
/**
* 根据方向查询题目总数
* @param direction
* @return
*/
int countByDirection(String direction);
}
impl层(实现service层中定义的接口)
package olcp.service.impl;
import olcp.dao.questionDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import olcp.entity.question;
import olcp.service.questionService;
import java.util.List;
@Service
public class questionServiceImpl implements questionService {
@Autowired
private questionDao questionDao1;
@Override
public List<question> findAll() {
return questionDao1.findAll();
}
@Override
public Page<question> findAll(Pageable pageable) {
return questionDao1.findAll(pageable);
}
@Override
public List<question> findAllExample(Example<question> example) { return questionDao1.findAll(example);
}
@Override
public question findById(int id){ return questionDao1.getOne(id); }
@Override
public void update(question question1){ questionDao1.save(question1); }
@Override
public int create(question question1){ return questionDao1.save(question1).getId(); }
@Override
public void delById(int id){ questionDao1.delete(id); }
@Override
public void save(question question1){ questionDao1.save(question1); }
@Override
public Page<question> findByDirection(String direction,Pageable pageable) { return questionDao1.findByDirection(direction,pageable); }
@Override
public int countByDirection(String direction)
{
return questionDao1.countByDirection(direction);
}
}
controller层(控制层,实现数据接口)
package olcp.web.admin;
import olcp.entity.question;
import olcp.service.questionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
@RestController
@RequestMapping("/admin/question")
public class adminQuestionController {
@Autowired
private questionService questionservice;
/**
* 分页查看对应方向的题目
*/
@RequestMapping("/allquestions")
public Page<question> getallquestions(String direction, @RequestParam(defaultValue = "0", required = true)
Integer page) {
Sort sort = new Sort(Sort.Direction.DESC, "id");
Pageable pageable = new PageRequest(page, 8, sort);
Page<question> questions = questionservice.findByDirection(direction, pageable);
return questions;
}
/**
* 获得对应方向的题目总数
*/
@RequestMapping("/getTotal")
public int geTotal(String direction) {
int total = questionservice.countByDirection(direction);
return total;
}
/**
* 新增题目
*/
@RequestMapping("/add")
public Boolean add(@RequestBody question question1) {
question question2 = new question();
question2.setContent(question1.getContent());
question2.setOption(question1.getOption());
question2.setImgurl(question1.getImgurl());
question2.setType(question1.getType());
question2.setDifficulty(question1.getDifficulty());
question2.setCreation_time(question1.getCreation_time());
question2.setDirection(question1.getDirection());
question2.setHot(question1.getHot());
questionservice.save(question2);
return true;
}
/**
* 修改题目
*/
@RequestMapping("/update")
public Boolean update(@RequestBody question question1) {
question question2 = questionservice.findById(question1.getId());
question2.setContent(question1.getContent());
question2.setOption(question1.getOption());
question2.setImgurl(question1.getImgurl());
question2.setType(question1.getType());
question2.setDifficulty(question1.getDifficulty());
question2.setCreation_time(question1.getCreation_time());
question2.setDirection(question1.getDirection());
question2.setHot(question1.getHot());
questionservice.update(question2);
return true;
}
/**
* 删除题目
*/
@RequestMapping("/delete")
public Boolean delete(int id) {
questionservice.delById(id);
return true;
}
}
下面运行springboot项目,在浏览器上输入对应的访问路径,可以看到对应的json数据
我这里配的是http://localhost:8081/tc/admin/question/allquestions?direction=java
当然我这里只是举的一个简单的例子,直接把数据接口中的json数据显示到前台了,并没有用h5+css+js或者前端框架那些去渲染数据了,有兴趣的同学可以用到自己的前后端分离的项目中去。
Spring Data JPA的内容还远不止我讲的这些,还有很多内层的以及一些注解什么的我就没讲了,这些到后面有机会再补充,这里先介绍SpringBoot整合Spring Data JPA完成数据接口获取的操作(后端部分)。