SpringBoot集成Swagger2+MybatisPlus逆向工程生成Swagger2注解

背景

swagger2介绍

swagger官网https://swagger.io/
官方介绍

Simplify API development for users, teams, and enterprises with the Swagger open source and professional toolset

借助Swagger开源和专业工具集,为用户,团队和企业简化API开发

swagger2加分项

没有swagger

swagger最大的作用其实就是生成接口API文档,早在之前没有使用swagger的时候,一般公司的接口API文档都是word的形式去书写,把接口的Api,RequestMethod,params,Result一类的写在表格里。
如果需要调整接口

  • 要么接口修改内容了,但是接口文档没做修改导致后续接口文档作为项目参考的话,对后续维护的开发人员们造成困扰
  • 要么接口内容修改,修改了接口文档,前后台联调的时候就会出现同一个文件一直传输比较麻烦。

有swagger

  • 实时同步api与文档:swagger可以在线自动生成接口文档,后台修改接口的话,接口文档随着项目的启动及时更新。
  • 在线测试:wasgger支持在线测试接口,甚至后台可以完全抛弃postman的使用,前台也可以输入数据,测试接口的可通行。
  • 多团队API方案:如果是以项目团队以项目线出发的话,swagger可以创建多个Docket以适用不同的项目线。
  • 无需过多冗余的word文档:可以解决上边提到的更新的文档来回传输的冗余文档问题。

swagger2扣分项

就个人在学习和使用的过程中,感觉缺点无非就是,在一个比较庞大的项目中如果要引进swagger,那,把所有的Controller、model、params,都加上注解,会是一个比较大的工程。
缺点本人感觉只有一个那就是,除了写注解繁琐一点以外,没什么其他缺点,不过这点缺点来说对于以上提出的有点简直是忽略不计

swagger2注意事项

我们的项目接口肯定是对内不可对外的,由此可知,我们的本地环境可以设置swagger页面地址可访问,生产环境则一定不可以访问这个非常重要。

搭建

搭建SpringBoot项目

此篇不会可以看我的其他文章使用Maven及Spring Initializer快速创建Spring Boot项目

引入依赖

要想使用swagger需要引入以下两个依赖
如果不使用这个可以去下载其他版本(https://mvnrepository.com/)

<!-- 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>
			<!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
			<dependency>
				<groupId>io.springfox</groupId>
				<artifactId>springfox-swagger2</artifactId>
				<version>2.9.2</version>
			</dependency>

后续补充:在使用过程中发现,使用这个依赖启动swagger的html页面经常报错

AbstractSerializableParameter : Illegal DefaultValue null for parameter type integer

原因是:这是由于实体类使用@ApiModelProperty时,example属性没有赋值导致的,在AbstractSerializableParameter的getExample方法中会将数值属性的example的转换数值类返回,example的默认值是"",因此当example没有赋值时,会出现上面的异常

解决方案pom中应该使用这样的dependency

            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-annotations</artifactId>
                <version>1.5.21</version>
            </dependency>
            <dependency>
                <groupId>io.swagger</groupId>
                <artifactId>swagger-models</artifactId>
                <version>1.5.21</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>
            <!-- https://mvnrepository.com/artifact/io.springfox/springfox-swagger2 -->
            <dependency>
                <groupId>io.springfox</groupId>
                <artifactId>springfox-swagger2</artifactId>
                <version>2.9.2</version>
            </dependency>

YML文件

其实swagger是不需要配置yml文件的,我添加的yml文件是为了解决上边提到的swagge2r注意事项
比较简单只有两行
简单理解,本地使用true 线上使用false
原因在下边

swagger:
  enable: true

创建文件

其中有提到以上yml文件中加入true和false的原因

package com.xiansheng.swaggerdemo.config;
/**
 * @author luck_sheng
 * @date 2021/1/26 14:33
 * @Version 1.0
 * @description Swagger Configuration description
 */
@Configuration
@EnableSwagger2
public class SwaggerConfig {

    @Value("${swagger.enable}")
    private Boolean enable;
    //生成环境yml文件可以指定为 false
    //生产环境时不可显示swagger接口文档,接口对外不可开放(***重点***)

    @Bean
    public Docket docketA() {
        //团队A
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).groupName("A");
    }

    @Bean
    public Docket docketB() {
        //团队B
        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo()).groupName("B");
    }

    @Bean
    public Docket docket(Environment environment) {
        //是否在生产环境展示swagger
        //方案一
        //此方法可以解决项目处于测试环境时,项目要显示swagger,生产环境时不显示swagger
        //设置要显示swagger的环境
        Profiles profiles = Profiles.of("dev", "test");
        //判断当前是否处于该环境
        //通过apiInfo(apiInfo()).enable()接收此参数判断是否要显示
        boolean b = environment.acceptsProfiles(profiles);
        System.out.println(b);
        //方案二
        //在yml文件中加入
        //swagger:
        //  enable: true
        //或者不加,项目则http://localhost:8080/swagger-ui.html访问不到
        //swagger:
        //  enable:
        //Configuration类中使用@Value取到值,通过apiInfo(apiInfo()).enable()接收此参数判断是否要显示
        System.out.println(enable);

        return new Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo())//docket实例关联apiInfo

                .enable(enable)//配置是否启用swagger,true为启用,false为禁用,禁用则浏览器无法访问swagger-ui.html
                .groupName("Test")//配置分组,想要配置几个分组就配置几个docket
                .select()
                .apis(RequestHandlerSelectors
//                        .any()//扫描所有,项目中所有的接口都能被扫描到
//                        .none()//不扫描接口
//                        .withClassAnnotation(Controller.class)//通过类上的注解扫描,扫描类上的接口
//                        .withMethodAnnotation(GetMapping.class)//通过方法上的注解扫描,扫描方法上的接口
                                .basePackage("com.xiansheng.swaggerdemo.controller")//根据包路径扫描接口
                )
                //过滤
