项目集成swagger

一:思考:

1.swagger解决了我们什么问题?

传统开发中,我们在开发完成一个接口后,为了测试我们的接口,我们通常会编写单元测试,以测试我们的接口的可用性,或者用postman等第三方接口测试工具进行测试,但是这也有一些弊端,我们需要为接口准备测试数据,但有时,数据量较大时,前期准备工作可能相当耗时

2.除了用于接口测试,我们还能利用它做些什么有意义的事呢?

在项目的开发过程中,我们通常会用到大量的定时任务;
a.分布式环境:quartz
b.单机环境:有spring提供的schedule 或者用线程(局限性较大)
因为公司没有引入调度中心,没有一个统一的地方对项目中的定时任务进行统一的管理,所以需要每个项目集成自己的调度框架

例如:我现在有一个需求,是每天早上7点的时候,对昨日告警发送一个统计日报,最简单的做法是引入@schedule(cron="0 0 7 * * ?")

我们经过本地的辛苦开发测试,一切正常,可是当我们将项目发布到QA环境,发现自己无法对这个定时任务的代码进行有效测试,如果需要观察我们甚至需要等到明天早上7点

问题的根源在于 Schedule 方法基于时间触发,如果使其暴露出来,能够手工触发,将大大增加灵活性。

我通过对其定制,可以暴露使用到了schedule的地方,并提供手动触发,

二:集成swagger

1.引入依赖

<dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger2</artifactId>
       <version>2.7.0</version>
   </dependency>
   <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger-ui</artifactId>
       <version>2.7.0</version>
   </dependency>

2.启用swagger

在配置类上加上注解@EnableSwagger2

三:为定时调度任务schedule暴露接口

#### 1.HandlerMapping 扩展

新建 ScheduleMethodHandlerMapping 继承自 RequestMappingInfoHandlerMapping ,实现 HandlerMapping 接口。

public class ScheduleMethodHandlerMapping
extends RequestMappingInfoHandlerMapping
implements HandlerMapping{
/**
* 包含@Scheduled注解方法的bean为handler
* @param beanType
* @return
*/
@Override
protected boolean isHandler(Class<?> beanType) {
return Arrays.asList(MethodUtil.getMethods(beanType)).stream()
.anyMatch(method -> method.getAnnotation(Scheduled.class) != null);
}

/**
* 处理@Scheduled标注方法,生成对于的RequestMappingInfo
* @param method
* @param handlerType
* @return
*/
@Override
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
if (method.getAnnotation(Scheduled.class) == null){
return null;
}
return RequestMappingInfo.paths("/schedule/" + handlerType.getSimpleName() + "/" + method.getName())
.methods(RequestMethod.GET)
.build();
}

/**
* 提高该HandlerMapping在HandlerMapping中的顺序,使其能优先处理
* @return
*/
@Override
public int getOrder() {
return 1;
}
}
 

2.HandlerAdapter 扩展

andlerAdapter 扩展主要解决 Schedule 方法的执行问题。

带有 @Scheduled 注解的 Method 方法,需要单独的 HandlerAdapter 进行处理,并将处理结果通过 json 方式返回。

新建 ScheduleMethodHandlerAdapter

ScheduleMethodHandlerAdapter 继承自 AbstractHandlerMethodAdapter ,实现 HandlerAdapter 接口。

public class ScheduleMethodHandlerAdapter
extends AbstractHandlerMethodAdapter
implements HandlerAdapter {

/**
* 支持使用@Scheduled标准的handlerMethod对象
* @param handlerMethod
* @return
*/
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return handlerMethod.hasMethodAnnotation(Scheduled.class);
}

/**
* 调用HandlerMethod方法,并返回json视图
* @param request
* @param response
* @param handlerMethod
* @return
* @throws Exception
*/
@Override
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

Map<String, Object> data = Maps.newHashMap();
data.put("service", handlerMethod.getBeanType().getSimpleName());
data.put("method", handlerMethod.getMethod().getName());
Stopwatch stopwatch = Stopwatch.createStarted();
try {
// 调用HandleMethod方法
handlerMethod.getMethod().invoke(handlerMethod.getBean());
stopwatch.stop();
data.put("result", "success");
}catch (Exception e){
data.put("result", "error");
data.put("exception", e.toString());
}finally {
data.put("cost", stopwatch.elapsed(TimeUnit.MILLISECONDS) + "ms");

}
// 返回Json视图
return new ModelAndView(new MappingJackson2JsonView(), data);
}

