一.添加maven依賴包
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--引入資料庫包-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!--引入swagger包-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
<!--引入aop統一處理請求-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
</dependencies>
二.swaggerui配置檔案
package com.xxx.config;
import com.google.common.base.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* swaggerui配置檔案
*
* @author fuyang
* @date 2019/10/20
*/
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket api(){
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.pathMapping("/")
.select()
.apis(RequestHandlerSelectors.any())
.paths(Predicates.not(PathSelectors.regex("/error.*")))//不顯示swaggerui預設的接口位址
.paths(PathSelectors.regex("/.*"))
.build();
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder().title("swaggerui主标題名稱")
.contact(new Contact("聯系人名稱","","聯系人郵箱位址"))
.description("swaggerui說明")
.version("1.0.0")
.build();
}
}
三.springboot配置
1.環境配置
server:
port: 8086
tomcat:
uri-encoding: utf-8
servlet:
context-path: /luckymoney -->接口通路的預設路徑
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/具體連結的庫名
username: 資料庫主機名稱
password: 資料庫密碼
jpa:
hibernate:
ddl-auto: update -->資料庫做更新操作
show-sql: true -->日志輸出sql執行語句
2.啟動檔案配置
說明:啟動檔案需與包名在同一級
package com.config;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class LuckymoneyApplication {
public static void main(String[] args) {
SpringApplication.run(LuckymoneyApplication.class, args);
}
}
四.接口開發
1.實體類開發(新增一張資料表)
package com.iot.domain;
import io.swagger.annotations.ApiParam;
import javax.persistence.*;
import java.math.*;
/**
* 實體類開發
*
* @author fuyang
* @date 2019/10/20
*/
@Entity
public class Luckymoney {
//id為主鍵,自增
@Id
@GeneratedValue
private Integer id;
private BigDecimal money;
private String producer;
private String consumer;
public Luckymoney() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public BigDecimal getMoney() {
return money;
}
public void setMoney(BigDecimal money) {
this.money = money;
}
public String getProducer() {
return producer;
}
public void setProducer(String producer) {
this.producer = producer;
}
public String getConsumer() {
return consumer;
}
public void setConsumer(String consumer) {
this.consumer = consumer;
}
@Override
public String toString() {
return "Luckymoney{" +
"id=" + id +
", money=" + money +
", producer='" + producer + '\'' +
", consumer='" + consumer + '\'' +
'}';
}
}
2.自定義一個接口繼承JpaRepository,操作資料庫
在接口實作方法中,自動裝配該執行個體對象,然後調用jap下面的方法
建立資料:
repository.save(luckymoney)//傳入對象
更新資料:
repository.save(luckymoney)
查詢資料:
repository.findAll();
删除資料:
repository.deleteById(id);
package com.iot.repository;
import com.iot.domain.*;
import org.springframework.data.jpa.repository.JpaRepository;
/**自定義一個接口繼承JpaRepository接口,
* 第一個參數是要操作資料庫中的某一個表名,
* 第二個參數是主鍵的類型。
* 定義好後即可使用Jpa中的方法完成對資料庫的基本操作。
* @author luxiaojiu
* @date 2019/10/20
*/
public interface LuckymoneyRepository extends JpaRepository<Luckymoney,Integer> {
}
3.基于RESTful開發api
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbwxCdh1mcvZ2LcV2Zh1Wa9M3clN2byBXLzN3btg3P3pVdC5GTrpUbNVTQUp1aK1WT5VEVOVTWE9EewknT6tGRNRzZ61Ee4k3YsR2VZRHbyg1aGJjYzJEWkZHOXFWdVhUY6VzVZBHctxkeWJjWoFzVhRXUXlld4d0YxkTeMZTTINGMShUYvwlbj5yZtlmbkN3YuQnclZnbvN2Ztl2Lc9CX6MHc0RHaiojIsJye.jpg)
(1).get接口開發
/**
* 擷取查詢操作
* @return
*/
@GetMapping("/luckymoneys")
public List<Luckymoney> list(){
return repository.findAll();
}
(2).post接口開發
/**
* 建立操作
* @return
*/
@PostMapping("/createLuckymoney")
public Luckymoney createLuckymoney (@RequestParam("producer") String producer, @RequestParam("money") BigDecimal money){
Luckymoney luckymoney = new Luckymoney();
luckymoney.setProducer(producer);
luckymoney.setMoney(money);
return repository.save(luckymoney);
}
(3).put接口開發
/**
* 更新操作
* @param id
* @param consumer
* @return
*/
@PutMapping("/updateLuckymoney/{id}")
public Luckymoney updateLuckymoney(@PathVariable("id") Integer id,@RequestParam("consumer") String consumer){
Optional<Luckymoney> optional = repository.findById(id);
if (optional.isPresent()){
Luckymoney luckymoney = optional.get();
luckymoney.setConsumer(consumer);
return repository.save(luckymoney);
}
return null;
}
(4).delete接口開發
/**
* 根據id删除對應資料
* @param id
* @return
*/
@DeleteMapping("/deleteLuckymoney/{id}")
public String deleteLuckymoney(@PathVariable("id") Integer id){
repository.deleteById(id);
return Integer.toString(id);
}
五.接口文檔內建到Swagger UI
1.在接口開發類上方加入注解
@Api(tags = {"對應swagger ui組别名稱"})
@RestController
@Api(tags = {"紅包收發操作"})
public class LuckymoneyController {
}
2.在接口方法上方加入注解
@ApiOperation(value = "接口名稱",notes = "接口詳細說明")
@GetMapping("/selectLuckymoney/{id}")
@ApiOperation(value = "通過主鍵id查詢紅包",notes = "擷取指定紅包資訊")
public Luckymoney selectLuckymoney(@PathVariable("id") Integer id){
return repository.findById(id).orElse(null);
}
3.在接口請求參數前加入注解
@ApiParam(name = "請求參數名",value = "參數說明")
@GetMapping("/selectLuckymoney/{id}")
@ApiOperation(value = "通過主鍵id查詢紅包",notes = "擷取指定紅包資訊")
public Luckymoney selectLuckymoney(@ApiParam(name = "id",value = "主鍵ID")@PathVariable("id") Integer id){
return repository.findById(id).orElse(null);
}
4.運作swaggerUI,通路接口
(1).運作springboot啟動檔案
LuckymoneyApplication.java
(2).通路swaggerui連結
說明:端口号為springboot配置檔案中設定的端口号
http://localhost:8086/luckymoney/swagger-ui.html
六.SpringBoot中的事務處理
說明:一個流程中的步驟需同時成功或失敗,此時用事務實作;需要接口校驗的業務邏輯用事務實作
1.實作方式
@Service
public class LuckymoneyService {
@Autowired
private LuckymoneyRepository repository;
/**
* 資料庫事務,同時成功或失敗
* ex:扣庫存 > 建立訂單 需同時成功或失敗
*/
@Transactional
public void createTwoLuckymoney(){
Luckymoney luckymoney1 = new Luckymoney();
luckymoney1.setProducer("大兄弟");
luckymoney1.setMoney(new BigDecimal("520"));
repository.save(luckymoney1);
Luckymoney luckymoney2 = new Luckymoney();
luckymoney2.setProducer("小兄弟");
luckymoney2.setMoney(new BigDecimal("1314"));
repository.save(luckymoney2);
}
}
2.在controller層調用
/**
* 調用事務方法,同時建立兩個紅包
*/
@PostMapping("/createTwo")
public void createTwo(){
service.createTwoLuckymoney();
}
七.使用aop處理請求日志
package com.iot.aspect;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.*;
/**
* 使用aop統一處理請求及傳回日志
*
* @author fuyang
* @date 2019/10/28
*/
@Aspect
@Component
public class HttpAspect {
private final static Logger logger = LoggerFactory.getLogger(HttpAspect.class);
//監控LuckymoneyController類下的所有方法
@Pointcut("execution(public * com.iot.controller.LuckymoneyController.*(..))")
public void log(){
}
/**
* 輸出接口request資訊
* @param joinPoint
*/
@Before("log()")
public void doBefore(JoinPoint joinPoint){
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
//輸出url
logger.info("url={}",request.getRequestURL());
//輸出method
logger.info("method={}",request.getMethod());
//輸出請求ip
logger.info("ip={}",request.getRemoteAddr());
//輸出類方法
logger.info("class_method={}",joinPoint.getSignature().getDeclaringTypeName()+"."+joinPoint.getSignature().getName());
//輸出請求參數
logger.info("args={}",joinPoint.getArgs());
}
//方法調用結束後需要輸出的資訊
@After("log()")
public void doAfter(){
logger.info("接口調用結束!!!");
}
/**
* 輸出接口響應資訊,将傳回的對象進行轉換字元串處理
* @param object
*/
@AfterReturning(returning = "object",pointcut = "log()")
public void doAfterReturning(Object object){
logger.info("response={}",object.toString());
}
}
八.接口響應字段格式設定
(1).定義接口具體傳回的字段
package com.iot.domain;
/**
* 定義接口傳回的具體字段格式
*
* @author fuyang
* @date 2019/10/29
*/
public class Result<T>{
/**
* 錯誤碼
*/
private Integer code;
/**
* 提示資訊
*/
private String msg;
/**
* 接口傳回的具體内容,泛型
*/
private T data;
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
(2).為接口傳回的字段指派
調用Result類指派
package com.iot.utils;
import com.iot.domain.*;
/**
* 為接口傳回的字段指派
* 傳回Result.java對象
* @author fuyang
* @date 2019/10/29
*/
public class ResultUtil {
public static Result success(Object object){
Result result = new Result();
result.setCode(0);
result.setMsg("成功");
result.setData(object);
return result;
}
public static Result success(){
return success(null);
}
public static Result error(Integer code,String msg){
Result result = new Result();
result.setCode(code);
result.setMsg(msg);
return result;
}
}
九.異常處理
說明:對抛出的異常進行處理
(1).定義一個枚舉類,管理接口傳回的code和message,
調用方式:ResultEnum.PRODUCER_ERROR
備注:接口傳回的格式為
{
"code": 102,
"msg": "未查詢到結果",
"data": null
}
package com.iot.enums;
/**
* 為接口傳回的code和message定義枚舉
* 友善統一管理
* @author fuyang
* @date 2019/10/31
*/
public enum ResultEnum {
UNKNOW_ERROR(-1,"未知錯誤"),
SUCCESS(0,"成功"),
PRODUCER_ERROR(100,"發送人錯誤"),
AMOUNT_ERROR(101,"發送金額錯誤"),
PARAM_ERROR(102,"未查詢到結果");
private Integer code;
private String message;
public Integer getCode() {
return code;
}
public String getMessage() {
return message;
}
ResultEnum(Integer code, String message) {
this.code = code;
this.message = message;
}
}
(2).自定義異常類(解決抛出的異常按照規定的格式傳回)
package com.iot.exception;
import com.iot.enums.*;
/**
* 部分異常的情況不滿足Result.java定義的格式,需單獨處理
* 自定義異常類,需傳入code和message
* @author fuyang
* @date 2019/10/30
*/
public class LuckymoneyException extends RuntimeException{
private Integer code;
public LuckymoneyException(ResultEnum resultEnum) {
super(resultEnum.getMessage());
this.code = resultEnum.getCode();
}
public Integer getCode() {
return code;
}
public void setCode(Integer code) {
this.code = code;
}
}
(3).定義一個異常捕獲類(如果捕獲到的類是自定義的異常類,則傳回自定義的響應格式)
package com.iot.handle;
import com.iot.domain.*;
import com.iot.exception.*;
import com.iot.utils.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* 定義一個異常捕獲類
* 對捕獲到的類進行字段傳回值的處理
* @author fuyang
* @date 2019/10/30
*/
@ControllerAdvice
public class ExceptionHandle {
private final static Logger logger = LoggerFactory.getLogger(ExceptionHandle.class);
@ExceptionHandler(value = Exception.class)
@ResponseBody
public Result handle(Exception e){
LuckymoneyException luckymoneyException = (LuckymoneyException) e;
//如果捕獲到的異常類是LuckymoneyException抛出的則走下面判斷
if (e instanceof LuckymoneyException){
return ResultUtil.error(luckymoneyException.getCode(),luckymoneyException.getMessage());
}else {
logger.error("【系統異常】{}",e);
return ResultUtil.error(-1,"未知錯誤");
}
}
}
(4).在事務中調用自定義異常類LuckymoneyException,參數code/message直接讀取枚舉
/**
* 校驗紅包發送人
* @param id
* @throws Exception
*/
public void getMoney(Integer id) throws Exception{
Luckymoney luckymoney = repository.findById(id).get();
String producer = luckymoney.getProducer();
if (producer.equals("echo")){
throw new LuckymoneyException(ResultEnum.PRODUCER_ERROR);
}else if (producer.equals("luke")){
throw new LuckymoneyException(ResultEnum.AMOUNT_ERROR);
}
}
十.基于junit單元測試
(1).對service測試
選中service中待測試的方法名,右鍵go to ---> Test ---> create new test ---> 勾選待測試的方法 --- ok
package com.iot.service;
import com.iot.domain.*;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* 單元測試
* 基于事務中的校驗
* @author fuyang
* @date 2019/11/10
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class LuckymoneyServiceTest {
@Autowired
private LuckymoneyService luckymoneyService;
@Test
public void findOneTest(){
Luckymoney luckymoney = luckymoneyService.findOne(30);
Assert.assertEquals("echo",luckymoney.getProducer());
}
}
(2).對controller api測試
選中controller中待測試的方法名,右鍵go to ---> Test ---> create new test ---> 勾選待測試的方法 --- ok
package com.iot.controller;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class LuckymoneyControllerTest {
@Autowired
private MockMvc mvc;
//校驗傳回的狀态碼為200,内容為iot
@Test
public void list() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/luckymoneys"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().string("iot"));
}
}