//                .paths(PathSelectors
//                        .ant("/test")//配置如何通过path过滤,这里扫描/test开头的接口
                        .any()//任何请求都扫描过滤
                        .regex()//通过正则表达式控制过滤
//                )
                .build()//工厂模式
                ;
    }

    //配置文档信息
    private ApiInfo apiInfo() {
        Contact contact = new Contact("", "", "");
        return new ApiInfo(
                "测试API文档",//标题
                "XXXX项目的API接口文档",//描述
                "1.0",//版本
                "urn:tos",//组织链接
                contact,//联系人信息
                "Apache 2.0",//许可
                "http://www.apache.org/licenses/LICENSE-2.0",//许可链接
                new ArrayList()//扩展
        );
    }

}

访问失败原因

如果显示以下页面
在这里插入图片描述

token

关于token的问题网上的解决方案就比较多了,我也是照搬过来的代码,所以就不附上解决方案, 因为我还遇到了另外一个比较麻烦的问题,目前这个问题在网上还搜索不到类似的文章和解决方案,等我找到问题的解决方案再做补充
20210906补充
之前遇到的问题就是我们所用到的access_token为url跟的并不是header跟的,关于url的痛点是其他帖子上面没有找到相关的解决方案,基本全部都是url上面的token
后续根据通过文章了解到swagger的参数

@ApiImplicitParams:用在请求的方法上,表示一组参数说明
@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)–> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType=“Integer”
defaultValue:参数的默认值

由此得知想要使用加入参数为url跟的token需要将 paramType的参数设置为query
附上我现在的全局的token是这样加的

      private List<ApiKey> securitySchemes() {
        List<ApiKey> apiKeyList = new ArrayList<>();
        apiKeyList.add(new ApiKey("access_token", "access_token", "query"));
        return apiKeyList;
    }

    private List<SecurityContext> securityContexts() {
        List<SecurityContext> securityContexts = new ArrayList<>();
        securityContexts.add(
                SecurityContext.builder()
                        .securityReferences(defaultAuth())
                        .forPaths(PathSelectors.regex("^(?!auth).*$"))
                        .build());
        return securityContexts;
    }

    private List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        List<SecurityReference> securityReferences = new ArrayList<>();
        securityReferences.add(new SecurityReference("access_token", authorizationScopes));
        return securityReferences;

则new ApiKey中 的query(大部分文章为header)则完美实现token在url上的全局验证,亲测有效

访问失败解决方案

服务对url的拦截解决方案:

@EnableWebMvc
@Slf4j
public class ResponseHandler {
    private static final List<String> EXCLUD_PATH = Lists.newArrayList(
            "/v2/api-docs",
            "/swagger-resources",
            "/swagger-resources/configuration/security",
            "/swagger-resources/configuration/ui"
    );

    @RestControllerAdvice
    static class CommonResultResponseAdvice implements ResponseBodyAdvice<Object> {

        @Override
        public boolean supports(MethodParameter methodParameter, Class<? extends HttpMessageConverter<?>> aClass) {
            if (EXCLUD_METHODS.contains(methodParameter.getMethod().getName())) {
                return false;
            }
            return true;
        }

