springboot集成swagger2

1、swagger简介

  Swagger是一款RESTful接口的文档在线自动生成、功能测试功能框架。一个规范和完整的框架,用于生成、描述、调用和可视化RESTful风格的Web服务,加上swagger-ui,可以有很好的呈现。

  当我们在后台的接口修改了后,swagger可以实现自动的更新,而不需要人为的维护这个接口进行测试。

       knife4j是一款对swagger功能增强的插件,优化展示页面及接口调试功能,具体介绍参见-----Knife4j官方介绍  

       例如:这是引入knife4j的效果

       

2:基于前面的知识点

  本知识点在springboot使用基于Mybatis注解方式实现的CRUD的基础上进行的。

3、springboot与swagger的集成:

  第一步:(单独集成swagger2)jar包的引入:

  <!-- swagger -->
  <dependency>
     <groupId>io.springfox</groupId>
     <artifactId>springfox-boot-starter</artifactId>
  </dependency>

如果集成knife4j,则引入这个依赖 

<dependency>
      <groupId>com.github.xiaoymin</groupId>
      <artifactId>knife4j-spring-boot-starter</artifactId>
      <version>2.0.5</version>
</dependency>

 

第二步:swagger的配置启动类编写:

         要使用swagger要进行一些配置,这个在界面的图上是可以显示的:类似于说明书:在这个类中我们会使用注解来进行启动 swagger:

  

具体配置如下:

单独配置 swagger 如下配置   没有权限校验的

package cn.xdf.springboot;
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.service.Contact;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import  springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
//@EnableKnife4j  这个注解释集成knife4j才加的
public class Swagger2 {

     @Value("${swagger.enable}")
     private boolean swagger;        

     // swagger2的配置文件,这里可以配置swagger2的一些基本的内容,比如扫描的包等等
     @Bean
     public Docket createRestApi() {
          return new Docket(DocumentationType.SWAGGER_2)
                   .apiInfo(apiInfo())
                   .select()
                   // 为当前包路径
                  .apis(RequestHandlerSelectors.basePackage("cn.xdf.springboot.controller"))
                   .paths(PathSelectors.any())
                   .build();
     }
     // 构建 api文档的详细信息函数,注意这里的注解引用的是哪个
     private ApiInfo apiInfo() {
          return new ApiInfoBuilder()
                   // 页面标题
                   .title("Spring Boot 测试使用 Swagger2 构建RESTful API")
                   // 创建人信息
                   .contact(new Contact("MrZhang",  "https://www.cnblogs.com/zs-notes/category/1258467.html",  "1729497919@qq.com"))
                   // 版本号
                   .version("1.0")
                   // 描述
                   .description("API 描述")
                   .build();
     }
}

如果有权限校验  则修改

 ParameterBuilder ticketPar = new ParameterBuilder();
        List<Parameter> pars = new ArrayList<Parameter>();
        ticketPar.name("Authorization").description("token")
                .modelRef(new ModelRef("string"))
                .parameterType("header")
                .defaultValue("Bearer-")
                .required(false)
                .build();
        pars.add(ticketPar.build());
        return new Docket(DocumentationType.SWAGGER_2)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("cn.xdf.springboot.controller"))
                .paths(PathSelectors.any())
                .build()
                .globalOperationParameters(pars);

此外,放开swagger资源

@Configuration
@EnableWebMvc
@Log4j2
public class InterceptorConfiguration implements WebMvcConfigurer {

    @Value("${image_url}")
    private String imageUrl;

    @Resource
    private AuthorizationInterceptor authorizationInterceptor;
    @Autowired
    private IgnoredUrlsProperties ignoredUrlsProperties;

