Spring Data JPA是Spring基于Hibernate开发的一个JPA框架。如果用过Hibernate或者MyBatis的话,就会知道对象关系映射(ORM)框架有多么方便。但是Spring Data JPA框架功能更进一步,为我们做了 一个数据持久层框架几乎能做的任何事情。

这里总结一下我的整合流程的一个简单例子

首先快速构建一个springboot项目我就不说了,这个比较简单。

项目架构

基于SpringFilter打印Access log spring data page_springboot


1.pom.xml文件加上Spring Data JPA的依赖

<!--spring data jpa 数据持久化组件-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </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;
    }
}

数据库表结构如下:

基于SpringFilter打印Access log spring data page_JavaWeb_02

基于SpringFilter打印Access log spring data page_List_03

下面运行springboot项目,在浏览器上输入对应的访问路径,可以看到对应的json数据
我这里配的是http://localhost:8081/tc/admin/question/allquestions?direction=java

基于SpringFilter打印Access log spring data page_springboot_04


当然我这里只是举的一个简单的例子,直接把数据接口中的json数据显示到前台了,并没有用h5+css+js或者前端框架那些去渲染数据了,有兴趣的同学可以用到自己的前后端分离的项目中去。

Spring Data JPA的内容还远不止我讲的这些,还有很多内层的以及一些注解什么的我就没讲了,这些到后面有机会再补充,这里先介绍SpringBoot整合Spring Data JPA完成数据接口获取的操作(后端部分)。