在系统开发过程中,对数据库的操作是必不可少的一项内容,SpringBoot为我们提供了 SpringDataJPA 来快速实现对数据库的 CRUD(Create,Read,Update,Delete)操作。
JPA 是 Java Persistence API 的简称,中文名 Java 持久层 API,是官方(Sun)在 JDK5.0 后提出的 Java 持久化规范。其目的是为了简化现有 JAVA EE 和 JAVA SE 应用开发工作,以及整合现有的 ORM 技术实现规范统一。
下面将使用SpringBoot访问MySQL数据库,并且结合SpringDataJPA完成CRUD简单操作。
首先在N0.1 SpringBoot 2.X 之 SpringBoot初体验已经创建好了对应的项目,在此基础上,还需要引入另外的SpringBoot组件来支持CRUD操作。
其中,必须的组件为 JPA,MySql和Web,DevTools用来实现SpringBoot项目热部署,修改代码会自动部署项目,Freemarker 是模板引擎,用来实现页面。
打开项目自动生成的 Application.java 文件:
package com.minstone;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class HelloSpringBootApplication {
public static void main(String[] args) {
SpringApplication.run(HelloSpringBootApplication.class, args);
}
}
其中 @SpringBootApplication 是 Spring Boot 项目的核心注解,主要目的是开启自动配置,main 方法是应用的入口。
接下来,需要在 application.yml 中配置数据源和 JPA 等信息。
可以看到在配置文件中,我们使用了本地的一个mysql数据库,并且创建了一个名叫 db_book 的数据库,JPA 配置了 ddl-aoto 来实现根据实体类自动建表,show-sql 用来在控制台输出JPA自动生成的sql语句。
spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/db_book
username: root
password: 123456
jpa:
hibernate:
ddl-auto: update
show-sql: true
除此之外,还需要配置DevTools的一些信息。
devtools:
restart:
enabled: true
additional-paths: src/main/java
接下来,需要创建一个 Book 实体。
package com.minstone.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity(name="t_book")
public class Book {
@Id
@GeneratedValue
private Integer id;
@Column(length=100)
private String bookName;
@Column(length=50)
private String author;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBookName() {
return bookName;
}
public void setBookName(String bookName) {
this.bookName = bookName;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
}
然后我们要创建一个 DAO,并继承 JpaRepository 用于简单查询,继承 JpaSpecificationExecutor 来实现复杂查询。
简单查询不需要代码实现,当简单查询无法满足我们的需求时,需要我们自己用代码去实现。
package com.minstone.dao;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
import org.springframework.data.jpa.repository.Query;
import com.minstone.entity.Book;
/**
* 图书dao
* @author ChenDongWei
*
*/
public interface BookDao extends JpaRepository<Book, Integer>, JpaSpecificationExecutor<Book>{
/**
*
* queryByName:(根据名称查询图书). <br/>
* @author ChenDongWei
* @date 2018年8月10日上午10:26:20
* @param bookName
* @return
*/
@Query(value = "select * from t_book where book_name like %?1%", nativeQuery=true)
public List<Book> queryByName(String bookName);
}
创建完 DAO 后,我们再创建一个 BookService
类,在该项目中,我并没有编写 Service 接口,而是直接编写 BookService 来操作 DAO,在实际开发工作中,我们往往需要创建 Service 接口的。
package com.minstone.service;
import java.util.List;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import com.minstone.dao.BookDao;
import com.minstone.entity.Book;
@Service
@Transactional
public class BookService {
@Autowired
private BookDao bookDao;
//查询所有
public List<Book> findAll(){
return bookDao.findAll();
}
//添加图书
public void add(Book book) {
bookDao.save(book);
}
//根据ID查找图书
public Book preUpdate(int id) {
Book book = bookDao.getOne(id);
return book;
}
//修改图书
public void update(Book book) {
bookDao.save(book);
}
//删除图书
public void delete(int id) {
bookDao.deleteById(id);
}
//根据书名查找图书
public List<Book> queryByName(String bookName){
return bookDao.queryByName(bookName);
}
//根据名称或作者查询(高级)
public List<Book> queryByNameOrAuthor(Book book) {
List<Book> bookList = bookDao.findAll(new Specification<Book>() {
@Override
public Predicate toPredicate(Root<Book> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
Predicate predicate = cb.conjunction();
if (book != null) {
if (StringUtils.isNotBlank(book.getBookName())) {
predicate.getExpressions().add(cb.like(root.get("bookName"), "%"+book.getBookName().trim()+"%"));
}
if (StringUtils.isNotBlank(book.getAuthor())) {
predicate.getExpressions().add(cb.like(root.get("author"), "%"+book.getAuthor().trim()+"%"));
}
}
return predicate;
}
});
return bookList;
}
}
上述方法中,queryByNameOrAuthor 方法是根据名称或作者查询,需要调用到我们在 DAO 中收到编写的代码,其他的方法,都是 SpringBoot JPA 内置的方法,当然,其支持分页的操作,在这里不做演示。
接着我们创建一个 BookController 类。
package com.minstone.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
import com.minstone.entity.Book;
import com.minstone.service.BookService;
/**
* 图书控制类
* @author ChenDongWei
*
*/
@RestController
@RequestMapping("/book/")
public class BookController {
@Autowired
private BookService bookService;
/**
*
* list:(查询所有图书). <br/>
* @author ChenDongWei
* @date 2018年8月9日下午8:27:53
* @return
*/
@RequestMapping("list")
public ModelAndView list() {
ModelAndView modelAndView = new ModelAndView("bookList");
modelAndView.addObject("bookList", bookService.findAll());
return modelAndView;
}
/**
*
* add:(添加图书). <br/>
* @author ChenDongWei
* @date 2018年8月9日下午8:28:48
* @param book
* @return
*/
@RequestMapping("add")
public ModelAndView add(Book book) {
bookService.add(book);
return list();
}
/**
*
* preUpdate:(跳转到修改图书). <br/>
* @author ChenDongWei
* @date 2018年8月9日下午8:29:07
* @param id
* @return
*/
@RequestMapping("preUpdate/{id}")
public ModelAndView preUpdate(@PathVariable("id")Integer id) {
ModelAndView modelAndView = new ModelAndView("bookUpdate");
modelAndView.addObject("book", bookService.preUpdate(id));
return modelAndView;
}
/**
*
* update:(修改图书). <br/>
* @author ChenDongWei
* @date 2018年8月9日下午8:29:25
* @param book
* @return
*/
@RequestMapping("update")
public ModelAndView update(Book book) {
bookService.update(book);
return list();
}
/**
*
* delete:(删除图书). <br/>
* @author ChenDongWei
* @date 2018年8月9日下午8:29:43
* @param id
* @return
*/
@RequestMapping("delete")
public ModelAndView delete(Integer id) {
bookService.delete(id);
return list();
}
/**
*
* query:(根据名称查询图书). <br/>
* @author ChenDongWei
* @date 2018年8月10日上午10:16:04
* @param bookName
* @return
*/
@RequestMapping("queryByName")
public ModelAndView queryByName(String bookName) {
ModelAndView modelAndView = new ModelAndView("bookList");
modelAndView.addObject("bookList", bookService.queryByName("放弃"));
return modelAndView;
}
/**
*
* queryByNameOrAuthor:(根据名称或作者查询). <br/>
* @author ChenDongWei
* @date 2018年8月10日下午1:46:57
* @param book
* @return
*/
@RequestMapping("queryByNameOrAuthor")
public ModelAndView queryByNameOrAuthor(Book book) {
ModelAndView modelAndView = new ModelAndView("bookList");
modelAndView.addObject("bookList", bookService.queryByNameOrAuthor(book));
return modelAndView;
}
}
最后,需要用 freemarker 模板和 html 来实现页面。
在 src/main/webapp 目录下创建 bookAdd.html。
在 src/main/resources/templates 页面下创建 bookList.ftl 和 bookUpdate.ftl 页面,其中 .ftl 是 freemarker 模板的后缀。
创建 bookList.ftl
创建 bookUpdate.ftl
至此,SpringBoot 实现 CRUD 的项目就完成了,我们启动项目测试一下。
注意:首次项目启动后,控制台会打印 Hibernate 的建表语句,这是因为我们在 application.yml 中配置了 ddl-auto: update,会根据实体类自动在数据库创建表。
创建的表如下,其中长度,主键等与实体类的配置是一致的。
然后我们在表中手动插入几条初始数据。
运行项目成功后,访问 http://127.0.0.1:8082/book/list 查询图书列表
此时,控制台打印出了执行的 sql 语句。
Hibernate: select book0_.id as id1_1_, book0_.author as author2_1_, book0_.book_name as book_nam3_1_ from t_book book0_
列表显示正常,搜索,添加,修改和删除功能也能正常实现。