首页 > 其他分享 >[Web] 接口文档工具: Swagger

[Web] 接口文档工具: Swagger

时间:2024-07-15 15:43:12浏览次数:9  
标签:Web Swagger return String 文档 org import swagger public

0 引言

1 springboot 整合 swagger2 ,并配置密码登录认证

依赖引入

  • spring-boot.version : 2.3.12.RELEASE
  • swagger.version : 1.5.14
  • springfox-swagger2.version : 2.8.0
<!-- swagger | start -->
<!-- springfox-swagger2 : 内部依赖/自动引入 swagger-annotations / swagger-models -->
<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger2</artifactId>
	<exclusions>
		<exclusion>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
		</exclusion>
	</exclusions>
	<version>${springfox-swagger2.version}</version>
</dependency>

<dependency>
	<groupId>io.springfox</groupId>
	<artifactId>springfox-swagger-ui</artifactId>
	<version>${springfox-swagger2.version}</version>
</dependency>

<dependency>
	<groupId>io.swagger</groupId>
	<artifactId>swagger-annotations</artifactId>
	<version>${swagger.version}</version>
</dependency>

<dependency>
	<groupId>io.swagger</groupId>
	<artifactId>swagger-models</artifactId>
	<version>${swagger.version}</version>
</dependency>
<!-- swagger | end -->


<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-web</artifactId>
	<version>${spring-boot.version}</version>
	<exclusions>
		<exclusion>
			<groupId>org.apache.logging.log4j</groupId>
			<artifactId>log4j-api</artifactId>
		</exclusion>
		<!-- 去掉默认日志配置logback -->
		<exclusion>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-logging</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<!-- 模板引擎 -->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-thymeleaf -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-thymeleaf</artifactId>
	<version>${spring-boot.version}</version>
</dependency>

配置文件: application.yml

# swagger-doc
swagger:
  # requestHander 的包路径
  package: cn.xxx.yyy.app
  title: project API
  description: project API
  version: 1.0
  # 登录认证的账户密码
  username: ${SWAGGER_USERNAME:admin}
  password: ${SWAGGER_PASSWORD:admin}
  contactAuthor: jack
  contactUrl: localhost:${server.port}/swagger-ui.html
  contactEmail: [email protected]

spring:
  resources:
    # 静态资源的路径
    static-locations: classpath:/static
  thymeleaf:
    cache: false
    prefix: classpath:/templates/
    encoding: UTF-8 #编码
    suffix: .html #模板后缀
    mode: HTML #模板

注:需配置静态路径的目录(spring.resources.static-locations)、模板引擎的策略(spring.thymeleaf)

启用 Swagger2

方式1:@EnableSwagger2 注解

  • @EnableSwagger2springfox提供的一个注解,代表swagger2相关技术开启。启用后,会自动扫描当前类所在包,及子包中所有类型的swagger相关注解,做swagger文档的定制
//@EnableFeignClients // [feign] Feign 客户端调用第三方接口,本工程暂不涉及
@EnableDiscoveryClient(autoRegister = true) // [nacos] 注册中心 | feign 整合 nacos 需要启用此注解(服务提供端 + Feign 客户端) | true: 开启服务自动注册功能,项目启动后能在 nacos 的web端界面看到服务的相关信息,且具备拉取服务信息的功能(前提是 nacos.discovery.enabled 不为 false)

@EnableSwagger2 // [swagger] 开启swagger2
@Api(tags = "yyyy app 启动模块") // [swagger] 作用范围: 模块类 | tags = "模块说明"

@MapperScan("cn.seres.bd.datasource.app") // [mybatis]
@ServletComponentScan(basePackages = "cn.xxx.yyy.app")// 扫描 Servlet 包,例如: ApplicationRequestListener
@SpringBootApplication // [spring-boot]
//@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
@RestController // // [spring-web(mvc / webflux)]
//@RequestMapping("/") // [spring-web(mvc / webflux)]
@ComponentScan(basePackages = {"cn.xxx.yyy"}) // [spring-context]
public class DataSourceApplication {
   ...
}

方式2:配置类 : Swagger2

import com.google.common.base.Function;
import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import springfox.documentation.RequestHandler;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Contact;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;

import java.util.ArrayList;
import java.util.List;
//@EnableSwagger2 此处,也可利用注解
@Configuration
public class Swagger2Configuration implements WebMvcConfigurer {
    private static final String splitor = ";";

    //可以获取application.yml 配置的参数
    @Autowired
    public Environment env;

    @Autowired
    private ApplicationContext applicationContext;

