一、简介
spring-boot作为当前最为流行的Java web开发脚手架,越来越多的开发者选择用其来构建企业级的RESTFul API接口。这些接口不但会服务于传统的web端(b/s),也会服务于移动端。在实际开发过程中,这些接口还要提供给开发测试进行相关的白盒测试,那么势必存在如何在多人协作中共享和及时更新API开发接口文档的问题。
假如你已经对传统的wiki文档共享方式所带来的弊端深恶痛绝,那么尝试一下Swagger2 方式,一定会让你有不一样的开发体验。
使用 Swagger 集成文档具有以下几个优势:
- 功能丰富 :支持多种注解,自动生成接口文档界面,支持在界面测试API接口功能;
- 及时更新 :开发过程中花一点写注释的时间,就可以及时的更新API文档,省心省力;
- 整合简单 :通过添加pom依赖和简单配置,内嵌于应用中就可同时发布API接口文档界面,不需要部署独立服务。
二、案例
1、pom引包
<!--添加Swagger依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.7.0</version>
</dependency>
<!--添加Swagger-UI依赖 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.7.0</version>
</dependency>
<!-- 引入swagger-bootstrap-ui依赖包-->
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>swagger-bootstrap-ui</artifactId>
<version>1.8.7</version>
</dependency>
2、添加配置类
package com.zhouzy.ssm.config;
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.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import com.github.xiaoymin.swaggerbootstrapui.annotations.EnableSwaggerBootstrapUI;
@Configuration
@EnableSwagger2
@EnableSwaggerBootstrapUI // 开启SwaggerBootstrapUI
public class SwaggerConfig {
@Bean
public Docket createRestApi(){
return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.any())
.paths(PathSelectors.any()).build();
}
private ApiInfo apiInfo(){
return new ApiInfoBuilder()
.title("Kitty API Doc")
.description("This is a restful api document of Kitty.")
.version("1.0")
.build();
}
}
3、接口
1)接口组
接口有时候应该是分组的,而且大部分都是在一个controller中的,比如用户管理相关的接口应该都在UserController中,那么不同的业务的时候,应该定义/划分不同的接口组。接口组可以使用@Api
来划分。
比如:
/* 类注解 */
@Api(tags = "首页管理")
@Controller
public class IndexController {
}
2)接口
我们可以使用@ApiOperation
来描述接口,比如:
/**
* 首页
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "首页", notes = "跳转到用户列表页面")
@RequestMapping("/")
public String index() {
return "user/userList";
}
常用配置项:
- value:可以当作是接口的简称
- notes:接口的描述
- tags:可以额外定义接口组,比如这个接口外层已经有
@Api(tags = "用户管理")
,将接口划分到了“用户管理”中,但你可以额外的使用tags,例如tags = "角色管理"
让角色管理中也有这个接口文档。
3)参数
此时我们需要使用@ApiModel
来标注实体类,然后在接口中定义入参为实体类即可:
- @ApiModel:用来标类
- 常用配置项:
- value:实体类简称
- description:实体类说明
- 常用配置项:
- @ApiModelProperty:用来描述类的字段的意义。
- 常用配置项:
- value:字段说明
- example:设置请求示例(Example Value)的默认值,如果不配置,当字段为string的时候,此时请求示例中默认值为"".
- name:用新的字段名来替代旧的字段名。
- allowableValues:限制值得范围,例如
{1,2,3}
代表只能取这三个值;[1,5]
代表取1到5的值;(1,5)
代表1到5的值,不包括1和5;还可以使用infinity或-infinity来无限值,比如[1, infinity]
代表最小值为1,最大值无穷大。 - required:标记字段是否必填,默认是false,
- hidden:用来隐藏字段,默认是false,如果要隐藏需要使用true,因为字段默认都会显示,就算没有
@ApiModelProperty
。
- 常用配置项:
比如:
package com.zhouzy.ssm.model;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import java.io.Serializable;
import java.util.Date;
/**
* @description 用户信息表
* @author zhouzhiyao
* @date 2021-08-03
*/
@ApiModel(value="用户信息",description="用户信息")
public class UserInfo implements Serializable {
private static final long serialVersionUID = 1L;
/**
* id
*/
@ApiModelProperty(value = "用户ID",required = false,example = "1",hidden=true)
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
/**
* 姓名
*/
@ApiModelProperty(value = "姓名",required = true,example = "张三")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* 年龄
*/
@ApiModelProperty(value = "年龄",required = true,example = "23")
private Integer age;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
/**
* 性别:0:男 1:女
*/
@ApiModelProperty(value = "性别",required = true,example = "0")
private Integer sex;
public Integer getSex() {
return sex;
}
public void setSex(Integer sex) {
this.sex = sex;
}
/**
* 地址
*/
@ApiModelProperty(value = "地址",required = true,example = "上海浦东")
private String address;
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
/**
* 手机号
*/
@ApiModelProperty(value = "手机号",required = true,example = "13349668342")
private String mobile;
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
/**
* 创建时间
*/
private Date createTime;
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
/**
* 更新时间
*/
private Date updateTime;
public Date getUpdateTime() {
return updateTime;
}
public void setUpdateTime(Date updateTime) {
this.updateTime = updateTime;
}
public UserInfo() {}
}
4) 新增一个控制层接口类
package com.zhouzy.ssm.controller;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.annotation.Resource;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.alibaba.fastjson.JSONObject;
import com.zhouzy.ssm.model.DataGrid;
import com.zhouzy.ssm.model.PageInfo;
import com.zhouzy.ssm.model.UserInfo;
import com.zhouzy.ssm.service.UserInfoService;
/* 类注解 */
@Api(tags = "用户管理")
@Controller
@RequestMapping("/user")
public class UserInfoController {
@Resource
private UserInfoService userInfoService;
/**
* 新增
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "新增用户", notes = "新增用户")
@PostMapping("/insert")
@ResponseBody
public void insert(@RequestBody UserInfo userInfo){
userInfoService.innerTest(userInfo);
}
/**
* 刪除
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "删除用户", notes = "删除用户")
@PostMapping("/delete")
public void delete(int id){
userInfoService.delete(id);
}
/**
* 更新
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "更新用户", notes = "更新用户")
@PostMapping("/update")
public void update(UserInfo userInfo){
userInfoService.update(userInfo);
}
/**
* 查询 根据主键 id 查询
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "根据ID查看用户", notes = "用户详情")
@GetMapping("/load")
public Object load(int id){
return userInfoService.load(id);
}
/**
* 查询 分页查询
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "跳转用户列表", notes = "跳转用户列表")
@GetMapping("/list")
public String pageList() {
return "user/userList";
}
/**
* 查询 分页查询
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "分页查询", notes = "分页查询用户列表")
@SuppressWarnings("unchecked")
@GetMapping("/listData")
@ResponseBody
public String listData(PageInfo page) {
int pageNum = page.getPage();
int size = page.getLimit();
Map<String,Object> map = userInfoService.pageList((pageNum-1)*size, size);
List<UserInfo> data = (List<UserInfo>)map.get("data");
int count = (Integer)map.get("count");
DataGrid<UserInfo> grid = new DataGrid<UserInfo>(data,count,0,null);
return JSONObject.toJSONString(grid);
}
/**
* 新增
* @author zhouzhiyao
* @date 2021/08/03
**/
@ApiOperation(value = "批量插入", notes = "批量插入")
@PostMapping("/insertBatch")
@ResponseBody
public void insertBatch(){
List<UserInfo> users = new ArrayList<UserInfo>();
UserInfo u1 = new UserInfo();
UserInfo u2 = new UserInfo();
u1.setName("张三");
u1.setAddress("上海");
u1.setAge(24);
u1.setMobile("13347882343");
u1.setSex(0);
u2.setName("李四");
u2.setAddress("北京");
u2.setAge(34);
u2.setMobile("13347882345");
u2.setSex(1);
users.add(u1);
users.add(u2);
userInfoService.insertBatch(users);
}
}
4、加载资源文件
//通过重写配置方法覆盖
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/mapper/**").addResourceLocations("classpath:/mapper/");//mapper.xml
registry.addResourceHandler("/**")
.addResourceLocations("classpath:/static/")
.addResourceLocations("classpath:/templates/")
.addResourceLocations("classpath:/META-INF/resources/"); //swagger2页面;
super.addResourceHandlers(registry);
}
.addResourceLocations("classpath:/META-INF/resources/"); //swagger2页面;
这个要加上否则页面出不来,报404错误!
5、启动
package com.zhouzy.ssm;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
@MapperScan("com.zhouzy.ssm.mapper") //扫描的mapper
@SpringBootApplication
@EnableWebMvc
@EnableAspectJAutoProxy(exposeProxy=true)
public class Webapplication {
public static void main(String[] args) {
SpringApplication.run(Webapplication.class, args);
}
}
三、测试