        @Override
        public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
            String requestPath = serverHttpRequest.getURI().getPath();
            log.info("requestPath:{}", requestPath);
            if (EXCLUD_PATH.contains(requestPath)) {
                return o;
            }
        }

    }

}

spring security对url的拦截解决方案:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs", "/swagger-resources/**",
                "/swagger-resources", "/swagger-resources/configuration/security", "/swagger-resources/configuration/security",
                "/swagger-ui.html", "/css/**", "/js/**", "/images/**", "/webjars/**", "**/favicon.ico", "/index");
    }
}

swagger常用注解

注解description
@Api应用在请求的控制器类上边表示该类的说明
@ApiOperation应用在请求的方法上边,说明该方法的说明
@ApiParam应用在请求的参数前边,说明该参数的定义
@ApiImplicitParams应用在请求的方法上边 ,包含一组参数{@ApiImplicitParam}
@ApiImplicitParam应用在请求的方法上边,ApiImplicitParams内,表示参数的定义
@ApiModel应用在实体类上边,表示该类的说明
@ApiModelProperty应用在实体类的属性上边,表示该属性的说明

swagger常用注解的常用参数

注解参数
@Api@Api(tags=“Card(证件)”)
@ApiOperation@ApiOperation(value=“获取指定用户证件列表”)
@ApiParam@ApiParam(name = “id”,value = “主键”,required = true) Integer id
@ApiImplicitParams@ApiImplicitParams({})
@ApiImplicitParam@ApiImplicitParam(name = “regId”,value = “用户id”)
@ApiModel@ApiModel(description = “证件信息”)
@ApiModelProperty@ApiModelProperty(“证件类型”)
在这里插入图片描述

MybatisPlus逆向工程生成Swagger2注解

之前一直使用的都是myabtis的generator逆向生成code的Controller,Service,Mapper,Model部分,后来,后来学习了Mybatis Plus,并且该项技术从学习到使用项目已经维持了大概五个月的时间,已经到了稳定的状态,所以写下这边文章记录一下

官方文档

先讲MP的官方文档拿过来。
Mybtis-Plus官方地址
首先打开官网展示如下,有如下一句话:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑。
就我个人使用的话,感觉Mybtis-plus确实是在Mybaits的基础之上只做增加不做修改。
在这里插入图片描述
在这里插入图片描述

MP特性

无侵入:只做增强不做改变,引入它不会对现有工程产生影响,如丝般顺滑
损耗小:启动即会自动注入基本 CURD,性能基本无损耗,直接面向对象操作
强大的 CRUD 操作:内置通用 Mapper、通用 Service,仅仅通过少量配置即可实现单表大部分 CRUD 操作,更有强大的条件构造器,满足各类使用需求
支持 Lambda 形式调用:通过 Lambda 表达式,方便的编写各类查询条件,无需再担心字段写错
支持主键自动生成:支持多达 4 种主键策略(内含分布式唯一 ID 生成器 - Sequence),可自由配置,完美解决主键问题
支持 ActiveRecord 模式:支持 ActiveRecord 形式调用,实体类只需继承 Model 类即可进行强大的 CRUD 操作
支持自定义全局通用操作:支持全局通用方法注入( Write once, use anywhere )
内置代码生成器:采用代码或者 Maven 插件可快速生成 Mapper 、 Model 、 Service 、 Controller 层代码,支持模板引擎,更有超多自定义配置等您来使用
内置分页插件:基于 MyBatis 物理分页,开发者无需关心具体操作,配置好插件之后,写分页等同于普通 List 查询
分页插件支持多种数据库:支持 MySQL、MariaDB、Oracle、DB2、H2、HSQL、SQLite、Postgre、SQLServer 等多种数据库
内置性能分析插件:可输出 Sql 语句以及其执行时间,建议开发测试时启用该功能,能快速揪出慢查询
内置全局拦截插件:提供全表 delete 、 update 操作智能分析阻断,也可自定义拦截规则,预防误操

搭建

依赖

		<dependency>
       	 <groupId>com.baomidou</groupId>
       	 <artifactId>mybatis-plus-boot-starter</artifactId>
      	  <version>Latest Version</version>
  	  </dependency>
    	<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!-- mybatis plus 代码生成器依赖 -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-generator</artifactId>
            <version>3.1.0</version>
        </dependency>
        <!-- 代码生成器模板 -->
        <dependency>
            <groupId>org.freemarker</groupId>
            <artifactId>freemarker</artifactId>
   		</dependency>
   		
   		<dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-dts</artifactId>
            <version>3.3.1</version>
        </dependency>

