程序员社区

SpringBoot整合Swagger,不用手撕接口文档啦

> Hello,欢迎来到程序员社区。 今天聊一聊 SpringBoot整合Swagger,不用手撕接口文档啦,希望对大家有所帮助。

Java面试手册PDF下载:[点击下载最全Java面试手册](http://117.78.51.75/219-2)

编程电子书汇总

写在前面

Swagger 是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。Swagger 让部署管理和使用功能强大的API从未如此简单,非常好用哦。不过这里要提醒一下的是,项目发布生产环境的时候,记得关闭swagger,以防泄漏项目接口文档,被攻击。如果觉得写得挺好,请给点个关注和点个赞哦,嘿嘿嘿

准备

首先第一步要做的当然是创建一个只有web场景的新项目,然后引入swagger的依赖,这里的swagger-ui提供了一个非常好看的可视化UI,帮助我们整理Controller的API,从而生成API文档。

dependency>
    groupId>io.springfox/groupId>
    artifactId>springfox-swagger2/artifactId>
    version>2.9.2/version>
/dependency>
dependency>
    groupId>io.springfox/groupId>
    artifactId>springfox-swagger-ui/artifactId>
    version>2.9.2/version>
/dependency>

配置

我们导入了swagger的依赖之后,当然是需要对swagger进行相关的配置,我们在Config包下创建一个SwaggerConfig配置类,用它来对swagger进行相关的配置,配置类的具体内容如下。当然,你还可对对固定接口进行过滤,不过我这里就不演示那么复杂了,就举个简单的例子。

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;

@Configuration
@EnableSwagger2
public class SwaggerConfig {
    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.dbc.ubiquity.Controller"))
                .paths(PathSelectors.any())
                .build();
    }


    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Ubiquity系统")
                .description("Ubiquity系统 API 1.0.0")
                .termsOfServiceUrl("填一个你的借口文档的地址,或者其他地址都可以")
                .version("1.0")
                .contact(new Contact("DengBoCong", "个人网站地址", "你的邮箱"))
                .build();
    }
}

经过这2步配置后,我们启动服务后,访问:http://localhost:8080/swagger-ui.html就完成了集成。在上面的basePackage("com.dbc.ubiquity.Controller"),我们配置了Swagger会默认把所有Controller中的RequestMapping方法都生成API出来。

常用注解

  • @Api:修饰整个类,描述Controller的作用

  • @ApiOperation:描述一个类的一个方法,或者说一个接口

  • @ApiParam:单个参数描述

  • @ApiModel:用对象来接收参数

  • @ApiProperty:用对象接收参数时,描述对象的一个字段

  • @ApiResponse:HTTP响应其中1个描述

  • @ApiResponses:HTTP响应整体描述

  • @ApiIgnore:使用该注解忽略这个API

  • @ApiClass

  • @ApiError

  • @ApiErrors

  • @ApiParamImplicit

  • @ApiParamsImplicit

写Controller测试

我们知道上面的一些注解的含义之后呢,我们现在可以来写Controller来测试一下,不过这里要说明一下的是,我们没有集成数据库,所以我这里使用模拟数据,Spring已经内含了模拟数据类,即MockMvc,首先我们先写两个实体类(这个实体类当然不能使用@Entity 来注释啦),具体内容如下:

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;

import java.util.Date;

public class Message {
    private Long id;
    @ApiModelProperty(value = "消息体")
    private String text;
    @ApiModelProperty(value = "消息总结")
    private String summary;
    private Date createDate;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }

    public String getSummary() {
        return summary;
    }

    public void setSummary(String summary) {
        this.summary = summa编程电子书汇总ry;
    }

    public Date getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

    @Override
    public String toString() {
        return "Message{" +
                "id=" + id +
                ", text='" + text + ''' +
                ", summary='" + summary + ''' +
                ", createDate=" + createDate +
                '}';
    }
}

public class User {
    private Long id;
    private String name;
    private int age;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

然后是Repository类,具体内容如下

import java.util.List;

public interface MessageRepository {
    ListMessage> findAll();
    Message save(Message message);
    Message update(Message message);
    Message updateText(Message message);
    Message findMessage(Long idJava面试手册);
    void deleteMessage(Long id);
}
@Service("messageRepository")
public class InMemoryMessageRepository implements MessageRepository {
    private static AtomicLong counter = new AtomicLong();
    private final ConcurrentMapLong, Message> messages = new ConcurrentHashMap>();

    @Override
    public ListMessage> findAll() {
        ListMessage> messages = new ArrayList>(this.messages.values());
        return messages;
    }

    @Override
    public Message save(Message message) {
        Long id = message.getId();
        if (id == null){
            id = counter.incrementAndGet();
            message.setId(id);
        }
        this.messages.put(id, message);
        return message;
    }

    @Override
    public Message update(Message message) {
        this.messages.put(message.getId(), message);
        return message;
    }

    @Override
    public Message updateText(Message message) {
        Message msg = this.messages.get(message.getId());
        msg.setText(message.getText());
        this.messages.put(msg.getId(), msg);
        return msg;
    }

    @Override
    public Message findMessage(Long id) {
        return this.messages.get(id);
    }

    @Override
    public void deleteMessage(Long id) {
        this.messages.remove(id);
    }
}

然后我们编写一个对各个实体类进行相应格式的基础类,具体内容如下

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

/*
 * 通用相应对象
 * */
@ApiModel(description = "响应对象")
public class BaseResultT> {
    private static final int SUCCESS_CODE = 0;
    private static final String SUCCESS_MESSAGE = "成功";

