前言
本篇文章主要介紹的是Springboot整合SpringDataJPA基於Restful風格實現增刪改查功能。
Spring Boot介紹
Spring Boot是由Pivotal團隊提供的全新框架,其設計目的是用來簡化新Spring應用的初始搭建以及開發過程。該框架使用了特定的方式來進行配置,從而使開發人員不再需要定義樣板化的配置。通過這種方式,我們不必像Spring MVC一樣寫大量的xml配置文件。
GitHub源碼鏈接位於文章底部。
總結來說,springboot是一個快速開發的框架,開箱即用,提供了各種默認配置來簡化項目配置,能夠集成第三方框架,這是通過maven依賴實現的,它簡化了xml,采用注解的形式,springboot還內嵌了tomcat容器,幫助開發者快速開發與部署。
添加依賴
新建一個maven項目,在pom文件中添加以下依賴
這個依賴引入了mvc框架,開啟了接口訪問的方式,它也正是以這種maven依賴的方式集成第三方框架的。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
</dependencies>
主程序啟動入口
在controller、service等同級目錄下,創建Application.java啟動類
SpringBootApplication注解=Configuration注解+EnableAutoConfiguration注解+ComponentScan注解。
Configuration注解負責初始化並啟動spring容器,這個類內部方法上使用Bean注解可以實現spring容器的注入。
EnableAutoConfiguration注解負責初始化配置,啟動springboot需要啟動的項,后邊詳細解釋此注解的作用。
ComponentScan注解負責掃包,springboot啟動程序后,能夠被外部訪問的只有被SpringBootApplication注解掃描到的包下的類。
SpringBootApplication注解啟動類默認掃包范圍是當前包下或者子包下所有的類。
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
控制層
@RestController
public class HelloWordController {
@GetMapping("/hello")
public String index() {
return "Hello World";
}
}
成功啟動主程序之后,瀏覽器輸入 http://localhost:8080/hello 便可以查看信息。(因為沒有配置端口,默認端口就是8080)
修改默認端口
在resource資源目錄下創建application.yml文件
server:
port: 8081
重新啟動后,瀏覽器輸入 http://localhost:8081/hello 可以查看信息。
application.yml文件內容的格式,以上文中的端口為例:
server+冒號+空格,然后換行,+一個tab鍵占位符+port+冒號+空格+8080,
意為server屬性下的port屬性的值為8080.
基於Restful風格實現增刪改查功能
一、Restful風格介紹
是一種網絡應用程序的設計風格和開發方式,REST指的是一組架構約束條件和原則。滿足這些約束條件和原則的應用程序或設計就是 RESTful。
每一個URI代表1種資源;
客戶端使用GET、POST、PUT、DELETE4個表示操作方式的動詞對服務端資源進行操作:GET用來獲取資源,POST用來新建資源(也可以用於更新資源),PUT用來更新資源,DELETE用來刪除資源;
二、開發准備
1、新建數據庫和表
在MySql中創建一個名為springboot的數據庫和名為一張t_user的表。
CREATE DATABASE `springboot`;
USE `springboot`;
DROP TABLE IF EXISTS `t_user`;
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'id',
`name` varchar(10) DEFAULT NULL COMMENT '姓名',
`age` int(2) DEFAULT NULL COMMENT '年齡',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;
2、修改pom文件,添加依賴
<!--父級依賴,它用來提供相關的 Maven 默認依賴。
使用它之后,常用的springboot包依賴可以省去version 標簽
配置UTF-8編碼,指定JDK8-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath ></relativePath>
</parent>
<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>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- MySQL 連接驅動依賴 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.39</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>
<build>
<resources>
<!--允許maven創建xml文件,否則xml要放在resources里-->
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
<filtering>true</filtering>
</resource>
</resources>
</build>
3.工程結構
com.lxg.springboot.controller - Controller 層
com.lxg.springboot.dao - 數據操作層 DAO
com.lxg.springboot.common - 存放公共類
com.lxg.springboot.entity - 實體類
com.lxg.springboot.service - 業務邏輯層
Application - 應用啟動類
application.yml - 應用配置文件,應用啟動會自動讀取配置
4.修改application.yml文件,添加數據庫連接屬性
server:
port: 8080
spring:
datasource:
username: root
password: root
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql://localhost:3306/springboot?useUnicode=true&characterEncoding=utf8
三、編碼
1.在common中創建公共類
1.1 封裝分頁結果PageResult
@Data
public class PageResult<T> {
/**
* 總記錄數
*/
private Long total;
/**
* 每頁數據
*/
private List<T> rows;
public PageResult(Long total, List<T> rows) {
this.total = total;
this.rows = rows;
}
}
1.2 封裝統一返回結果
@Data
public class Result {
/**
* 返回結構狀態
*/
private Boolean flag;
/**
* 返回狀態碼
*/
private Integer code;
/**
* 返回消息
*/
private String message;
/**
* 返回數據內容
*/
private Object data;
public Result(Boolean flag, Integer code, String message, Object data) {
this.flag = flag;
this.code = code;
this.message = message;
this.data = data;
}
public Result(Boolean flag, Integer code, String message) {
this.flag = flag;
this.code = code;
this.message = message;
}
public Result() {
}
}
1.3 返回狀態碼
public class StatusCode {
//成功
public static final Integer OK = 20000;
//失敗
public static final Integer ERROR = 20001;
//用戶名或密碼錯誤
public static final Integer USER_PASS_ERROR = 20002;
//權限不足
public static final Integer ACCESS_ERROR = 20003;
//遠程調用失敗
public static final Integer REMOTE_ERROR = 20004;
//重復操作
public static final Integer REPEATE_ERROR = 20005;
}
2.在entity中新建實體類
@Data
@Entity
@Table(name="t_user")
public class User implements Serializable {
/** 編號 */
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private String id;
/** 姓名 */
private String name;
/** 年齡 */
private Integer age;
}
注解:Data:安裝lombok插件再使用該注解可省略getter/setter、無參構造等方法,具體使用見文章https://www.lxgblog.com/article/1572329460
Entity:對實體注釋,聲明實體。
Table:與數據庫表綁定。
Id:聲明Id。
GeneratedValue(strategy = GenerationType.IDENTITY):數據庫主鍵自增。
3.在dao中新建UserDao
UserDao需要繼承JpaRepository<實體類,實體類ID類型>, JpaSpecificationExecutor<實體類>,
JpaRepository<>泛型的第二個參數與id有關,如findById(id)的id類型
public interface UserDao extends JpaRepository<U實體類ID類型ser,String>, JpaSpecificationExecutor<User> {
//這里的數字指的是第幾個參數
@Modifying
@Query("update User u set u.age =?2 where u.id =?1")
void update(String id, Integer age);
}
4.service層新建UserService
@Service
public class UserService {
@Autowired
private UserDao userDao;
/**
* 新增或修改,無id為新增,有id為修改
* @param user
*/
// @Transactional
public void saveUser(User user) {
userDao.save(user);
/**
* 這里的save方法會更新所有字段,如果只傳了age屬性進行更新,
* name屬性就會修改為null,避免這個問題需要使用下面的原生Sql
* 並且加上方法上的@Transactional注解
* userDao.update(user.getId(),user.getAge());
*/
}
/**
* 根據id刪除
*
* @param id
*/
public void deleteUser(String id) {
userDao.deleteById(id);
}
/**
* 查詢所有
*/
public List<User> findAll() {
return userDao.findAll();
}
/**
* 根據id查詢
*
* @param id
*/
public User findUserById(String id) {
return userDao.findById(id).get();
}
/**
* 條件查詢+age排序
* @param searchMap
*/
public List<User> findSearch(Map searchMap) {
Specification<User> specification = createSpecification(searchMap);
Sort sort = new Sort(Sort.Direction.ASC, "age");
return userDao.findAll(specification,sort);
}
/**
* 條件+分頁+age排序
* @param searchMap
* @param page
* @param size
*/
public Page<User> findSearch(Map searchMap, int page, int size) {
Specification<User> specification = createSpecification(searchMap);
Sort sort = new Sort(Sort.Direction.ASC, "age");
PageRequest pageRequest = PageRequest.of(page - 1, size,sort);
return userDao.findAll(specification, pageRequest);
}
/**
* 創建查詢條件
*/
private Specification<User> createSpecification(Map searchMap) {
return new Specification<User>() {
@Override
public Predicate toPredicate(Root<User> root, CriteriaQuery<?> criteriaQuery,
CriteriaBuilder criteriaBuilder) {
List<Predicate> preList = new ArrayList<Predicate>();
if (searchMap.get("name") != null && !(searchMap.get("name")).equals("")) {
preList.add(
criteriaBuilder.like(root.get("name").as(String.class), "%" + searchMap.get("name") + "%"));
}
if (searchMap.get("age") != null && !(searchMap.get("age")).equals("")) {
preList.add(criteriaBuilder.equal(root.get("age").as(Integer.class), searchMap.get("age")));
}
Predicate[] preArray = new Predicate[preList.size()];
return criteriaBuilder.and(preList.toArray(preArray));
}
};
}
}
5.controller層
@RestController
@RequestMapping(value = "/user")
public class UserController {
@Autowired
private UserService userService;
/**
* 新增
* @param user
*/
@RequestMapping(method = RequestMethod.POST)
public Result addUser(@RequestBody User user) {
userService.saveUser(user);
return new Result(true, StatusCode.OK,"新增成功");
}
/**
* 修改
* @param user
*/
@RequestMapping(method = RequestMethod.PUT)
public Result updateUser(@RequestBody User user) {
if (user.getId() == null || user.getId().equals("")) {
return new Result(false, StatusCode.ERROR,"無id,更新失敗");
}
userService.saveUser(user);
return new Result(true, StatusCode.OK,"更新成功");
}
/**
* 根據id刪除
* @param id
* @return
*/
@RequestMapping(value = "/{id}", method = RequestMethod.DELETE)
public Result delete(@PathVariable String id) {
userService.deleteUser(id);
return new Result(true, StatusCode.OK,"刪除成功");
}
/**
* 查詢所有
*/
@RequestMapping(method = RequestMethod.GET)
public List<User> findAllUser() {
return userService.findAll();
}
/**
* 根據id查詢
* @param id
*/
@RequestMapping(value = "/{id}", method = RequestMethod.GET)
public Result findByUserId(@PathVariable String id) {
return new Result(true, StatusCode.OK,"查詢成功",userService.findUserById(id));
}
/**
* 條件查詢
*/
@RequestMapping(value="/search",method = RequestMethod.POST)
public Result findSearch(@RequestBody Map searchMap){
return new Result(true,StatusCode.OK,"查詢成功 ",userService.findSearch(searchMap));
}
/**
* 條件+分頁
* @param searchMap
* @param page
* @param size
*/
@RequestMapping(value = "/search/{page}/{size}",method = RequestMethod.POST)
public Result findSearch(@RequestBody Map searchMap,@PathVariable int page,@PathVariable int size){
Page<User> pageBean = userService.findSearch(searchMap, page, size);
return new Result(true,StatusCode.OK,"查詢成功",new PageResult<>(pageBean.getTotalElements(),pageBean.getContent()) );
}
}
@PathVariable注解的參數與@RequestMapping中value中的{}內參數一致。
四、測試
啟動Application 之后,使用postman工具進行接口的測試。postman的使用教程查看另一偏博文。
1.新增
2.根據id屬性刪除,再次查詢所有,會發現少了一條
3.根據id屬性修改,再次查詢所有,會發現已經改變。
4.查詢所有
5.根據id屬性查詢
6.條件+age排序查詢
6.條件+age排序+分頁查詢
經過上面的例子可以發現,增刪改查的url都是同一個,即localhost:8080/user, 如果有一些簡單的條件,則放到它的后面作為條件。作為區別,使用了不同的請求方式,如Post,Get,Put,Delete等。
本文GitHub源碼:https://github.com/lixianguo5097/springboot/tree/master/springboot-jpa
CSDN:https://blog.csdn.net/qq_27682773
簡書:https://www.jianshu.com/u/e99381e6886e
博客園:https://www.cnblogs.com/lixianguo
個人博客:https://www.lxgblog.com