    //解决跨域问题配置
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowCredentials(true)
                .allowedHeaders("*")
                .allowedOrigins("*")
                .allowedMethods("GET","POST","PUT","DELETE");

    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/**").addResourceLocations("classpath:/resources/",imageUrl).setCachePeriod(0);
//        registry.addResourceHandler("swagger-ui.html")
//                .addResourceLocations("classpath:/META-INF/resources/");

        registry.addResourceHandler("/webjars/**")
                .addResourceLocations("classpath:/META-INF/resources/webjars/");

        registry.addResourceHandler("doc.html").addResourceLocations("classpath:/META-INF/resources/");

}

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册拦截器
        InterceptorRegistration ir = registry.addInterceptor(authorizationInterceptor);
        // 配置拦截的路径
        ir.addPathPatterns("/**");
        // 配置不拦截的路径
        ir.excludePathPatterns(ignoredUrlsProperties.getUrls());
    }

}

security 的配置类  放开 过滤资源  配置在配置文件中 jgnoreUrls

 @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        //忽略路径
        List<String> urls = ignoredUrlsProperties.getUrls();
        String [] ignoreUrls = urls.toArray(new String [urls.size()]);

        httpSecurity.csrf().disable()
                .httpBasic().authenticationEntryPoint(authenticationEntryPoint)
                //session状态  无状态
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                //请求之前的认证过滤器  token校验
                .and().authorizeRequests()
                .antMatchers(ignoreUrls).permitAll()
                // 所有请求都需要认证
                .anyRequest().authenticated().and().cors();

        httpSecurity
                .headers()
                .frameOptions().sameOrigin()  // required to set for H2 else H2 Console will be blank.
                .cacheControl();

        //httpSecurity.authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll();
        httpSecurity.exceptionHandling().accessDeniedHandler(authAccessDeniedHandler);
        httpSecurity.addFilterBefore(authenticationRequestFilter, UsernamePasswordAuthenticationFilter.class);
    }

    修改添加application.properties文件  设置接口api生效的环境  参数

#是否激活 swagger true or false
swagger.enable=true



# 忽略鉴权url controller 不鉴权
ignored:
  urls:
    - /swagger-ui.html
    - /swagger-ui.html/**
    - /swagger-resources/**
    - /webjars/springfox-swagger-ui/**
    - /swagger/**
    - /v2/**

  第三步:使用swagger来进行模拟测试:

         使用swagger2来进行测试接口主要是在哪些类中使用:这里我们依然选择在controller层:

package cn.xdf.springboot.controller;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import  org.springframework.beans.factory.annotation.Autowired;
import  org.springframework.web.bind.annotation.DeleteMapping;
import  org.springframework.web.bind.annotation.GetMapping;
import  org.springframework.web.bind.annotation.PathVariable;
import  org.springframework.web.bind.annotation.PostMapping;
import  org.springframework.web.bind.annotation.PutMapping;
import  org.springframework.web.bind.annotation.RequestBody;
import  org.springframework.web.bind.annotation.RequestMapping;
import  org.springframework.web.bind.annotation.RequestParam;
import  org.springframework.web.bind.annotation.RestController;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import cn.xdf.springboot.mapper.CategoryMapper;
import cn.xdf.springboot.pojo.Category;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiOperation;
/**
* 控制层 简单演示增删改查及分页
*
*/
@RestController
@RequestMapping("api")
@Api("swaggerDemoController相关的api")
public class SwaggerDemoController {