    @Bean
    public Docket api() {
        //添加 head 参数 start
        ParameterBuilder tokenPar = new ParameterBuilder();
        List<Parameter> params = new ArrayList<Parameter>();
        //这里配置 访问jwt令牌请求头,不需要的不加
        /**
         params.add(
         new ParameterBuilder()
         .name("authorization")
         .description("令牌")
         .modelRef(new ModelRef("string"))
         .parameterType("header")
         .required(false)
         .build()
         );
         **/

        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                //.apis(RequestHandlerSelectors.any())
                .apis(RequestHandlerSelectors.basePackage(env.getProperty("swagger.package")))
                //.apis(basePackage("com.tyzn.controller.api"  + splitor + "com.tyzn.controller.backApi"))
                .paths(PathSelectors.any())
                //.paths(Predicates.not(PathSelectors.regex("/error.*")))//过滤掉 error* 页面
                //.paths(Predicates.or(PathSelectors.regex("/error.*"), PathSelectors.regex("/admin/.*") ) ) //过滤掉 error* 页面或 /admin/ 路径的请求
                .build()
                .globalOperationParameters(params)
                .apiInfo(apiInfo());
    }

    private ApiInfo apiInfo() {
        ApiInfoBuilder ab = new ApiInfoBuilder();
        ab.title(env.getProperty("swagger.title"));
        ab.description(env.getProperty("swagger.description"));
        ab.version(env.getProperty("swagger.version"));
        ab.contact(new Contact(env.getProperty("swagger.contactAuthor"), env.getProperty("swagger.contactUrl"), env.getProperty("swagger.contactEmail")));
        //ab.contact(new Contact("Jack", "localhost:8080/swagger-ui.html", "[email protected]"));
        return ab.build();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/static/**")
                .addResourceLocations("classpath:/static/");
        registry.addResourceHandler("swagger-ui.html")
                .addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");
    }

    public static Predicate<RequestHandler> basePackage(final String basePackage) {
        return input -> declaringClass(input).transform(handlerPackage(basePackage)).or(true);
    }

    private static Function<Class<?>, Boolean> handlerPackage(final String basePackage) {
        return input -> {
            // 循环判断匹配
            for (String strPackage : basePackage.split(splitor)) {
                boolean isMatch = input.getPackage().getName().startsWith(strPackage);
                if (isMatch) {
                    return true;
                }
            }
            return false;
        };
    }

    private static Optional<? extends Class<?>> declaringClass(RequestHandler input) {
        return Optional.fromNullable(input.declaringClass());
    }
}

登录过滤器 : SwaggerFilter


import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @author 闲走天涯
 * @version V1.0
 * @Title: Swagger2
 * @Description: 登录过滤器
 * @date 2021-08-05
 */
@Component
public class SwaggerFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // TODO Auto-generated method stub
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;
        String requestURI = req.getRequestURI();
        //swagger-security
        if (requestURI.contains("swagger-ui")) {
            //获取 session
            HttpSession session = req.getSession();
            //判断 swagger 是否已经登录
            Object swaggerLogin = session.getAttribute("swaggerLogin");
            if (swaggerLogin == null || StringUtils.isEmpty(swaggerLogin.toString()) || !Boolean.parseBoolean(swaggerLogin.toString())) {
                String basePath = req.getScheme() + "://" + req.getServerName() + ":" + req.getServerPort() + req.getContextPath() + "/";
                String fullPath = basePath + "swagger/toLogin";
                //重定向登录页面
                res.sendRedirect(fullPath);
            } else {
                chain.doFilter(req, res);
            }
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void destroy() {
        // TODO Auto-generated method stub
    }
}

控制器 : SwaggerController

  • SwaggerController : swagger 登录控制层-登录接口

import cn.xxx.common.entity.SwaggerAccount;
import cn.xxx.model.dto.XResponse;
import com.alibaba.cloud.commons.lang.StringUtils;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletRequest;

@Controller // 应该用@RestController, 如果是 @Controller,会认为你返回的一个 modelandview 要解析,即会报错"TemplateInputException: Error resolving template 无法解析页面"
@RequestMapping(value = "/swagger")
@Slf4j
public class SwaggerController {

    @Value("${swagger.username}")
    private String swaggerUserName;

    @Value("${swagger.password}")
    private String swaggerPassword;

    @PostConstruct
    public void init(){
        log.info("swaggerUserName: {}", swaggerUserName);
        log.info("swaggerPassword: {}", swaggerPassword);
    }

    @GetMapping(value = {"toLogin", ""})
    public String toLogin(HttpServletRequest request) {
        Object swaggerLogin = request.getSession().getAttribute("swaggerLogin");
        if (swaggerLogin != null && StringUtils.isNotBlank(swaggerLogin.toString()) && Boolean.parseBoolean(swaggerLogin.toString())) {
            return "redirect:/swagger-ui.html";
        }
        return "swaggerLogin";
    }

    @PostMapping(value = "/login")
    @ResponseBody
    public ResponseEntity<XResponse> login(@RequestBody SwaggerAccount swaggerAccount, HttpServletRequest request) {
        log.info("swaggerAccount : {} , config.username : {}, config.password : {}", swaggerAccount, swaggerUserName, swaggerPassword);
        if (
            StringUtils.isNotBlank(swaggerAccount.getUsername()) && StringUtils.isNotBlank(swaggerAccount.getPassword())
            && swaggerUserName.equals(swaggerAccount.getUsername()) && swaggerPassword.equals(swaggerAccount.getPassword())
        ) {
            request.getSession().setAttribute("swaggerLogin", true);
            return ResponseEntity.ok( XResponse.success("ok") );
        }
        return ResponseEntity.ok( XResponse.failure("fail") );
    }
}
  • SwaggerAccount
import lombok.*;

@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class SwaggerAccount {
    private String username;

    private String password;
}
  • XResponse
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

@ApiModel(value = "公共响应对象", description = "公共响应对象") // [swagger] 作用范围: 模型类,如VO、BO
public class XResponse<T> {
    private static final long serialVersionUID = 1L;

    /**
     * 状态码
     */
    @ApiModelProperty(
            value = "响应状态",
            example = "true",
            hidden = false
    ) // [swagger] 作用范围: 类的方法、属性上 / hidden=true 可隐藏该属性 / value = "属性说明"
    private Boolean status;

    /**
     * 返回对象
     */
    @ApiModelProperty(value = "业务数据")
    private T data;

    /**
     * 错误码
     */
    @ApiModelProperty(value = "错误码")
    private String errorCode;

    /**
     * 错误信息
     */
    @ApiModelProperty(value = "错误信息", example = "error message")
    private String errorMsg;

    @ApiModelProperty(value = "traceId", example = "trace id")
    private String traceId;

    public XResponse() {

    }

    public XResponse(Boolean status, T data, String errorCode, String errorMsg) {
        this.status = status;
        this.data = data;
        this.errorCode = errorCode;
        this.errorMsg = errorMsg;
    }

    public static XResponse create(Boolean status, Object data, String errorCode,
                                        String errorMsg) {
        return new XResponse(status, data, errorCode, errorMsg);
    }

    public static XResponse success() {
        return create(true, null, null, null);
    }

    public static <T> XResponse success(T obj) {
        return create(true, obj, null, null);
    }

    public static XResponse failure() {
        return create(false, null, null, null);
    }

    public static XResponse failure(String errorCode) {
        return create(false, null, errorCode, null);
    }

    public static XResponse failure(String errorCode, String errorMsg) {
        return create(false, null, errorCode, errorMsg);
    }

    public Boolean getStatus() {
        return status;
    }

    public T getData() {
        return data;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public String getErrorMsg() {
        return errorMsg;
    }

    public void setStatus(Boolean status) {
        this.status = status;
    }

    public void setData(T data) {
        this.data = data;
    }

    public void setErrorCode(String errorCode) {
        this.errorCode = errorCode;
    }

    public void setErrorMsg(String errorMsg) {
        this.errorMsg = errorMsg;
    }

    public String getTraceId() {
        return traceId;
    }

    public void setTraceId(String traceId) {
        this.traceId = traceId;
    }

    @Override
    public String toString() {
        return "XResponse{" +
                "status=" + status +
                ", data=" + data +
                ", errorCode='" + errorCode + '\'' +
                ", errorMsg='" + errorMsg + '\'' +
                ", traceId='" + traceId + '\'' +
                '}';
    }
}

登录页面 : swagger-login.html

  • /resources/templates/swagger-login.html
<!DOCTYPE html>
<html lang="en">
<head>
    <!-- https://www.runoob.com/html/html5-intro.html -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Login</title>
    <style>
        .login {
            width: 100%;
            height: 600px;
            text-align: center;
            display: flex;
            justify-content: center;
            align-items: center;
            flex-flow: column;
        }

        .body > div {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-bottom: 10px;
        }

        .body > div > input {
            margin-left: 10px;
        }
    </style>
</head>
<body>
<div class="login">
    <h2 class="title">欢迎使用 SWAGGER </h2>
    <div class="body">
        <div>
            <span>账号:</span>
            <input type="text" id="username">
        </div>
        <div>
            <span>密码:</span>
            <input type="password" id="password">
        </div>
    </div>

    <button type="button" id="logBtn">登陆</button>

</div>

<!-- 对应文件在服务器的物理存储路径: /resources/static/js/jquery-3.7.1.js -->
<script src="../js/jquery-3.7.1.js"></script>
<!--<script src="https://code.jquery.com/jquery-3.7.1.js"></script>-->
<script>
    $('#logBtn').click(function () {
        let username = $("#username").val();
        let password = $("#username").val();
        if (username === '' && password === '') {
            alert('username and password must be not empty!');
            return false;
        }
        $.ajax({
            url: '/swagger/login',
            //data: { username: username, password: password },
            data : JSON.stringify({ username: username, password: password }),
            type: 'post',
            //contentType: 'application/x-www-form-urlencoded'
            contentType: 'application/json',
            //dataType: 'json',
            success: function (result) {
                if (result.status) {
                    location.href = '/swagger-ui.html';
                } else {
                    alert(result.errorCode + ':' + result.errorMsg);
                }
            }
            , error : function (result) {
                console.log("error")
            }
        });
    });
</script>
</body>
</html>

测试访问

X 参考文献

"控制台日志输出告警,页面按F12打开swagger控制台"/","/csrf"两个404接口" => 在 2.9.x 版本中有,暂时还没有找到好的解决方案,回退到 2.8.0 版本可以解决

标签:Web,Swagger,return,String,文档,org,import,swagger,public
From: https://www.cnblogs.com/johnnyzen/p/18303277

相关文章

  • Python Web应用的部署与维护
    PythonWeb应用的部署与维护是一个涉及多个环节和技术的复杂过程,涵盖了从项目准备、服务器配置、代码部署到后期监控与维护的全方位工作。以下是对这一过程的详细阐述。一、Web应用的部署1.项目准备在部署之前,首先需要确保PythonWeb项目已经开发完成,并且经过了充分的测......
  • 在webapi中创建一个jwt token
    1.第一步首先创建一个webapi项目2.安装nuget包: Microsoft.AspNetCore.Authentication.JwtBearer3.,然后再Program.cs文件中添加 4.然后运行起来 5.打开jwt.io网站,解密token 关于:iss,sub,exp,iat,nbf更新信息看下图:  ......
  • javaweb高校宿舍管理系统|寝室管理[包运行成功+永久免费答疑辅导
    项目功能简介:本项目含代码详细讲解视频,手把手带同学们敲代码从0到1完成项目详细教程学习地址:https://www.bilibili.com/video/BV1V7411M7Et《基于javaweb实现的高校宿舍管理系统》该项目含有源码、文档、答辩ppt、开题报告、代码详细讲解教程等资料、配套开发软件、软件安......
  • webrtc-streamer实时播放监控
    公司要做web端监控实时播放,经过调研,webrtc-streamer的方式对前后端项目侵入最少,且没有延迟卡钝的现象。一、准备工作一个摄像头,摄像头对应的rtsp流链接,一台电脑,一个vue项目。二、Webrtc-streamer安装及启动教程 1、下载安装包下载地址:https://github.com/m......
  • Web请求全过程剖析:从URL输入到页面呈现
    摘要在数字化时代,我们与互联网的交互日益频繁。本文将深入探讨从浏览器输入URL到页面完全呈现的整个Web请求过程,包括页面渲染的两种主要机制:服务器渲染和前端JS渲染。1.Web请求的起点:DNS查询用户在浏览器地址栏输入www.example.com。浏览器查询DNS,将域名转换为IP地址,例......
  • WPF中webview2鼠标移动窗体
    WPF里webview2会一直处于其他控件最上层,是个历史遗留问题。为了能在webview2里鼠标移动让窗体跟着移动位置代码如下:asyncTaskInitializeAsync(){AppLog.AddLog("InitializeAsync...........");try{CoreWebView2Envir......
  • Webpack 代码分割和懒加载技术
    在现代前端开发中,优化应用性能是一个至关重要的任务。Webpack作为一个强大的打包工具,为我们提供了代码分割和懒加载的功能,可以显著提升应用的加载速度和用户体验。本文将深入解析Webpack的代码分割和懒加载技术,帮助开发者更好地理解和应用这些技术。什么是代码分割?代码分割(Co......
  • 使用Java实现WebSocket通信
    使用Java实现WebSocket通信大家好,我是微赚淘客系统3.0的小编,是个冬天不穿秋裤,天冷也要风度的程序猿!今天我们来探讨如何使用Java实现WebSocket通信,WebSocket是一种在单个TCP连接上进行全双工通信的协议,非常适合实时数据传输。1.WebSocket简介WebSocket协议在Web开发中广泛应用,......
  • 搭建一个javaweb项目的准备流程
    搭建一个javaweb项目的准备流程以所学系统项目为例:1src\main\java\com\utils1.1tools:DruidTools.java​ 需要在lib中加入druid-xx-xx.jar包代码展示packagecom.utils;importcom.alibaba.druid.pool.DruidDataSourceFactory;importjavax.sql.DataSource;impor......
  • [附开题]flask框架Web民宿管理系统的设计与实现89x8t(源码+论文+python)
    本系统(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。系统程序文件列表开题报告内容研究背景:近年来,随着旅游业的蓬勃发展和消费者出行方式的多元化,民宿作为一种新兴的住宿选择,凭借其独特的居住体验、灵活的租赁方式和个性化的服务,受......