下面的例子是基于SpringBoot JPA以及H2数据库来实现的,下面就开始搭建项目吧。
首先看下项目的整体结构:
具体操作步骤:
打开IDEA,创建一个新的Spring Initializr项目,填写好groupID等信息,依赖勾选web和H2,一路next:
pom.xml关键依赖:
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies>
新建controller、domain、service包,创建JPA实体类User:
package com.example.demo.domain; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.time.LocalDate; import javax.persistence.*; /** * @Description: SpringBoot自动配置会探测到我们使用了H2数据库,它会根据实体类自动创建数据表 * @author: Alan * @Date: 2018/11/30 22:33 */ @Entity @Table(name = "user") public class User implements Serializable{ private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id;//主键 @Column(nullable = false) private String firstName;//名 @Column(nullable = false) private String lastName;//姓 @Column(nullable = false) private String idCard;//身份证 @Column(nullable = false) @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate dateOfBirth;//出生日期 public User() { } public User(Long id, String firstName, String lastName, String idCard, LocalDate dateOfBirth) { this.id = id; this.firstName = firstName; this.lastName = lastName; this.idCard = idCard; this.dateOfBirth = dateOfBirth; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public String getIdCard() { return idCard; } public void setIdCard(String idCard) { this.idCard = idCard; } public LocalDate getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(LocalDate dateOfBirth) { this.dateOfBirth = dateOfBirth; } @Override public String toString() { return "User{" + "id=" + id + ", firstName='" + firstName + '\'' + ", lastName='" + lastName + '\'' + ", idCard='" + idCard + '\'' + ", dateOfBirth=" + dateOfBirth + '}'; } }
说明:
@Entity: 指明了这是一个entity
@Table:指定生成的表名
@Id: 标记该entity的主键
@GeneratedValue: 提供主键的生成策略
编写配置文件和数据生成语句:
application.properties:
#激活开发环境的的配置文件
spring.profiles.active=dev
application-dev.properties:
#端口设置
server.port=8080
#开启日志记录(日志文件会在10Mb大小的时候被截断,产生新的日志文件)
logging.file=logs/my.log
spring.h2.console.enabled=true
spring.jpa.open-in-view=true
spring.data.jpa.repositories.bootstrap-mode=default
logging.level.org.hibernate.SQL=debug
import.sql:
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven1', 'Jobs1','630121199206081105', '1998-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven2', 'Jobs2','510181199412105672', '1992-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven3', 'Jobs','610702199009261457', '1991-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven4', 'Jobs','430426198801075355', '1994-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven5', 'Michael','420117199502232760', '1998-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven6', 'Michael','130203199404122670', '1998-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven7', 'Michael','430703197612014630', '1998-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven8', 'Michael','350124197805280264', '1998-07-13');
INSERT INTO USER (FIRST_NAME, LAST_NAME, ID_CARD, DATE_OF_BIRTH) values ('Steven9', 'Michael','500230197205314628', '1998-08-19');
JpaRepository
该接口继承了PagingAndSortingRepository和QueryByExampleExecutor接口,相比CrudRepository接口多了分页和排序功能,因此JpaRepository功能更加全面,如果你不需要分页和排序功能,使用CrudRepository即可。这里我们使用JpaRepository,其定义如下:
@NoRepositoryBean public interface JpaRepository<T, ID> extends PagingAndSortingRepository<T, ID>, QueryByExampleExecutor<T> {
UserRepository(相当于DAO层,定义了增删改查的方法):
package com.example.demo.service; import com.example.demo.domain.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import java.time.LocalDate; import java.util.List; /** * @Description: * @author: Alan * @Date: 2018/11/30 22:54 */ public interface UserRepository extends JpaRepository<User, Long>{ /******************************create***************************************/ @Override User save(User user); /******************************read***************************************/ /** * Using sort * @param lastName * @param sort * @return */ @Query("select u from User u where u.lastName like ?1%") List<User> findByAndSort(String lastName, Sort sort); /** * Query creation * this translates into the following query: * select u from User u where u.idCard = ?1 */ User findByIdCard(String idCard); /** * Native Queries * The @Query annotation allows for running native queries by setting the nativeQuery flag to true * @param idCard * @return */ @Query(value = "select * from user where ID_CARD = ?1", nativeQuery = true) User findByIdCard2(String idCard); /** * Using @Query * @param idCard * @return */ @Query("select u from User u where u.idCard = ?1") User findByIdCard3(String idCard); /** * Declare native count queries for pagination at the query method by using @Query * @param lastName * @param pageable * @return */ @Query(value = "SELECT * FROM User WHERE LAST_NAME = ?1", countQuery = "SELECT count(*) FROM User WHERE LAST_NAME = ?1", nativeQuery = true) Page<User> findByLastNameWithPageable(String lastName, Pageable pageable); /** * Using Named Parameters * @param firstName * @param lastName * @return */ @Query("select u from User u where u.firstName = :firstName or u.lastName = :lastName") List<User> findByFirstNameOrLastName(@Param("firstName") String firstName, @Param("lastName") String lastName); /** * findByDateOfBirth * @param date * @return */ List<User> findByDateOfBirth(@Param("date") LocalDate date); /** * find all users * @param sort * @return */ @Override List<User> findAll(Sort sort); /****************************update*****************************************/ /** * update a usr by Modifying Queries * @param firstName * @param idCard * @return */ @Modifying @Query("update User u set u.firstName = ?1 where u.idCard = ?2") int updateUser(String firstName, String idCard); /****************************delete*****************************************/ /** * delete a user by idCard * @param idCard */ void deleteByIdCard(String idCard); /** * Using a derived delete query * @param idCard */ @Modifying @Query("delete from User u where u.idCard = ?1") void deleteByIdCard2(String idCard); /** * delete a user by id * @param id */ @Override @Modifying @Query(value = "delete from user where id = ?1", nativeQuery = true) void deleteById(Long id); }
UserService:
package com.example.demo.service; import com.example.demo.domain.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.Param; import java.time.LocalDate; import java.util.List; /** * @Description: * @author: Alan * @Date: 2018/12/1 11:44 */ public interface UserService { /****************************create*****************************************/ User save(User user); /****************************read*****************************************/ List<User> findByAndSort(String lastName, Sort sort); User findByIdCard(String idCard); User findByIdCard2(String idCard); User findByIdCard3(String idCard); Page<User> findByLastNameWithPageable(String lastName, Pageable pageable); List<User> findByFirstNameOrLastName(String firstName, String lastName); List<User> findByDateOfBirth(@Param("date") LocalDate date); List<User> findAll(Sort sort); /*****************************update****************************************/ int updateUser(String firstName, String idCard); /*****************************delete****************************************/ void deleteByIdCard(String idCard); void deleteByIdCard2(String idCard); void deleteById(Long id); }
UserServiceImpl:(UserService的实现类)
package com.example.demo.service; import com.example.demo.domain.User; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.time.LocalDate; import java.util.List; /** * @Description: * @author: Alan * @Date: 2018/12/1 11:44 */ @Component("userService") @Transactional public class UserServiceImpl implements UserService { private UserRepository userRepository; UserServiceImpl(UserRepository userRepository) { this.userRepository = userRepository; } /**************************create********************************/ @Override public User save(User user) { return userRepository.save(user); } /**************************read********************************/ @Override public List<User> findByAndSort(String lastName, Sort sort) { return userRepository.findByAndSort(lastName, sort); } @Override public User findByIdCard(String idCard) { return userRepository.findByIdCard(idCard); } @Override public User findByIdCard2(String idCard) { return userRepository.findByIdCard2(idCard); } @Override public User findByIdCard3(String idCard) { return userRepository.findByIdCard3(idCard); } @Override public Page<User> findByLastNameWithPageable(String lastName, Pageable pageable) { return userRepository.findByLastNameWithPageable(lastName, pageable); } @Override public List<User> findByFirstNameOrLastName(String firstName, String lastName) { return userRepository.findByFirstNameOrLastName(firstName, lastName); } @Override public List<User> findByDateOfBirth(@Param("date") LocalDate date) { return userRepository.findByDateOfBirth(date); } @Override public List<User> findAll(Sort sort) { return userRepository.findAll(sort); } /**************************update********************************/ @Override public int updateUser(String firstName, String idCard) { return userRepository.updateUser(firstName, idCard); } /**************************delete********************************/ @Override public void deleteByIdCard(String idCard) { userRepository.deleteByIdCard(idCard); } @Override public void deleteByIdCard2(String idCard) { userRepository.deleteByIdCard2(idCard); } @Override public void deleteById(Long id) { userRepository.deleteById(id); } }
UserController:
package com.example.demo.controller; import com.example.demo.domain.User; import com.example.demo.service.UserService; 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.format.annotation.DateTimeFormat; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import java.time.LocalDate; import java.util.List; /** * @Description: * POST - Create a new resource * GET - Read a resource * PUT - Update an existing resource * DELETE - Delete a resource * Tomcat by default is not enabled for HTTP PUT command. * 只要让地址栏的参数可以传入函数里面,就能执行修改、新增、删除操作,method用RequestMethod.GET即可 * 用PUT、POST、DELETE会报405错误,因为输入到地址栏默认使用GET方法 * 注解@DateTimeFormat(iso = DateTimeFormat.ISO.DATE)主要是解决请求日期无法转成LocalDate的问题 * @author: Alan * @Date: 2018/12/1 10:38 */ @RestController public class UserController { @Autowired private UserService userService; /*****************************create*************************************/ @RequestMapping(value = "/saveUser/{firstName}/{lastName}/{idCard}/{date}",method = RequestMethod.GET) @Transactional public User saveUser(@PathVariable String firstName, @PathVariable String lastName, @PathVariable String idCard, @PathVariable @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) { User user = new User();//Id是自增长的,不需要传 user.setFirstName(firstName); user.setLastName(lastName); user.setIdCard(idCard); user.setDateOfBirth(date); return userService.save(user); } /*****************************Read***** ********************************/ @RequestMapping(value = "/findByAndSort/{lastName}", method = RequestMethod.GET) public List<User> findByAndSort(@PathVariable String lastName) { Sort sort = new Sort(Sort.Direction.DESC, "firstName"); return userService.findByAndSort(lastName, sort); } @RequestMapping(value = "/findByIdCard/{idCard}", method = RequestMethod.GET) @Transactional(readOnly = true) public User findByIdCard(@PathVariable(name = "idCard") String idCard) { return userService.findByIdCard(idCard); } @RequestMapping(value = "/findByIdCard2/{idCard}", method = RequestMethod.GET) @Transactional(readOnly = true) public User findByIdCard2(@PathVariable(name = "idCard") String idCard) { return userService.findByIdCard2(idCard); } @RequestMapping(value = "/findByIdCard3/{idCard}", method = RequestMethod.GET) @Transactional(readOnly = true) public User findByIdCard3(@PathVariable(name = "idCard") String idCard) { return userService.findByIdCard3(idCard); } @RequestMapping(value = "/findByLastNameWithPageable/{lastName}", method = RequestMethod.GET) @Transactional(readOnly = true) public Page<User> findByLastNameWithPageable(@PathVariable String lastName) { Sort sort = new Sort(Sort.Direction.DESC, "id"); Pageable pageable = new PageRequest(5,2,sort); return userService.findByLastNameWithPageable(lastName, pageable); } @RequestMapping(value = "/findByFirstNameOrLastName/{firstName}/{lastName}", method = RequestMethod.GET) public List<User> findByFirstNameOrLastName(@PathVariable String firstName, @PathVariable String lastName) { return userService.findByFirstNameOrLastName(firstName, lastName); } @RequestMapping(value = "/findByDateOfBirth/{date}", method = RequestMethod.GET) public List<User> findByDateOfBirth(@PathVariable(name = "date") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) LocalDate date) { return userService.findByDateOfBirth(date); } @RequestMapping(value = "/findAll", method = RequestMethod.GET) public List<User> findAll() { Sort sort = new Sort(Sort.Direction.ASC, "id"); return userService.findAll(sort); } /*****************************update*************************************/ @RequestMapping(value = "/updateUser/{firstName}/{idCard}", method = RequestMethod.GET) public int updateUser(@PathVariable String firstName, @PathVariable String idCard) { return userService.updateUser(firstName, idCard); } /*****************************delete*************************************/ @RequestMapping(value = "/deleteByIdCard/{idCard}", method = RequestMethod.GET) @Transactional public String deleteByIdCard(@PathVariable String idCard) { userService.deleteByIdCard(idCard); return "SUCCESS"; } @RequestMapping(value = "/deleteByIdCard2/{idCard}", method = RequestMethod.GET) @Transactional public String deleteByIdCard2(@PathVariable String idCard) { userService.deleteByIdCard2(idCard); return "SUCCESS"; } @RequestMapping(value = "/deleteById/{id}", method = RequestMethod.GET) @Transactional public String deleteById(@PathVariable Long id) { userService.deleteById(id); return "SUCCESS"; } }
SpringBoot主类移植com包下,这样其他类才能被扫描到:
启动SpringBoot项目:点击菜单栏的运行按钮或者运行main方法
此时控制台可以看到创建表和插入sql语句的日志:
查询所有用户:
浏览器地址栏输入:http://localhost:8080/findAll
可以看到所有的记录:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
[ { "id": 1, "firstName": "Steven1", "lastName": "Jobs1", "idCard": "630121199206081105", "dateOfBirth": "1998-07-13" }, { "id": 2, "firstName": "Steven2", "lastName": "Jobs2", "idCard": "510181199412105672", "dateOfBirth": "1992-07-13" }, { "id": 3, "firstName": "Steven3", "lastName": "Jobs", "idCard": "610702199009261457", "dateOfBirth": "1991-07-13" }, { "id": 4, "firstName": "Steven4", "lastName": "Jobs", "idCard": "430426198801075355", "dateOfBirth": "1994-07-13" }, { "id": 5, "firstName": "Steven5", "lastName": "Michael", "idCard": "420117199502232760", "dateOfBirth": "1998-07-13" }, { "id": 6, "firstName": "Steven6", "lastName": "Michael", "idCard": "130203199404122670", "dateOfBirth": "1998-07-13" }, { "id": 7, "firstName": "Steven7", "lastName": "Michael", "idCard": "430703197612014630", "dateOfBirth": "1998-07-13" }, { "id": 8, "firstName": "Steven8", "lastName": "Michael", "idCard": "350124197805280264", "dateOfBirth": "1998-07-13" }, { "id": 9, "firstName": "Steven9", "lastName": "Michael", "idCard": "500230197205314628", "dateOfBirth": "1998-08-19" } ]
新增一个user:
http://localhost:8080/saveUser/java/springboot/330987193709193205/1937-09-19
页面会输出新插入的user:
此时再findAll,会发现多了新插入的id为10的记录:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
[ { "id": 1, "firstName": "Steven1", "lastName": "Jobs1", "idCard": "630121199206081105", "dateOfBirth": "1998-07-13" }, { "id": 2, "firstName": "Steven2", "lastName": "Jobs2", "idCard": "510181199412105672", "dateOfBirth": "1992-07-13" }, { "id": 3, "firstName": "Steven3", "lastName": "Jobs", "idCard": "610702199009261457", "dateOfBirth": "1991-07-13" }, { "id": 4, "firstName": "Steven4", "lastName": "Jobs", "idCard": "430426198801075355", "dateOfBirth": "1994-07-13" }, { "id": 5, "firstName": "Steven5", "lastName": "Michael", "idCard": "420117199502232760", "dateOfBirth": "1998-07-13" }, { "id": 6, "firstName": "Steven6", "lastName": "Michael", "idCard": "130203199404122670", "dateOfBirth": "1998-07-13" }, { "id": 7, "firstName": "Steven7", "lastName": "Michael", "idCard": "430703197612014630", "dateOfBirth": "1998-07-13" }, { "id": 8, "firstName": "Steven8", "lastName": "Michael", "idCard": "350124197805280264", "dateOfBirth": "1998-07-13" }, { "id": 9, "firstName": "Steven9", "lastName": "Michael", "idCard": "500230197205314628", "dateOfBirth": "1998-08-19" }, { "id": 10, "firstName": "java", "lastName": "springboot", "idCard": "330987193709193205", "dateOfBirth": "1937-09-19" } ]
更新一个user:
将刚插入的id为10的用户的firstName修改成java666:
http://localhost:8080/updateUser/java666/330987193709193205
页面返回1,表示修改成功。
输入:http://localhost:8080/findByIdCard/330987193709193205
可以看到身份证为330987193709193205的firstName确实被修改了:
删除一个user:
输入:http://localhost:8080/deleteById/1
页面显示:
这样id为1的user就被删除了,再输入http://localhost:8080/findAll,id为1的user已不存在:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
[ { "id": 2, "firstName": "Steven2", "lastName": "Jobs2", "idCard": "510181199412105672", "dateOfBirth": "1992-07-13" }, { "id": 3, "firstName": "Steven3", "lastName": "Jobs", "idCard": "610702199009261457", "dateOfBirth": "1991-07-13" }, { "id": 4, "firstName": "Steven4", "lastName": "Jobs", "idCard": "430426198801075355", "dateOfBirth": "1994-07-13" }, { "id": 5, "firstName": "Steven5", "lastName": "Michael", "idCard": "420117199502232760", "dateOfBirth": "1998-07-13" }, { "id": 6, "firstName": "Steven6", "lastName": "Michael", "idCard": "130203199404122670", "dateOfBirth": "1998-07-13" }, { "id": 7, "firstName": "Steven7", "lastName": "Michael", "idCard": "430703197612014630", "dateOfBirth": "1998-07-13" }, { "id": 8, "firstName": "Steven8", "lastName": "Michael", "idCard": "350124197805280264", "dateOfBirth": "1998-07-13" }, { "id": 9, "firstName": "Steven9", "lastName": "Michael", "idCard": "500230197205314628", "dateOfBirth": "1998-08-19" }, { "id": 10, "firstName": "java666", "lastName": "springboot", "idCard": "330987193709193205", "dateOfBirth": "1937-09-19" } ]
分页查询:
输入:http://localhost:8080/findByLastNameWithPageable/Michale
页面显示:lastName为Michale的共有5条记录,page设置:每页2个,共5页
输出结果与程序一致:
附录:
注解说明:
@Entity: 指明了这是一个entity
@Table:指定生成的表名
@Id: 标记该entity的主键
@GeneratedValue: 提供主键的生成策略
@Component:声明为一个组件
@Transactional:声明为事务
@Autowired:自动注入
@Query:查询操作
@Modifying:修改操作
@PathVariable:将URL中的请求参数绑定到控制器的入参上
@Override:重写
@Param:声明属性
语句说明:
1、使用SpEL表达式
@Query("select u from User u where u.idCard = ?1")
User findByIdCard3(String idCard);
2、使用原生SQL(需添加nativeQuery=true)
@Query(value = "select * from user where ID_CARD = ?1", nativeQuery = true) User findByIdCard2(String idCard);
3、使用属性表达式(Property Expressions)
User findByIdCard(String idCard);
(注:上面的方法,JPA会转换成等价的查询语句:select * from User u where u.idCard = ?1)
官方文档上的JPA标准API:
Keyword | Sample | JPQL snippet |
---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4、使用命名参数(:参数名+@Param)
@Query("select u from User u where u.firstName = :firstName or u.lastName = :lastName") List<User> findByFirstNameOrLastName(@Param("firstName") String firstName, @Param("lastName") String lastName);
H2数据库控制台:
地址栏输入http://localhost:8080/h2-console/进入H2控制台
程序运行流程图(调用关系):
以上就是SpringBoot JPA增删改查的简单应用,当然你也可以将数据库换成mysql。
官方参考文档:https://docs.spring.io/spring-data/jpa/docs/current/reference/html/