@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
return 0;
}

/**
* 提高在HandlerAdapter列表中的顺序,以优先处理
* @return
*/
@Override
public int getOrder() {
return 0;
}
}

3.与 Spring Boot 集成

ScheduleMethodHandlerMappingScheduleMethodHandlerAdapter 开发完成后,我们需要将其与 Spring Boot 进行集成,并通过参数控制是否启用。

新建 ScheduleEndpointConfiguration

新建 ScheduleEndpointConfiguration 配置类,对 ScheduleMethodHandlerMapping 和 ScheduleMethodHandlerAdapter 进行注册。

/**
* 根据配置属性控制是否启用该配置。
* <br />
* spring.schedule.endpoint.enabled = true 启用配置 <br />
* spring.schedule.endpoint.enabled = false 禁用配置 <br />
*/
@ConditionalOnProperty(prefix = "spring.schedule.endpoint", value = "enabled", havingValue = "true", matchIfMissing = false)
@Configuration
public class ScheduleEndpointConfiguration {
/**
* 注册 ScheduleMethodHandlerAdapter Bean
* @return
*/
@Bean
public ScheduleMethodHandlerAdapter scheduleMethodHandlerAdapter(){
return new ScheduleMethodHandlerAdapter();
}

/**
* 注册ScheduleMethodHandlerMapping Bean
* @return
*/
@Bean
public ScheduleMethodHandlerMapping scheduleMethodHandlerMapping(){
return new ScheduleMethodHandlerMapping();
}
}

在 resources 目录新建 META-INF 目录,并新建 spring.factories 文件,文件内声明 ScheduleEndpointConfiguration 为自动配置项。

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.fudax.sqcs.common.schedule.ScheduleEndpointConfiguration

四:集成效果

访问接口:/swagger-ui.html

这谁ChangeController下的所有接口

查看暴露的定时任务接口

在类MessageServer我有两个定时任务:pushAll()方法 clear()方法

点击 try it out即可立即触发

五:安全

这种端点暴露只能在本地测试,开发环境使用,上到生产应该是严格禁止操作的

所以,我写环境校验,以保证生产的安全性

package com.fudax.sqcs.common.schedule.condition;

import com.fudax.sqcs.common.constants.Env;
import com.google.common.collect.Sets;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.type.AnnotatedTypeMetadata; import java.util.Map; public class OnEnvironmentCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Map<String, Object> attributes = metadata.getAnnotationAttributes(ConditionalOnEnvironment.class.getName());
Env[] envs = (Env[]) attributes.get("values");
Env currentEnv = Env.getCurrentEnv();
return Sets.newHashSet(envs).contains(currentEnv);
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
@Documented
@Conditional(OnEnvironmentCondition.class)
public @interface ConditionalOnEnvironment { Env[] values() default {Env.LOCAL};
}