    @ApiModelProperty(value = "响应码", name = "code", required = true, example = "" + SUCCESS_CODE)
    private int code;

    @ApiModelProperty(value = "响应消息", name = "msg", required = true, example = SUCCESS_MESSAGE)
    private String msg;

    @ApiModelProperty(value = "响应数据", name = "data")
    private T data;

    private BaseResult(int code, String msg, T data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    private BaseResult() {
        this(SUCCESS_CODE, SUCCESS_MESSAGE);
    }

    private BaseResult(int code, String msg) {
        this(code, msg, null);
    }

    private BaseResult(T data) {
        this(SUCCESS_CODE, SUCCESS_MESSAGE, data);
    }

    public static T> BaseResultT> success() {
        return new BaseResult>();
    }

    public static T> BaseResultT> successWithData(T data) {
        return new BaseResult>(data);
    }

    public static T> BaseResultT> failWithCodeAndMsg(int code, String msg) {
        return new BaseResult>(code, msg, null);
    }

    public static T> BaseResultT> buildWithParam(ResponseParam param) {
        return new BaseResult>(param.getCode(), param.getMsg(), null);
    }

    public int getCode() {
        return code;
    }

    public void setCode(int 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;
    }

    public static class ResponseParam {
        private int code;
        private String msg;

        private ResponseParam(int code, String msg) {
            this.code = code;
            this.msg = msg;
        }

        public static ResponseParam buildParam(int code, String msg) {
            return new ResponseParam(code, msg);
        }

        public void setCode(int code) {
            this.code = code;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            thiJava面试手册s.msg = msg;
        }

        public int getCode() {
            return code;
        }
    }
}

到这里,我们所有的工作包括配置和逻辑都已经完成了,接下来就是测试我们编写的代码是否会生效了,测试类的具体内容如下:

import org.aspectj.lang.annotation.Before;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.context.WebApplicationContext;

import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
public class MessageControllerTest {

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

//    @Before(value = "saveMessage()")
    public void setup() {
        this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
        saveMessages();
    }

    @Test
    public void saveMessage() throws Exception {
        setup();
        final MultiValueMapString, String> params = new LinkedMultiValueMap>();
        params.add("text", "text");
        params.add("summary", "summary");
        String mvcResult=  mockMvc.perform(MockMvcRequestBuilders.post("/message")
                .params(params)).andReturn().getResponse().getContentAsString();
        System.out.println("Result === "+mvcResult);
    }

    @Test
    public void getAllMessages() throws Exception {
        String mvcResult= mockMvc.perform(MockMvcRequestBuilders.get("/messages"))
                .andReturn().getResponse().getContentAsString();
        System.out.println("Result === "+mvcResult);
    }

    @Test
    public void getMessage() throws Exception {
        String mvcResult= mockMvc.perform(MockMvcRequestBuilders.get("/message/6"))
                .andReturn().getResponse().getContentAsString();
        System.out.println("Result === "+mvcResult);
    }

    @Test
    public void modifyMessage() throws Exception {
        final MultiValueMapString, String> params = new LinkedMultiValueMap>();
        params.add("id", "6");
        params.add("text", "text");
        params.add("summary", "summary");
        String mvcResult= mockMvc.perform(MockMvcRequestBuilders.put("/message").params(params))
                .andReturn().getResponse().getContentAsString();
        System.out.println("Result === "+mvcResult);
    }

    @Test
    public void patchMessage() throws Exception {
        final MultiValueMapString, String> params = new LinkedMultiValueMap>();
        params.add("id", "6");
        params.add("text", "text");
        String mvcResult= mockMvc.perform(MockMvcRequestBuilders.patch("/message/text").params(params))
                .andReturn().getResponse().getContentAsString();
        System.out.println("Result === "+mvcResult);
    }

    @Test
    public void deleteMessage() throws Exception {
        mockMvc.perform(MockMvcRequestBuilders.delete("/message/6"))
                .andReturn();
        String mvcResult= mockMvc.perform(MockMvcRequestBuilders.get("/messages"))
                .andReturn().getResponse().getContentAsString();
        System.out.println("Result === "+mvcResult);
    }

    private v编程电子书汇总oid  saveMessages()  {
        for (int i=1;i10;i++){
            final MultiValueMapString, String> params = new LinkedMultiValueMap>();
            params.add("id",""+i);
            params.add("text", "text"+i);
            params.add("summary", "summary"+i);
            try {
                MvcResult mvcResult=  mockMvc.perform(MockMvcRequestBuilders.post("/message")
                        .params(params)).andReturn();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

}

接下来我们访问http://localhost:8080/swagger-ui.html
SpringBoot整合Swagger,不用手撕接口文档啦插图

最后

Swagger2默认将所有的Controller中的RequestMapping方法都会暴露,然而在实际开发中,我们并不一定需要把所有API都提现在文档中查看,这种情况下,使用注解@ApiIgnore来解决,如果应用在Controller范围上,则当前Controller中的所有方法都会被忽略,如果应用在方法上,则对应用的方法忽略暴露API。注解@ApiOperation和@ApiParam可以理解为API说明,多动手尝试就很容易理解了。如果我们不使用这样注解进行说明,Swagger2也是有默认值的,没什么可说的试试就知道了。

> 时间不一定能证明很多东西,但是一定能看透很多东西。坚信自己的选择,不动摇,使劲跑,明天会更好。

赞(0) 打赏
未经允许不得转载:IDEA激活码 » SpringBoot整合Swagger,不用手撕接口文档啦

一个分享Java & Python知识的社区