文章目录
1、Swagger介绍
随着互联网技术的发展,现在的网站架构基本都由原来的后端渲染变成了前端渲染、前后端分离的形态,而且前端技术和后端技术在各自的道路上越走越远。
前端和后端的唯一联系变成了API接口。API文档变成了前后端开发人员联系的纽带,变得越来越重要。Swagger就是一款让后端开发人员更好的书写API文档的框架。
官方说法:Swagger是一个规范和完整的框架,用于生成、描述、调用和可视化 RESTful 风格的 Web 服务。总体目标是使客户端和文件系统作为服务器以同样的速度来更新。文件的方法,参数和模型紧密集成到服务器端的代码,允许API来始终保持同步。
Swagger的一个最大的优点是能实时同步api与文档。在项目开发过程中,发生过多次:修改代码但是没有更新文档,前端还是按照老旧的文档进行开发,在联调过程中才发现问题的情况(当然依据开闭原则,对接口的修改是不允许的,但是在项目不稳定阶段,这种情况很难避免)。
Swagger的作用:
1)接口文档在线自动生成
2)功能测试
2、引入Swagger框架
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger-ui -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
3、引入jackson框架
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.9.10</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.10</version>
</dependency>
4、配置Swagger
package com.cskfz.student.config;
import com.google.common.base.Predicates;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
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;
import java.util.stream.Stream;
import static java.util.stream.Collectors.toSet;
/**
* @Author: yangzc
* @Description:
* @Date: Created on 16:47 2019/11/23
* @Modified By:
*/
@Configuration
@EnableSwagger2
@ComponentScan(basePackages = {"com.cskfz.student.controller"})
public class SwaggerConfig{
@Bean
public Docket customDocket(){
Docket docket = new Docket(DocumentationType.SWAGGER_2);
return docket.apiInfo(apiInfo()).
pathMapping("/")
.select() // 选择那些路径和api会生成document
.apis(RequestHandlerSelectors.any())// 对所有api进行监控
//不显示错误的接口地址
.paths(Predicates.not(PathSelectors.regex("/error.*")))//错误路径不监控
.paths(PathSelectors.regex("/.*"))// 对根下所有路径进行监控
.build().protocols(Stream.of("http", "https").collect(toSet()));
}
private ApiInfo apiInfo(){
Contact contact = new Contact("yangzc","https://github.com/yangzc23/","876295854@qq.com");
return new ApiInfoBuilder().
title("学生管理API").
description("学生管理接口说明文档").
contact(contact).
version("1.0.0").
build();
}
}
5、添加Swagger资源文件的映射
package com.cskfz.student.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Author: yangzc
* @Description: 资源映射路径
* @Date: Created on 12:54 2019/11/19
* @Modified By:
*/
@Configuration
public class MyWebAppConfigurer implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/upload/**").addResourceLocations("file:D:/upload/");
registry.addResourceHandler("swagger-ui.html").
addResourceLocations("classpath:/META-INF/resources/");//swagger的html文件
registry.addResourceHandler("/webjars/**").
addResourceLocations("classpath:/META-INF/resources/webjars/");//swagger的js和css文件
}
}
6、Controller代码
package com.cskfz.student.controller;
import com.cskfz.student.controller.agent.annotation.ApiJsonObject;
import com.cskfz.student.controller.agent.annotation.ApiJsonProperty;
import com.cskfz.student.entity.Student;
import com.cskfz.student.pojo.ActionResult;
import com.cskfz.student.pojo.StudentVO;
import com.cskfz.student.utils.DBUtil;
import io.swagger.annotations.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
/**
* @Author: yangzc
* @Description:
* @Date: Created on 11:39 2019/11/19
* @Modified By:
*/
@Api(value = "student", description = "学生管理")
@Controller
@RequestMapping("/")
public class MyController {
@Autowired
private DBUtil dbUtil;
@Value("${upload.file.path}")
private String savePath;
/**
* 学生列表
* @param params
* @return
*/
@ApiOperation(value = "学生列表", notes = "根据指定的页码和行数返回学生列表")
@PostMapping(value = "/welcome", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ActionResult getStudents(@ApiJsonObject(name = "params", value = {
@ApiJsonProperty(key = "page", example = "1", description = "页码"),
@ApiJsonProperty(key = "rows", example = "5", description = "行数")
}) @RequestBody Map<String,String> params) {
//PrintWriter pw = null;
Connection conn = null;
PreparedStatement stmt = null;
//
Map<String,Object> data = new HashMap<String,Object>();
List<Student> list = new ArrayList<Student>();
ActionResult result = null;
int rows = Integer.parseInt(params.get("rows"));
int page = Integer.parseInt(params.get("page"));
int begin = (page-1)*rows;
try {
conn = dbUtil.getConnection();
stmt = conn.prepareStatement("SELECT COUNT(*) FROM STUDENT");
ResultSet rs = stmt.executeQuery();
rs.next();
data.put("total", rs.getInt(1));
stmt = conn.prepareStatement("SELECT * FROM STUDENT ORDER BY SNO LIMIT ?,?");
stmt.setInt(1, begin);
stmt.setInt(2, rows);
rs = stmt.executeQuery();
while(rs.next()) {
list.add(new Student(rs.getInt(1),rs.getString(2),rs.getString(3).equals("男"),rs.getDate(4),rs.getString(5)));
}
data.put("rows", list);
result = ActionResult.ok(data);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
/**
* 学生编辑
* @param sid
* @return
*/
@ApiOperation(value = "学生信息加载", notes = "根据学号获取该学生的信息")
@ApiImplicitParam(name = "sid", value = "学号", dataType = "int", paramType = "path", example = "1001")
@GetMapping(value = "/edit/{sid}", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ActionResult loadStudent(@PathVariable Integer sid){
Connection conn = null;
PreparedStatement stmt = null;
ActionResult result = null;
try {
conn = dbUtil.getConnection();
stmt = conn.prepareStatement("SELECT * FROM STUDENT WHERE SNO=?");
stmt.setInt(1, sid);
ResultSet rs = stmt.executeQuery();
if(rs.next()) {
result = ActionResult.ok(new Student(rs.getInt(1),rs.getString(2),rs.getString(3).equals("男"),rs.getDate(4),rs.getString(5)));
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
/**
* 学生保存
* @param stu
* @return
*/
@ApiOperation(value = "学生信息保存", notes = "将输入的学生信息保存到数据库")
@PostMapping(value = "/save", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ActionResult saveStudent(StudentVO stu){
Connection conn = null;
PreparedStatement stmt = null;
ActionResult result = null;
String sno = stu.getSid();
//
String sname = stu.getSname();
//
String gender = stu.getGender().equals("0")?"女":"男";
//
String birth = stu.getBirth();
//
String filePath = stu.getFilePath();
//
try {
conn = dbUtil.getConnection();
if(sno==null||sno.equals("")) {
stmt = conn.prepareStatement("INSERT INTO STUDENT(SNAME,GENDER,BIRTH,PHOTO_URL) VALUES(?,?,?,?)");
stmt.setString(1, sname);
stmt.setString(2, gender);
stmt.setString(3, birth);
stmt.setString(4, filePath);
}else {
stmt = conn.prepareStatement("UPDATE STUDENT SET SNAME=?,GENDER=?,BIRTH=?,PHOTO_URL=? WHERE SNO=?");
stmt.setString(1, sname);
stmt.setString(2, gender);
stmt.setString(3, birth);
stmt.setString(4, filePath);
stmt.setInt(5, Integer.parseInt(sno));
}
stmt.executeUpdate();
result = ActionResult.ok();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();//关闭数据库的连接
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
/**
* 学生删除
* @param sid
* @return
*/
@ApiOperation(value = "删除学生信息", notes = "根据学号删除该学生的信息")
@ApiImplicitParam(name = "sid", value = "学号", dataType = "int", paramType = "path", example = "1001")
@DeleteMapping(value = "/delete/{sid}", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ActionResult delStudent(@PathVariable Integer sid){
Connection conn = null;
PreparedStatement stmt = null;
ActionResult result = null;
try {
conn = dbUtil.getConnection();
stmt = conn.prepareStatement("DELETE FROM STUDENT WHERE SNO = ?");
stmt.setInt(1, sid);
stmt.executeUpdate();
result = ActionResult.ok();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
conn.close();//关闭数据库的连接
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return result;
}
/**
* 文件上传
* @param file
* @param req
* @return
*/
@ApiOperation(value = "头像上传", notes = "文件上传")
@ApiImplicitParam(name = "source", value = "图片", dataType = "__file", required = true, paramType = "form")
@PostMapping(value = "/upload/file", produces = MediaType.APPLICATION_JSON_VALUE)
@ResponseBody
public ActionResult uploadFile(@RequestParam("source") MultipartFile file, HttpServletRequest req) {
ActionResult result = null;
try {
// 截取不同类型的文件需要自行判断
String filename = file.getOriginalFilename();
if (!file.isEmpty()) {
String extName = filename.substring(filename.indexOf("."));// 取文件格式后缀名
String uuid = UUID.randomUUID().toString().replace("-", "");
// 新名称
String newName = uuid + extName;// 在这里用UUID来生成新的文件夹名字,这样就不会导致重名
file.transferTo(new File(savePath+"/"+newName));
result = ActionResult.ok("upload/"+newName);
}
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
}
7、访问学生管理的接口文档
8、使用swagger调用学生管理接口
9、github项目地址
https://github.com/yangzc23/yangzc
10、参考资料
[01] 关于通过Swagger查看接口浏览器跳出Unable to infer base url. This is common when using dynamic servlet registrat…
[02] How can I set a description and an example in Swagger with Swagger annotations?
[03] SpringBoot + Swagger + ReDoc 笔记
[04] 如何手动描述java@RequestBodyMap<String,String>的示例输入?
[05] SpringMVC-如何接收各种参数(普通参数,对象,JSON, URL)
[06] swagger常用注解说明
[07] swagger ui swagger2 文件上传参数 input file
[08] AJAX发送GET、POST、DELETE、PUT请求到服务器
[09] springboot2.x集成swagger
[10] @ApiImplicitParams dataType file __ file swagger升级的一些坑
[11] springfox + swagger2自定义JsonObject/Map参数文档
[12] Swagger2 关于Map参数在API文档中展示详细参数以及参数说明
[13] swagger生成接口文档和map类型参数解析
[14] Swagger2.9.2的NumberFormatException
[15] swagger2 Illegal DefaultValue for parameter type integer
[16] Swagger使用总结
[17] Idea修改编译器版本
[18] Springboot 集成Swagger2后 接受实体类对象传参的实现方式
[19] Swagger生成的接口需要权限验证的处理方法
[20] Swagger学习
[21] @requestMapping的produces和consumes属性
[22] 解决访问swaggerUI接口文档显示basic-error-controler问题
[23] SpringBoot 整合 oauth2(三)实现 token 认证
[24] springfox项目github地址
[25] swagger api一键导入postman
[26] 在spring Boot中使用swagger-bootstrap-ui
[27] swagger-ui升级swagger-bootstrap-ui界面好看到起飞
[28] swagger-bootstrap-ui 开发指南
微信扫一扫关注公众号
点击链接加入群聊
https://jq.qq.com/?_wv=1027&k=5eVEhfN
软件测试学习交流QQ群号:511619105