    @Autowired
    CategoryMapper categoryMapper;
    private static final Logger logger=  LoggerFactory.getLogger(SwaggerDemoController.class);
    //1.商品添加
    //@PutMapping("add") 添加方法--restful风格
    @PutMapping("add")
    @ApiOperation(value="商品新增")
    //正常业务时, 需要在category类里或者server层进行事务控制,控制层一般不进行业务控制的。
    //@Transactional(rollbackFor = Exception.class)
    //@RequestParam 接收页面中的请求的参数
    public Map<String,Object> addCategory(@RequestParam  String name){
      Category category = new Category();
      category.setName(name);
      categoryMapper.save(category);
      logger.info("开始新增某个商品信息");
        Map<String,Object> result = new  HashMap<String,Object>();
        result.put("respCode", "01");
        result.put("respMsg", "新增成功!");
        result.put("data", category);
        return result;
    }
    //2.商品修改
    //@PostMapping("update")  修改方法--restful风格
    @PostMapping("update")  
    @ApiOperation(value = "商品修改", notes = "修改数据库中某个的商品信息")
    //@RequestBody 接收页面中的请求的参数对象(适用于post请求)
    //当入参为实体对象时,需要在方法上加@Valid或@Validated或者在参数前加@Valid或@Validated,或者在类上加@Validated
    public Map<String,Object> updateCategory(@Valid  @RequestBody  Category category) {
      Map<String,Object> result = new  HashMap<String,Object>();
      Category categoryGet =  categoryMapper.get(category.getId());
      if(categoryGet == null || "".equals(categoryGet)){
          try {
                   throw new Exception("修改的该商品不存在!");
              } catch (Exception e) {
                   e.printStackTrace();
              }
           result.put("respCode", "03");
           result.put("respMsg", "修改的该商品不存在!");
           result.put("data", category);
           return result;
      }
        categoryMapper.update(category);
        logger.info("开始修改某个商品信息");
        result.put("respCode", "03");
         result.put("respMsg", "修改成功!");
         result.put("data", category);
        return result;
    }
    //3.商品删除
    //@DeleteMapping("/delete/{id}") 删除方法--restful风格
    @DeleteMapping("/delete/{id}")
    @ApiOperation(value = "根据id删除商品", notes = "商品删除")
    @ApiImplicitParam(name = "id", value = "商品ID",  paramType = "path", required = true, dataType =  "Integer")
     public Map<String,Object>  deleteCategory(@PathVariable int id)throws Exception{   //@PathVariable 获取/delete/{id}中id
      Category category = categoryMapper.get(id);
      Map<String,Object> result = new  HashMap<String,Object>();
      if (category == null) {
          try {
                   throw new Exception("用户ID:" + id +  ",未找到");
              } catch (Exception e) {
                   e.printStackTrace();
              }
           result.put("respCode", "02");
           result.put("respMsg", "数据库无该商品信息,删除失败!");
           result.put("data", category);
           return result;
          }else{
              categoryMapper.delete(id);
              logger.info("开始删除某个商品信息");
              result.put("respCode", "01");
              result.put("respMsg", "删除成功!");
              result.put("data", category);
              return result;  
          }
     }
    //4.根据ID查询商品信息
    //@GetMapping("")  查询方法--restful风格
    @GetMapping("/get/{id}")
    @ApiOperation(value = "根据id查询商品", notes = "查询数据库中某个的商品信息")
    @ApiImplicitParam(name = "id", value = "商品ID",  paramType = "path", required = true, dataType =  "Integer")
    public Map<String,Object> getCategory(@PathVariable  int id) { //@PathVariable 获取/get/{id}中id
      Category category = categoryMapper.get(id);
      logger.info("开始查询某个商品信息");
      Map<String,Object> result = new  HashMap<String,Object>();
      if (category == null) {
          try {
                   throw new Exception("用户ID:" + id +  ",未找到");
              } catch (Exception e) {
                   e.printStackTrace();
              }
           result.put("respCode", "02");
           result.put("respMsg", "数据库无该商品信息");
           result.put("data", category);
           return result;
          }else{
             result.put("respCode", "01");
             result.put("respMsg", "查询成功!");
             result.put("data", category);
             return result;
          }
    }
    //5.分页查询
    //@GetMapping("")  查询方法--restful风格
    @GetMapping("/page")
    @ApiOperation(value="商品查询(分页)")        
    public Map<String,Object>  pageCategory(@RequestParam(value="start",defaultValue="0")int start,@RequestParam(value = "size", defaultValue =  "5") int size) throws Exception {
      //1. 在参数里接受当前是第几页 start ,以及每页显示多少条数据  size。 默认值分别是0和5。
          //2. 根据start,size进行分页,并且设置id 倒排序
          PageHelper.startPage(start,size,"id desc");
          //3. 因为PageHelper的作用,这里就会返回当前分页的集合了
          List<Category> cs = categoryMapper.findAll();
          logger.info("开始分页查询商品信息");
          //4. 根据返回的集合,创建PageInfo对象
          PageInfo<Category> page = new PageInfo<>(cs);
          
        Map<String,Object> result = new  HashMap<String,Object>();
        result.put("respCode", "01");
        result.put("respMsg", "成功");
        result.put("data", page);
        return result;
    }
    
}

这样swagger2与springboot就集成完毕了。

看下最终效果吧:

访问路径:  http://localhost:8080/swagger-ui.html  swagger的路径

访问路径:http://localhost:8080/doc.html#   knife4j的路径

调试:点击需要访问的api列表,点击try it out!按钮,表示 执行。

----------------------------------------------------------------------------------------------------------------------------------------------------------------

而且这些方法是实时更新的!!!

 

接下来测试一个新增方法:

 

 查询方法:

 

另外,大家可下载示例,查看自定义的字符出现的位置,这样可以对其有个大致了解,各字段的作用领域是哪里

Controller层添加注解

@Api:用于类;表示标识这个类是swagger的资源

 

属性名称数据类型  默认值 说明
 value     String "" 字段说明
  tags   String[] "" 标签说明 
 description  String  "" 详情描述 
 basePath
 