yml配置只需要简单配置数据库连接即可

自动生成代码

package com.beta.condingmybatisplus.util;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

/**
 * @author DC
 * @date 2021/03/30
 * @description mybatis-pus 代码生成器
 */
@Component
public class CodeGenerator {

    public static String scanner(String tip) {
        Scanner scanner = new Scanner(System.in);
        StringBuilder help = new StringBuilder();
        help.append("请输入" + tip + ":");
        System.out.println(help.toString());
        if (scanner.hasNext()) {
            String ipt = scanner.next();
            if (StringUtils.isNotEmpty(ipt)) {
                return ipt;
            }
        }
        throw new MybatisPlusException("请输入正确的" + tip + "!");
    }

    public static void main(String[] args) {
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        String projectPath = System.getProperty("user.dir");
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setActiveRecord(false)
                .setOutputDir(projectPath + ConfigDataSourceConstant.JAVA_LOCATION)//文件生成保存位置
                .setAuthor("DC")//作者
                .setOpen(false)默认true ,是否打开输出目录
                .setServiceName("%sService")
                .setDateType(DateType.ONLY_DATE)// 时间策略 默认TIME_PACK
                .setServiceImplName("%sServiceImpl")
                .setSwagger2(true)//启用swagger2
                .setMapperName("%sMapper")
                .setXmlName("%sMapper")
                .setFileOverride(true)
                .setActiveRecord(true)
                .setEnableCache(false)// 默认false,是否开启二级缓存
                .setBaseResultMap(true)
                .setBaseColumnList(false);
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(ConfigDataSourceConstant.DATA_URL)
                .setDriverName(ConfigDataSourceConstant.DRIVER_NAME)
                .setUsername(ConfigDataSourceConstant.USER_NAME)
                .setPassword(ConfigDataSourceConstant.PASS_WORD);
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        //pc.setModuleName(scanner("模块名"));
        pc.setParent(ConfigDataSourceConstant.PACKAGE_NAME)
                .setEntity(ConfigDataSourceConstant.ENTITY_NAME)
                .setService("service")
                .setServiceImpl("service.impl");
        mpg.setPackageInfo(pc);

        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            @Override
            public void initMap() {
                // to do nothing
            }
        };

        // 如果模板引擎是 freemarker
        String templatePath = "/templates/mapper.xml.ftl";

        // 自定义输出配置
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义配置会被优先输出
        focList.add(new FileOutConfig(templatePath) {
            @Override
            public String outputFile(TableInfo tableInfo) {
                // 自定义输出文件名 , 如果你 Entity 设置了前后缀、此处注意 xml 的名称会跟着发生变化!!
                return projectPath + ConfigDataSourceConstant.MAPPER_LOCATION +
                        "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);

        // 配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);
        mpg.setTemplate(templateConfig);

        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        strategy.setNaming(NamingStrategy.underline_to_camel)
                .setColumnNaming(NamingStrategy.underline_to_camel)
                .setEntityLombokModel(true)
                .setRestControllerStyle(true)
                .setInclude(scanner("表名,多个英文逗号分割").split(","))
                .setControllerMappingHyphenStyle(true)
                .setTablePrefix(pc.getModuleName() + "_");
        mpg.setStrategy(strategy);
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        mpg.execute();
    }
}

配置参数类

package com.beta.condingmybatisplus.util;

import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author 
 * @description 数据源配置
 */
@Component
@Data
public class ConfigDataSourceConstant {
    /**
     * 数据库来源
     */
    public static String DATA_URL = "XXXX";
    public static String USER_NAME = "XXXX";
    public static String PASS_WORD = "XXXX";
    public static String DRIVER_NAME = "com.microsoft.sqlserver.jdbc.SQLServerDriver";
    /**
     * java文件所在位置
     */
    public static String JAVA_LOCATION = "/conding-mybatisplus/src/main/java/";
    /**
     * mapper 文件所在位置
     */
    public static String MAPPER_LOCATION = "/conding-mybatisplus/src/main/resources/xml/";
    /**
     * 生成项目包的名字
     */
    public static String PACKAGE_NAME = "com.newclass";
    /**
     * 实体名字
     */
    public static String ENTITY_NAME = "entity";

}

其中 在自动生成的类中,
.setSwagger2(true)//启用swagger2
这句话便是启动swagger注解的关键

完结 biutifor 撒花

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值