org.springframework.boot
spring-boot-starter-web
io.springfox
springfox-swagger2
2.9.2
io.springfox
springfox-swagger-ui
2.9.2
com.github.xiaoymin
swagger-bootstrap-ui
1.9.6
上面代码中的springfox-swagger-ui和swagger-bootstrap-ui是两套UI框架,两者可以同时使用,也可以只使用其中的一个。
第二步:编写Swagger配置类,代码如下:@Configuration @EnableSwagger2 //是否开启swagger,正式环境一般是需要关闭的(避免不必要的漏洞暴露!),可根据springboot的多环境配置进行设置 public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) //设置全局参数 .globalOperationParameters(globalParamBuilder()) //设置全局响应参数 .globalResponseMessage(RequestMethod.GET,responseBuilder()) .globalResponseMessage(RequestMethod.POST,responseBuilder()) .globalResponseMessage(RequestMethod.PUT,responseBuilder()) .globalResponseMessage(RequestMethod.DELETE,responseBuilder()) .select() // 自行修改为自己的包路径 .apis(RequestHandlerSelectors.basePackage(“com.hc.controller”)) .paths(PathSelectors.any()) //设置安全认证 .build() .securitySchemes(security()); } private ApiInfo apiInfo() { return new ApiInfoBuilder() .title(“题库系统API文档”) //页面标题 .description("基于SpringBoot和MyBatisPlus的题库管理系统API操作文档 版本1.0 ")//描述 //服务条款网址 .termsOfServiceUrl(“http://www.hcitshow.online/”) .version(“1.0”) //版本号 .contact(new Contact(“梁云亮”, “http://www.hcitshow.online/”, “hcitlife@hotmail.com”))//创建人 .build(); } // 构建全局参数列表 private List globalParamBuilder(){ List pars = new ArrayList(); pars.add(parameterBuilder(“token”,“令牌”,“string”,“header”,false).build()); return pars; } // 创建参数 private ParameterBuilder parameterBuilder(String name, String desc, String type , String parameterType, boolean required) { ParameterBuilder tokenPar = new ParameterBuilder(); tokenPar.name(name).description(desc).modelRef(new ModelRef(type)).parameterType(parameterType).required(required).build(); return tokenPar; } // 安全认证参数 private List security() { List list=new ArrayList(); list.add(new ApiKey(“token”, “token”, “header”)); return list; } // 创建全局响应值 private List responseBuilder() { List responseMessageList = new ArrayList(); responseMessageList.add(new ResponseMessageBuilder().code(200).message(“响应成功”).build()); responseMessageList.add(new ResponseMessageBuilder().code(500).message(“服务器内部错误”).build()); return responseMessageList; } } select()函数返回一个ApiSelectorBuilder实例,用来控制哪些接口暴露给Swagger来展现。本例采用指定扫描的包路径来定义,Swagger会扫描该包下所有Controller定义的API,并产生文档内容(除了被@ApiIgnore指定的请求) apiInfo()配置一些基本的信息。apis()指定扫描的包会生成文档。再通过api函数创建Docket的Bean之后,apiInfo()用来创建该Api的基本信息(这些基本信息会展现在文档页面中)。 说明: @EnableSwagger2开启swagger2; @Configuration注解表明它是一个配置类,等价于XML中配置beans; @Bean标注方法等价于XML中配置bean。
第三步:编写实体类:@ApiModel(value = “Dept”,description = “部门信息”) public class Dept { @ApiModelProperty(“部门编号”) private int deptno; @ApiModelProperty(“部门名称”) private String dname; @ApiModelProperty(“部门地址”) private String loc; //……getter/setter、toString()、全参和默认构造方法 }
第四步:数据库模拟类public class DeptTable { private static ArrayList depts = new ArrayList();
static {
depts.add(new Dept(10, "ACCOUNTING", "CHICAGO"));
depts.add(new Dept(20, "RESEARCH", "DALLAS"));
depts.add(new Dept(30, "SALES", "CHICAGO"));
depts.add(new Dept(40, "OPERATIONS", "BOSTON"));
}
public static boolean insert(Dept dept) {
boolean res = depts.add(dept);
return res;
}
public static boolean update(Dept dept) {
Integer deptno = dept.getDeptno();
boolean flag = false;
for (int i = 0; i < depts.size(); i++) {
Dept temp = depts.get(i);
if (temp.getDeptno().equals(deptno)) {
depts.set(i, dept);
flag = true;
}
}
return flag;
}
public static boolean delete(Integer deptno) {
boolean flag = false;
for (int i = 0; i < depts.size(); i++) {
Dept dept = depts.get(i);
if (dept.getDeptno().equals(deptno)) {
depts.remove(i);
flag = true;
}
}
return flag;
}
public static Dept selectById(Integer deptno) {
for (int i = 0; i < depts.size(); i++) {
Dept dept = depts.get(i);
if (dept.getDeptno().equals(deptno)) {
return dept;
}
}
return null;
}
public static List selectAll() {
return depts;
}
}
第四步:编写Controller框架@RestController @RequestMapping(value = “/dept”) @Api(value = “DeptController-部门接口模拟”,tags= “DeptController-部门接口模拟”) @ApiResponses({ @ApiResponse(code = 200, message = “OK”), @ApiResponse(code = 400, message = “客户端请求错误”), @ApiResponse(code = 404, message = “找不到路径”), @ApiResponse(code = 500, message = “编译异常”) }) public class DeptController {
} 部署项目 请求网址:http://localhost/is/swagger-ui.html
具体CRUD 添加Dept Controller类中添加如下代码: @PostMapping(value = “/v1/dept”) @ApiOperation(value = “添加部门信息”, notes = “”, httpMethod = “POST”) public List addDept(@RequestBody Dept dept) throws Exception { DeptTable.insert(dept); return DeptTable.selectAll(); } 运行项目,打开页面http://localhost:8080/swagger-ui.html,效果如下:
打开页面http://localhost:8080/doc.html,效果如下:
修改部门信息 Controller类中添加如下代码: @PutMapping(value = “/v1/{deptno}”) @ApiOperation(value = “修改部门信息”, notes = “”, httpMethod = “PUT”) @ApiImplicitParams({ @ApiImplicitParam(paramType = “path”, name = “deptno”, value = “部门ID”, required = true, dataType = “Integer”), @ApiImplicitParam(paramType=“body”,name = “dept”, value = “用户实体,传入更改后的数据”, required = true, dataType = “Dept”) }) public List updateDept1(@PathVariable(value = “deptno”, required = true) Integer deptno, @RequestBody Dept dept) { dept.setDeptno(deptno); DeptTable.update(dept); return DeptTable.selectAll(); } @PutMapping("/v1/updateDept") @ApiOperation(value = “修改部门地址”, notes = “根据部门编号修改部门地址”) @ApiImplicitParams({ @ApiImplicitParam(paramType = “query”, name = “deptno”, value = “部门ID”, required = true, dataType = “Integer”), @ApiImplicitParam(paramType = “query”, name = “dname”, value = “部门名称”, required = true, dataType = “String”), @ApiImplicitParam(paramType = “query”, name = “loc”, value = “部门地址”, required = true, dataType = “String”) }) public List updateDept2(@RequestParam(value = “deptno”) Integer deptno, @RequestParam(value = “dname”) String dname, @RequestParam(value = “loc”) String loc) { Dept dept = new Dept(deptno, dname, loc); DeptTable.update(dept); return DeptTable.selectAll(); } 解释:
- paramType会直接影响程序的运行期,如果paramType与方法参数获取使用的注解不一致,会直接影响到参数的接收。
- Conntroller中定义的方法必须在@RequestMapper中显示的指定RequestMethod类型,否则SawggerUi会默认为全类型皆可访问, API列表中会生成多条项目。
- 在后台采用对象接收参数时,Swagger自带的工具采用的是JSON传参,测试时需要在参数上加入@RequestBody,正常运行采用form或URL提交时候请删除。 效果:
查询单个 Controller类中添加如下代码: @GetMapping(value = “/v1/{deptno}”) @ApiOperation(value = “获取部门详细信息”, notes = “根据url的deptno来获取部门详细信息”, httpMethod = “GET”) @ApiImplicitParam(name = “deptno”, value = “部门ID”, required = true, dataType = “Integer”, paramType = “path”) public Dept getDeptByDeptno1(@PathVariable Integer deptno) { return DeptTable.selectById(deptno); } @GetMapping(value = “/v2/{deptno}”) @ApiOperation(value = “获取部门详细信息”, notes = “根据url的deptno来获取部门详细信息”, httpMethod = “GET”) public Dept getDeptByDeptno2(@PathVariable Integer deptno) { return DeptTable.selectById(deptno); } @GetMapping(value = “/v3/getDeptByDeptno”) @ApiOperation(value = “获取部门详细信息”, notes = “根据id获取部门详细信息”) @ApiImplicitParam(paramType = “query”, name = “deptno”, value = “部门ID”, required = true, dataType = “Integer”) public Dept getDeptByDeptno3(@RequestParam Integer deptno) { return DeptTable.selectById(deptno); } 效果:
查询列表 Controller类中添加如下代码: @GetMapping(value = “/v1/list”) @ApiOperation(value = “获取部门列表”, notes = “一次全部取,不分页”, httpMethod = “GET”) @ApiImplicitParams({ @ApiImplicitParam(paramType = “header”, name = “token”, value = “token”, required = true, dataType = “String”), @ApiImplicitParam(paramType = “query”, name = “pageNum”, value = “当前页数”, required = false, dataType = “String”), @ApiImplicitParam(paramType = “query”, name = “pageSize”, value = “每页记录数”, required = true, dataType = “String”), }) public List getDoctorList(@RequestParam(value = “pageNum”, required = false, defaultValue = “1”) Integer pageNum, @RequestParam(value = “pageSize”, required = false) Integer pageSize) throws RuntimeException { return DeptTable.selectAll(); } 效果:
测试效果:
删除部门 Controller类中添加如下代码: @DeleteMapping(value = “/v1/{deptno}”) @ApiOperation(value = “删除部门信息”, notes = “”) //不知道为什么此处写成path会报错 @ApiImplicitParam(paramType = “path”, name = “deptno”, value = “部门ID”, required = true, dataType = “int”) public List deleteDept(@PathVariable(value = “deptno”) Integer deptno) { DeptTable.delete(deptno); return DeptTable.selectAll(); } 效果:
忽略 @ApiIgnore //使用该注解忽略这个API @GetMapping(value = “/hi”) public String jsonTest() { return " hi you!"; }
在Security中的配置 如果我们的Spring Boot项目中集成了Spring Security,那么如果不做额外配置,Swagger2文档可能会被拦截,此时只需要在Spring Security的配置类中重写configure方法,添加如下过滤即可: @Override public void configure(WebSecurity web) throws Exception { web.ignoring() .antMatchers("/swagger-ui.html") .antMatchers("/v2/") .antMatchers("/swagger-resources/"); } 如此之后,Swagger2文件就不需要认证就能访问了。
问题:java.lang.NumberFormatException异常 项目启动之后,打开网页http://127.0.0.1:8080/swagger-ui.html#/ ,会发现控制台报错:
是数值类型转换异常,原因是输入了一个空字符串 ,而且是把String转换成Long类型数值的过程中发生异常。分析后知道我们刚刚定义的Dept类中,有一个Integer类型的属性deptno. @ApiModelProperty(“部门编号”) private int deptno; 而在DeptController中,我们没有给方法的参数deptno设置默认值。这样系统会自动把我们输入的String类型的id,转换成Integer类型的deptno,再保存成JSON数据。这个转换过程调用的就是Integer.parseInt(),注意要求的是非空字符串!由于我们没有给这个addDept()这个方法设置默认值,所以系统已启动,就自动尝试把空字符串转换成Integer类型数值,所以就报错了。所以,解决办法就很简单——给参数id设置任意一个默认值。如下: @ResponseBody // @PostMapping(value = “/add”) @RequestMapping(value = “/add”, method = RequestMethod.POST, consumes = MediaType.APPLICATION_JSON_VALUE) @ApiOperation(value = “添加部门信息”, notes = “”, httpMethod = “POST”) @ApiImplicitParam(name = “deptno”,value = “部门id”,defaultValue = “10”) public List addDept(@RequestBody Dept dept) throws Exception { deptList.add(dept); return deptList; } 设置完,再启动项目就不会报错了。 或者: 实体类中,Integer类型的属性加@ApiModelProperty时,必须要给example参数赋值,且值必须为数字类型。 @ApiModelProperty(value = “部门编号”,example = “10”) private Integer deptno; 大功告成!