 String  "" 基本路径可以不配置 
 position int  "" 如果配置多个Api 想改变显示的顺序位置
 produces String  "" 提供者 (For example, "application/json, application/xml")
 consumes String  "" 消费者(For example, "application/json, application/xml")
 protocols String  "" 协议(Possible values: http, https, ws, wss.)
 authorizations Authorization[]  "" 高级特性认证时配置
 hidden boolean  "" 配置为true 将在文档中隐藏

@ApiResponses:在 Rest 接口上使用,用作返回值的描述

参数

属性名称数据类型默认值说明
valueApiResponse[]""访问对象 

ApiResponse参数

属性名称数据类型默认值说明
codeString ""响应的HTTP状态码
messageString ""响应的信息内容 
responseClass<?>""用于描述消息有效负载的可选响应类,对应于响应消息对象的 schema 字段
referenceString ""指定对响应类型的引用,指定的应用可以使本地引用,也可以是远程引用,将按原样使用,并将覆盖任何指定的response()类 
responseHeadersResponseHeader[]""声明包装响应的容器,有效值为List或Set,任何其他值都将被覆盖
responseContainerString""声明响应的容器,有效值为List,Set,Map,任何其他值都将被忽略
examplesExample ""例子

 

@ApiOperation:用在方法上,说明方法的作用,每一个url资源的定义

参数

属性名称数据类型默认值说明
valueString""url的路径值
notesString""文本说明 
tagsString[]""如果设置这个值、value的值会被覆盖
responseClass<?>""返回的对象
responseContainerString ""声明响应的容器,有效值为List,Set,Map,任何其他值都将被忽略
responseReferenceString ""声明包装响应的容器,有效值为List或Set,任何其他值都将被覆盖
httpMethodString """GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS" and "PATCH"
positionint""如果配置多个Api 想改变显示的顺序位置
nicknameString ""昵称 
producesString""提供者 (For example, "application/json, application/xml")
consumesString""消费者(For example, "application/json, application/xml")
protocolsString""协议(Possible values: http, https, ws, wss.) 
authorizationsAuthorization[]""高级特性认证时配置
hiddenboolean""隐藏 
responseHeadersResponseHeader[]""声明包装响应的容器,有效值为List或Set,任何其他值都将被覆盖
codeString ""http的状态码 默认 200
extensionsExtension[]""扩展属性 
ignoreJsonViewboolean""是否忽略显示 

 

@PathVariable:是获取get方式,url后面参数,进行参数绑定(单个参数或两个以内参数使用)

参数

属性名称数据类型默认值说明
valueString""url的路径值
nameString""重写属性名字 
requiredString""是否必填 

 

@RequestBody :在当前对象获取整个http请求的body里面的所有数据(两个以上参数封装成对象使用)

参数

属性名称数据类型默认值说明
requiredString""是否必填 

 

备注:实体类收参

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
 
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;
 
@ApiModel(description = "登录表单")
public class LoginFormParams implements Serializable {
    /**
     * 用户账号
     */
    @ApiModelProperty(value = "登录账号", name = "account", required = true, example = "admin")
    @NotBlank(message = "账号不允许为空,请输入")
    private String account;
    /**
     * 用户密码
     */
    @ApiModelProperty(value = "登录密码", name = "password", required = true, example = "123456")
    @NotBlank(message = "密码不允许为空,请输入")
    private String password;
    /**
     * 图片验证码
     */
    @ApiModelProperty(value = "验证码", name = "validCode", required = false, example = "TG20")
    /*@NotBlank(message = "验证码不允许为空,请输入")*/
    private String validCode;
 
    /**
     * 记住我
     */
    @ApiModelProperty(value = "记住我", name = "rememberMe", required = false, example = "false")
    private boolean rememberMe;
 
    public String getAccount() {
        return account;
    }
 
    public void setAccount(String account) {
        this.account = account;
    }
 
    public String getPassword() {
        return password;
    }
 
    public void setPassword(String password) {
        this.password = password;
    }
 
    public String getValidCode() {
        return validCode;
    }
 
    public void setValidCode(String validCode) {
        this.validCode = validCode;
    }
 
    public boolean isRememberMe() {
        return rememberMe;
    }
 
    public void setRememberMe(boolean rememberMe) {
        this.rememberMe = rememberMe;
    }
}
    /**
     * 账号登录
     * @param form
     * @param bindingResult
     * @param session
     * @return
     */
    @PostMapping("/ajaxLogin")
    @ApiOperation(value = "用户登录", notes = "用户异步登录处理")
    @ApiImplicitParam(name = "form", value = "用户登录表单", required = true, dataType = "LoginFormParams")
    @ResponseBody
    public JsonResult ajaxLogin(@Valid @RequestBody LoginFormParams form, BindingResult bindingResult, HttpSession session) throws Exception{
        if(bindingResult.hasErrors()){
            for (ObjectError error : bindingResult.getAllErrors()){
                return JsonResult.error(GlobalParams.EX_CODE4.getCode(), error.getDefaultMessage(), null);
            }
        }
 
        // 获取当前用户对象
        Subject subject = SecurityUtils.getSubject();
        // 生成令牌
        UsernamePasswordToken token = new UsernamePasswordToken(form.getAccount(),form.getPassword());
        if(form.isRememberMe()){
            token.setRememberMe(true);
        }else{
            token.setRememberMe(false);
        }
        subject.login(token);
        // 登录成功的用户对象
        SysUser user = (SysUser)subject.getPrincipal();
        // 将信息存储至Redis
        session.setAttribute("user", user);
        return JsonResult.<SysUser>ok(GlobalParams.EX_CODE5, user);
 
    }

【注意】两处地方

@RequestBody 以及

@ApiImplicitParam(name = "form", value = "用户登录表单", required = true, dataType = "LoginFormParams")

其中name 对应的是参数名称,value 是描述,dataType 对应的是参数类型

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值