项目集成swagger,并暴露指定端点给swagger的更多相关文章

  1. 开源一款强大的文件服务组件(QJ_FileCenter)(系列三 访问接口与项目集成)

    系列文章 1. 开源一款强大的文件服务组件(QJ_FileCenter)(系列一) 2. 开源一款强大的文件服务组件(QJ_FileCenter)(系列二 安装说明) 3. 开源一款强大的文件服务组件 ...

  2. 分享一个集成在项目中的REST APIs文档框架swagger

    1 为什么是使用swagger? 1-1 当后台开发人员开发好接口,是不是还要重新书写一份接口文档提给前端人员,当然对于程序员最不喜欢的就是书写文档(当然文档是必须的,有利于项目的维护) 1-2 当后 ...

  3. 使用IDEA快速搭建基于Maven的SpringBoot项目(集成使用Redis)

    迫于好久没写博客心慌慌,随便写个简单版的笔记便于查阅. 新建项目 新建项目 然后起名 继续next netx finish. 首先附上demo的项目结构图 配置pom.xml <?xml ver ...

  4. iOS-Cordova集成开发,已有项目集成cordova

    iOS-Cordova集成开发,已有项目集成cordova 项目组准备开发一个APP,要求Android和iOS端页面完全一致,除了一个页面跟业务相关的不同,其他界面基本一致,因此,萌生一个想法,关于 ...

  5. SpringBoot项目集成Hystrix

    Hystrix Hystrix是由Netflix开源的一个服务隔离组件,通过服务隔离来避免由于依赖延迟.异常,引起资源耗尽导致系统不可用的解决方案. 1.什么是服务熔断   服务熔断就是对该服务的调用 ...

  6. [转帖]spring boot项目集成jacoco

    小试牛刀:spring boot项目集成jacoco 2019-03-28 20:14:36 zyq23333 阅读数 509   版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议, ...

  7. Apollo简介及项目集成

    1. 产生背景 随着程序功能的日益复杂,程序的配置日益增多:各种功能的开关.参数的配置.服务器的地址…… 对程序配置的期望值也越来越高:配置修改后实时生效,灰度发布,分环境.分集群管理配置,完善的权限 ...

  8. 【DataBase】Hsqldb与项目集成

    Hsqldb与项目集成 进行模式下集成 可以集成进行(In-Process)模式下的hsqldb,由于数据存储在文件中,即使程序退出,数据也不会被销毁 采用jdbc集成的方式 package com. ...

  9. Spring Boot 项目集成 Alibaba Druid

    Druid 是一个非常好用的数据库连接池,但是他的好并不止体现在作为一个连接池加快数据访问性能上和连接管理上,他带有一个强大的监控工具:Druid Monitor.不仅可以监控数据源和慢查询,还可以监 ...

随机推荐

  1. SVG开发包, 20 个有用的 SVG 工具,提供更好的图像处理

    20 个有用的 SVG 工具,提供更好的图像处理 SVG 现正在 Web 设计领域变得越发流行, 你可以使用 Illustrator 或者 Inkscape 来创建 SVG 图像. 但当进行 Web ...

  2. 用DECODE进行排序

    DECODE用法: 现定义一table名为output,其中定义两个column分别为monthid(var型)和sale(number型),若sale值=1000时翻译为D,=2000时翻译为C,= ...

  3. jmeter 导入csv数据中json格式数据取值不完整

    1.jmeter中添加csv数据文件时,数据是json格式 2.jmeter中执行取值发现只取了一部分 分析原因,json格式数据,中间有逗号,而csv是根据逗号来分割的,这回导致我们取值错位. 解决 ...

  4. 如何为元组中的每个元素命名,提高程序可读性---Python数据结构与算法相关问题与解决技巧

    实际案例: 学生信息系统中,数据为固定格式:(名字,年龄,性别,邮箱) ,通常使用元组来存储 使用优点: 使用元组最大的优点在于节省空间,存储相同的数据,使用元组比使用字典,空间小很多 使用缺点: 访 ...

  5. 利用select单线程点对点聊天

    select的优点与使用方法 select用单线程的方法遍历所有待读写的I/O接口, 当有接口可用时就会返回. select可设置电脑阻塞或非阻塞. 特别注意: 每次select前都要重新初始化集合和 ...

  6. select的限制与poll的使用

    select的限制 select的并发数受到两个限制:1.一个进程能打开的最大描述符数量;2.select中fd_set集合容量的限制(FD_SETSIZE) 关于进程的最大描述符数量: ulimit ...

  7. multiprocessing的Process类的简单使用

    ''' 跨平台的进程创建模块(multiprocessing) 支持跨平台 :window/linux multiprocessing提供一个Process类来代表一个进程对象 ''' from mu ...

  8. Cocos2d-x之String

    |   版权声明:本文为博主原创文章,未经博主允许不得转载. 在Cocos2d-x中能够使用的字符串constchar*.std::string和cocos2d::__String等,其中const ...

  9. linux下对rpm源码手工打补丁

    前言 通常情况rpm包组件管理方式下的linux环境,常用打补丁的方式只有一种:修改spec文件定义的Patch和patch字段,其实spec文件中调用的底层命令还是patch.  因为业务需要要编译 ...

  10. 63.Perfect Squares(完美平方数)

    Level:   Medium 题目描述: Given a positive integer n, find the least number of perfect square numbers (f ...