SpringBoot接口开发并集成SwaggerUI

一.添加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

(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"));
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值