在api项目中 本地品种无法访问服务器api

在Android代码中,大家有时候会利用比大家在AndroidManifest中安装的android:minSdkVersion版本越来越高的模式,此时编写翻译器会提示警示,

浅谈springfox-swagger原理分析与应用过程中遭遇的坑,

swagger简介

swagger确实是个好东西,能够跟据业务代码自动生成相关的api接口文书档案,特别用于restful风格中的项目,开发职员差不多能够不要尤其去维护rest
api,那么些框架能够活动为你的事务代码生成restfut风格的api,而且还提供对应的测试界面,自动展现json格式的响应。大大有利了后台开发人士与前者的联络与联调费用。

springfox-swagger简介

签于swagger的兵不血刃功用,java开源界大牌spring框架急速跟上,它丰富利用自已的优势,把swagger集成到祥和的类别里,整了1个spring-swagger,后来便衍生和变化成springfox。springfox自己只是利用自身的aop的特点,通过plug的点子把swagger集成了进去,它本身对事情api的变型,照旧依靠swagger来完毕。

关于那几个框架的文书档案,网上的材料相比少,大多数是入门级的简约利用。本身在合龙那一个框架到祥和项目标经过中,蒙受了俯十地芥坑,为了化解这个坑,作者只可以扒开它的源码来看个毕竟。此文,便是记述本身在接纳springfox进度中对springfox的片段清楚以及须要注意的地方。

springfox大概原理

springfox的光景原理正是,在类型运行的过种中,spring上下文在开首化的进度,框架自动跟据配置加载壹些swagger相关的bean到当前的左右文中,并自行扫描系统中大概要求生成api文书档案这多少个类,并扭转对应的新闻缓存起来。假诺项目MVC控制层用的是springMvc那么会自行扫描全数Controller类,跟据那些Controller类中的方法生成对应的api文书档案。

因本人的花色便是SpringMvc,所以此文就以Srping
mvc集成springfox为例来钻探springfox的使用与原理。

SpringMvc集成springfox的步骤

先是,项目要求投入以下八个依靠:

<!-- sring mvc依赖 -->

   <dependency>

     <groupId>org.springframework</groupId>

     <artifactId>spring-webmvc</artifactId>

     <version>4.2.8.RELEASE</version>

   </dependency>

<!-- swagger2核心依赖 -->

   <dependency>

     <groupId>io.springfox</groupId>

     <artifactId>springfox-swagger2</artifactId>

     <version>2.6.1</version>

   </dependency>

   <!-- swagger-ui为项目提供api展示及测试的界面 -->

   <dependency>

     <groupId>io.springfox</groupId>

     <artifactId>springfox-swagger-ui</artifactId>

     <version>2.6.1</version>

   </dependency>

塑造属于自个儿的接济版本迭代的Asp,swagger原理分析与行使进度中相见的坑。位置八个依靠是种类集成springmvc及springfox最大旨的依赖,此外的信赖那里大概。个中第一个是springmvc的主干依靠,第三个是swagger信赖,第8个是界面相关的重视性,这几个不是必须的,假诺你不想用springfox自带的api界面包车型地铁话,也足以毫不这么些,而除此以外自身写1套适合自个儿项目标界面。参与那多少个依靠后,系统后会自动进入1些跟springfox及swagger相关jar包,笔者差不多看了须臾间,主要有以下那样多少个:

springfox-swagger2-2.6.1.jar

swagger-annotations-1.5.10.jar

swagger-models-1.5.10.jar

springfox-spi-2.6.1.jar

springfox-core-2.6.1.jar

springfox-schema-2.6.1.jar

springfox-swagger-common-2.6.1.jar

springfox-spring-web-2.6.1.jar

guava-17.0.jar

spring-plugin-core-1.2.0.RELEASE.jar

金沙注册送58 ,spring-plug-metadata-1.2.0.RELEASE.jar

spring-swagger-ui-2.6.1.jar

jackson-databind-2.2.3.jar

jackson-annotations-2.2.3.jar

地点是自家通过目测觉得springfox恐怕须求的jar,或者未有完全例出springfox所需的兼具jar。从下面jar能够观望pringfox除了依靠swagger之外,它还索要guava、spring-plug、jackson等信赖包(注意jackson是用以生成json必须的jar包,若是项目里作者未有投入那些依靠,为了集成swagger的话无法不附加再参与那些依靠)。

springfox的简约利用

要是只用springfox的暗中认可的配备来说,与springmvc集成起来11分不难,只要写四个好像于以下代码的类放到你的类型里就行了,代码如下:

@Configuration

@EnableWebMvc

@EnableSwagger2

publicclass ApiConfig {}

瞩目到,上边是三个空的java类文件,类名能够任意指定,但不可能不进入上述类中标明的@Configuration、@EnableWebMvc、@EnableSwagger2四个评释,那样就实现了springmvc与springfox的主题集成,有了四个表明,项目运营后就能够直接用接近于以下的地点来查看api列表了:

那真的是1个很神奇的机能,不难的四个表明,系统就自动展现出档次里全体Controller类的保有api了。现在,大家就这几个布局类入手,简单解析它的规律。那些类中尚无此外轮代理公司码,很显眼,八个表明起了至关心尊崇要的效用。当中@Configuration注解是spring框架中本身就有的,它是2个被@Component元声明标识的阐明,所以有了那个注脚后,spring会自动把那么些类实例化成3个bean注册到spring上下文中。首个评释@EnableWebMvc故名思义,正是启用srpingmvc了,在Eclipse中式点心到那一个评释里面大约看一下,它正是因此元注明@Import(DelegatingWebMvcConfiguration.class)往spring
context中塞入了三个DelegatingWebMvcConfiguration类型的bean。笔者想,这么些类的目标应该正是为swagger提供了一部分springmvc方面包车型地铁布署吧。第三个申明:@EnableSwagger2,看名字应该能够想到,是用来集成swagger
二的,他通过元证明:@Import({Swagger二DocumentationConfiguration.class}),又引进了2个Swagger二DocumentationConfiguration类型的安顿bean,而以此就是Swagger的宗旨配置了。它在那之中的代码如下:

@Configuration
@Import({ SpringfoxWebMvcConfiguration.class, SwaggerCommonConfiguration.class })
@ComponentScan(basePackages = {
 "springfox.documentation.swagger2.readers.parameter",
  "springfox.documentation.swagger2.web",
  "springfox.documentation.swagger2.mappers"
})

publicclassSwagger2DocumentationConfiguration {
 @Bean
 public JacksonModuleRegistrar swagger2Module() {
  returnnewSwagger2JacksonModule();
 }
}

本条类尾部通过有个别诠释,再引入SpringfoxWebMvcConfiguration类和SwaggerCommonConfiguration类,并经过ComponentScan注明,自动扫描springfox
.swagger二相关的的bean到spring
context中。那里,作者最感兴趣的是SpringfoxWebMvcConfiguration这几个类,那几个类作者猜应该正是springfox集成mvc比较基本的陈设了,点进入,看到以下代码:

@Configuration
@Import({ModelsConfiguration.class })
@ComponentScan(basePackages = {
  "springfox.documentation.spring.web.scanners",
"springfox.documentation.spring.web.readers.operation","springfox.documentation.spring.web.readers.parameter","springfox.documentation.spring.web.plugins","springfox.documentation.spring.web.paths"
})

@EnablePluginRegistries({ DocumentationPlugin.class,
  ApiListingBuilderPlugin.class,
  OperationBuilderPlugin.class,
  ParameterBuilderPlugin.class,
  ExpandedParameterBuilderPlugin.class,
  ResourceGroupingStrategy.class,
  OperationModelsProviderPlugin.class,
  DefaultsProviderPlugin.class,
  PathDecorator.class
})
publicclassSpringfoxWebMvcConfiguration {}

这几个类中上边包车型客车代码,无非正是经过@Bean申明再进入一些新的Bean,笔者对它的志趣不是非常大,笔者最感兴趣的是尾部通过@EnablePluginRegistries加入的那么些东西。springfox是基于spring-plug的建制结合swagger的,spring-plug具体是怎么落实的,小编临时还尚无时间去研商spring-plug的原理。但在下文仲提到自个儿写3个plug插件来增加swagger的效率。上边通过@EnablePluginRegistries参预的plug中,还未曾时间去看它全部的代码,近来自个儿看过的代码重要有ApiListingBuilderPlugin.class,
OperationBuilderPlugin.class,ParameterBuilderPlugin.class,
ExpandedParameterBuilderPlugin.class,

率先个ApiListingBuilderPlugin,它有五个实现类,分别是ApiListingReader和SwaggerApiListingReader。当中ApiListingReader会自动跟据Controller类型生成api列表,而SwaggerApiListingReader会跟据有@Api评释标识的类生成api列表。OperationBuilderPlugin插件便是用来生成现实api文书档案的,那个类别的插件,有很多广大贯彻类,他们分别分工,各做各的业务,具体小编从没仔细去看,只关怀了当中四个达成类:OperationParameterReader,那个类是用来读取api参数的Plugin。它借助于ModelAttributeParameterExpander工具类,能够将Controller中接口方法参数中国和欧洲大致类型的一声令下对像自动分析它个中的习性得出包括全部属性的参数列表(这里存在一个可能会现出极端递归的坑,下文有介绍)。而ExpandedParameterBuilderPlugin插件,主假诺用来扩充接口参数的一些功能,比如判断那几个参数的数据类型以及是或不是为那一个接口的总得参数等等。总体上说,整个springfox-swagger内部其实是由这一名目繁多的plug转运起来的。他们在系统运转时,就被调起来,有个别用来围观出接口列表,某些用来读取接口参数等等。他们合伙的目地正是把系统中装有api接口都围观出来,并缓存起来供用户查看。那么,那一层层表plug到底是哪些被调起来的,它们的实施入口倒底在哪?

  
大家把注意点放到上文SpringfoxWebMvcConfiguration这一个类代码尾部的ComponentScan表明内容上来,这一段表明中围观了二个叫springfox.documentation.spring.web.plugins的package,那么些package在springfox-spring-web-二.6.①.jar中得以找到。这么些package下,我们发现有八个可怜大旨的类,那正是DocumentationPluginsManager和DocumentationPluginsBootstrapper。对于第3个DocumentationPluginsManager,它是3个尚无兑现任何接口的bean,但它当中有广大PluginRegistry类型的习性,而且都是经过@Autowired评释把属性值注入进来的。接合它的类名来看,很简单想到,那么些就是治本全部plug的一个管理器了。很好通晓,因为ComponentScan评释的布置,全部的plug实例都会被spring实例化成叁个bean,然后被注入到那个DocumentationPluginsManager实例中被联合保管起来。在这么些package中的另三个重大的类DocumentationPluginsBootstrapper,看名字就能够猜到,他也许正是plug的起步类了。点进去看具体时就能够发现,他果然是三个被@Component标识了的零部件,而且它的构造方法中注入了刚刚描述的DocumentationPluginsManager实例,而且最首要的,它还落到实处了斯马特Lifecycle接口。对spring
bean生命周期有所领悟的人的都通晓,那么些组件在被实例化为二个bean纳入srping
context中被管制起来的时候,会自行调用它的start()方法。点到start()中看代码时就会发现,它有1行代码scanDocumentation(buildContext(each));正是用来扫描api文书档案的。进一步跟踪那么些格局的代码,就足以发现,那几个方法最后会通过它的DocumentationPluginsManager属性把持有plug调起一起扫描整个种类并生成api文书档案。扫描的结果,缓存在DocumentationCache这么些类的二个map属性中。

  
以上正是,srpingMvc整合springfox的差不离原理。它主假使通过EnableSwagger2申明,向srping
context注入了1体系bean,并在系统运转的时候自动扫描系统的Controller类,生成对应的api消息并缓存起来。其余,它还注入了某个被@Controller评释标识的Controller类,作为ui模块访问api列表的进口。比如springfox-swagger2-二.陆.壹.jar包中的Swagger2Controller类。那些Controller正是ui模块中用来走访api列表的界面地址。在走访

叩问了springfox的法则,上边来探望springfox使用进程中,小编赶上的什么坑。

springfox第一大坑:配置类生成的bean必须与spring
mvc共用同1个上下文。

前文描述了,在springmvc项目中,集成springfox是假设在类型写2个之类的从未有过别的交事务情代码的简便安排类就能够了。

@Configuration
@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
}

因为@Configuration表明的效益,spring会自动把它实例化成三个bean注入到上下文。但切记要注意的贰个坑便是:那一个bean所在的上下文必须跟spring
mvc为同3个上下文。怎么解理呢?因为在其实的spring
mvc项目中,常常有四个上下文,3个是跟上下文,另2个是spring
mvc(它是跟上下文的子上下文)。个中跟上下文是正是web.xml文件中跟spring相关的丰盛org.springframework.web.context.request.RequestContextListener监听器,加载起来的上下文,平时大家会写3个叫spring-contet.xml的布置文件,那之中的bean最后会早先化到跟上下文中,它最首要包涵系统内部的service,dao等bean,也席卷数据源、事物等等。而另贰个上下文是正是spring
mvc了,它通过web.xml中跟spring
mvc相关的不得了org.springframework.web.servlet.DispatcherServlet加载起来,他平日有三个配备文件叫spring-mvc.xml。大家在写ApiConfig这几个类时,借使控制用@Configuration注脚来加载,那么就亟须保障那几个类所在的路线刚还好springmvc的component-scan的布署的base-package范围内。因为在ApiConfig在被spring加载时,会注入一列类别的bean,而这几个bean中,为了能自动扫描出富有Controller类,有个别bean须求依靠于SpringMvc中的1些bean,假如项目把Srpingmvc的上下文与跟上下文分开来,作为跟上下文的子上下文的话。假诺非常的大心让这几个ApiConfig类型的bean被跟上文加载到,因为root
context中平昔不spring mvc的context中的那多少个配置类时就会报错。

实际上,笔者并不相同情通过@Configuration评释来布署Swagger,因为自身觉着,Swagger的api功用对于生产项目来说是不屑壹顾的。大家Swagger往往是用以测试环境供项如今端团队费用或供其他系统作接口集成使上。系统上线后,很或然在生产体系上隐藏这么些api列表。
但假若安顿是通过@Configuration表明写死在java代码里的话,那么上线的时候想去掉这么些功效的时候,那就狼狈了,不得不修改java代码重新编写翻译。基于此,笔者引入的二个方法,通过spring最古板的xml文件配置格局。具体做法正是去掉@Configuration注脚,然后它写一个看似于<bean
class=”com.jad.web.mvc.swagger.conf.ApiConfig”/>那样的bean配置到spring的xml配置文件中。在root
context与mvc的context分开的体系中,直接配备到spring-mvc.xml中,那样就确认保证了它跟springmvc
的context一定处于同1个context中。

springfox第三大坑:Controller类的参数,注意防止出现Infiniti递归的地方。

Spring
mvc有强劲的参数绑定机制,能够自行把请求参数绑定为二个自定义的下令对像。所以,很多开发职员在写Controller时,为了偷懒,间接把1个实体对像作为Controller方法的三个参数。比如上面那几个示例代码:

@RequestMapping(value = "update")
public String update(MenuVomenuVo, Model model){
}

那是超越5/十程序员喜欢在Controller中写的改动某些实体的代码。在跟swagger集成的时候,那里有1个大坑。假设MenuVo那些类中拥有的天性都以骨干项目,那辛亏,不会出哪些难题。但如若那一个类里面有1些任何的自定义类型的性质,而且以此本性又直接或直接的存在它自个儿类型的特性,那就会出难点。例如:要是MenuVo那些类是菜单类,在那个类时又富含MenuVo类型的一脾质量parent代表它的父级菜单。那样的话,系统运转时swagger模块就因不能加载这些api而一向报错。报错的来由固然,在加载这么些法子的经过中会解析那些update方法的参数,发现参数MenuVo不是不难类型,则会活动以递归的不2秘籍诠释它有着的类属性。那样就很简单陷入万分递归的死循环。

为了缓解那些难题,笔者眼下只是自个儿写了2个OperationParameter里德r插件完结类以及它依靠的ModelAttributeParameterExpander工具类,通过配备的办法替换掉到srpingfox原来的那三个类,偷梁换柱般的把参数解析那几个逻辑替换掉,并逃脱Infiniti递归。当然,这一定于是一种修改源码级其他章程。笔者眼下还尚无找到消除这几个题材的更健全的措施,所以,只好建议大家在用spring-fox
Swagger的时候尽量防止那种卓殊递归的意况。毕竟,那不符合springmvc命令对像的行业内部,springmvc参数的一声令下对像中最棒只含有不难的主导项目属性。

springfox第2大坑:api分组相关,Docket实例不可能推迟加载

springfox暗中认可会把全数api分成一组,那样经过类似于:

@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
@Bean
 public Docket customDocket() {
    return newDocket(DocumentationType.SWAGGER_2).apiInfo(apiInfo());
  }
}

上述代码中经过@Bean注入三个Docket,那么些布局并不是必须的,借使未有这么些布局,框架会自个儿生成贰个默许的Docket实例。这几个Docket实例的职能便是点名全体它能管住的api的公共音讯,比如api版本、小编等等基本消息,以及钦赐只列出什么api(通过api地址或申明过滤)。

Docket实例可以有五个,比如如下代码:

@EnableWebMvc
@EnableSwagger2
publicclass ApiConfig {
@Bean
 public Docket customDocket1() {
    return newDocket(DocumentationType.SWAGGER_2)
.groupName("apiGroup1").apiInfo(apiInfo()).select()

.paths(PathSelectors.ant("/sys/**"));

  }

@Bean
 public Docket customDocket2() {
    return newDocket(DocumentationType.SWAGGER_2)
.groupName("apiGroup2").apiInfo(apiInfo())
.select()
.paths(PathSelectors.ant("/shop/**"));
  }
}

当在档次中布置了八个Docket实例时,也就可以对api实行分组了,比如上边代码将api分为了两组。在那种场所下,必须给每①组内定多个不一样的名称,比如上边代码中的”apiGroup一”和”apiGroup2″,每壹组能够用paths通过ant风格的地点表明式来钦命哪1组管理哪些api。比如上边配置中,第二组管理地点为/sys/开端的api第三组管理/shop/起始的api。当然,还有许多别的的过滤格局,比如跟据类评释、方法表明、地址正则表明式等等。分组后,在api
列表界面右上角的下拉挑选中就能够采用不相同的api组。这样就把品种的api列表分散到不一致的页面了。那样,即方便管理,又不致于页面因急需加载太多api而假死。

只是,同使用@Configuration1样,笔者并不赞同接纳@Bean来布局Docket实例给api分组。因为那样,同样会把代码写死。所以,小编引入在xml文件中温馨部署Docket实例完结那些看似的功能。当然,思虑到Docket中的众多脾性,间接配备bean相比较坚苦,能够团结为Docket写一个FactoryBean,然后在xml文件中安顿FactoryBean就行了。然则将Docket配置到xml中时。又会遇见一个大坑,就那是,spring对bean的加载情势私下认可是延迟加载的,在xml中直接配置那么些Docket实例Bean后。你会发觉,未有一点功用,页面左上角的下拉列表中跟本没有您的分组项。

以此难题曾困扰过本人好多少个钟头,后来凭经验估摸出恐怕是因为sping
bean私下认可延迟加载,那么些Docket实例还没加载到spring
context中。实事注解,小编的猜忌是对的。笔者不知道那究竟springfox的3个bug,还是因为本人跟本不应该把对Docket的布署从原先的java代码中搬到xml配置文件中来。

springfox别的的坑:springfox还有个别其余的坑,比如@ApiOperation评释中,假使不内定httpMethod属性具体为某些get或post方法时,api列表中,会它get,post,delete,put等全数办法都列出来,搞到api列表重复的太多,很无耻。别的,还有在测试时,境遇登录权限难点,等等。这一群堆的比较易于解决的小坑,因为篇幅有限,小编就不多说了。还有诸如@Api、@ApiOperation及@ApiParam等等表明的用法,网上海人民广播广播台湾大学那地点的文书档案,笔者就不另行了。

上述就是本文的全体内容,希望对大家的上学抱有帮衬,也期待大家多多支持帮客之家。

swagger简介
swagger确实是个好东西,能够跟据业务代码自动生成相关的api接口文书档案,尤其…

    在当下的主流架构中,大家尤其多的看出web
Api的存在,小巧,灵活,基于Http协议,使它在更为多的微服务项目仍旧移动项目充当很好的service
endpoint。

金沙注册送58 1

焚薮而田办法是在艺术上助长@SuppressLint(“NewApi”)恐怕@TargetApi()。

问题

    以Asp.Net Web Api 为例,随着工作的恢宏,产品的迭代,我们的web
api也在随之转移,很多时候会现身多少个版本共存的景观,这年大家就需求统一筹划三个帮衬版本号的web
api link,比如:

原先:

如今:

在我们刚设计的时候,有非常大大概没有设想版本的题目,笔者见状众多的档次都会在link后加盟2个“?version=”的方法,那种方法实在能够消除难点,但对Asp.Net
Web
Api来说,进入的要么同多个Controller,我们要求在同八个Action中进行判定版本号,例如:

]

public class BlogsController : ApiController
{
    // GET api/<controller>
    public IEnumerable<string> Get([FromUri]string version = "")
    {
        if (!String.IsNullOrEmpty(version))
        {
            return new string[] { $"{version} blog1", $"{version} blog2" };
        }
        return new string[] { "blog1", "blog2" };
    }
}

大家看来大家通过判断url中的version参数进行对应的回到,为了保证原先接口的可用,大家要求对参数赋上默许值,尽管能够消除大家的版本迭代难题,但随着版本的不断更新,你会发觉那么些Controller会越来越臃肿,维护越来越劳累,因为这种修改已经严重背离了OCP(Open-Closed
Principle),最佳的措施是不修改原先的Controller,而是新建新的Controller,放在对应的目录中(可能项目中),比如:

金沙注册送58 2

为了不影响原本的花色,大家尽量不要改动原Controller的Namespace,除非你有丰富的握住未有影响,不然请尽大概只是运动到目录。

ok,为了维持原接口的投射,大家须求在WebApiConfig.Register中登记援助版本号的Route映射:

config.Routes.MapHttpRoute(
    name: "DefaultVersionApi",
    routeTemplate: "api/{version}/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
);

打开浏览器照旧postman,输入原先的api url,你会发觉那样的谬误:

金沙注册送58 3

那是因为web api
查找Controller的时候,只会依照ClassName实行搜寻的,当出现相同ClassName的时候,就会报那个漏洞非常多,那时候咱们就须要塑造自个儿的Controller
Selector,万幸微软留了四个接口给到大家:IHttpControllerSelector。可是为了合作原先的api(有个别不在我们权力限制内的api,不加版本号的那种),大家照旧直接集成DefaultHttpControllerSelector相比较好,大家给定二个平整,不担负大家版本迭代的api,就让它走原先的映照。

百度了下,查出原因

这他们中间有啥差异吗,很简单,

思路

一、项目运行的时候,先把符合条件的Controller参与到三个字典中

二、判断request,符合规则的,大家回来我们制订的controller。

金沙注册送58 4

金沙注册送58 5

金沙注册送58 6

@SuppressLint(“NewApi”)屏蔽一切新api中才能使用的法子报的android
lint错误

成立属于自身的Selector

思路有了,那改造起来也卓殊不难,明日我们先做一个简易的,等有时间改成可陈设的。

先是步,大家先创立三个Selector类,继承自DefaultHttpControllerSelector,然后开首化的时候创造3个属于我们温馨的字典:

public class VersionHttpControllerSelector : DefaultHttpControllerSelector
{
    private readonly HttpConfiguration _configuration;
    private readonly Lazy<Dictionary<string, HttpControllerDescriptor>> _lazyMappingDictionary;
    private const string DefaultVersion = "v1"; //默认版本号,因为之前的api我们没有版本号的概念
    private const string DefaultNamespaces = "WebApiVersions.Controllers"; //为了演示方便,这里就用到一个命名空间
    private const string RouteVersionKey = "version"; //路由规则中Version的字符串
    private const string DictKeyFormat = "{0}.{1}";
    public VersionHttpControllerSelector(HttpConfiguration configuration):base(configuration)
    {
        _configuration = configuration;
        _lazyMappingDictionary = new Lazy<Dictionary<string, HttpControllerDescriptor>>(InitializeControllerDict);
    }

    private Dictionary<string, HttpControllerDescriptor> InitializeControllerDict()
    {
        var result = new Dictionary<string, HttpControllerDescriptor>(StringComparer.OrdinalIgnoreCase);
        var assemblies = _configuration.Services.GetAssembliesResolver();
        var controllerResolver = _configuration.Services.GetHttpControllerTypeResolver();
        var controllerTypes = controllerResolver.GetControllerTypes(assemblies);

        foreach(var t in controllerTypes)
        {
            if (t.Namespace.Contains(DefaultNamespaces)) //符合NameSpace规则
            {
                var segments = t.Namespace.Split(Type.Delimiter);
                var version = t.Namespace.Equals(DefaultNamespaces, StringComparison.OrdinalIgnoreCase) ?
                    DefaultVersion : segments[segments.Length - 1];
                var controllerName = t.Name.Remove(t.Name.Length - DefaultHttpControllerSelector.ControllerSuffix.Length);
                var key = string.Format(DictKeyFormat, version, controllerName);
                if (!result.ContainsKey(key))
                {
                    result.Add(key, new HttpControllerDescriptor(_configuration, t.Name, t));
                }
            }
        }

        return result;
    }
}

有了字典接下去就好办了,只要求分析request就好了,符合大家版本要求的,就从大家的字典中搜寻对应的Descriptor,即使找不到,就走暗中同意的,那里大家需求重写SelectController方法:

public override HttpControllerDescriptor SelectController(HttpRequestMessage request)
{
    IHttpRouteData routeData = request.GetRouteData();
    if (routeData == null)
        throw new HttpResponseException(HttpStatusCode.NotFound);

    var controllerName = GetControllerName(request);
    if (String.IsNullOrEmpty(controllerName))
        throw new HttpResponseException(HttpStatusCode.NotFound);

    var version = DefaultVersion;
    if (IsVersionRoute(routeData, out version))
    {
        var key = String.Format(DictKeyFormat, version, controllerName);
        if (_lazyMappingDictionary.Value.ContainsKey(key))
        {
            return _lazyMappingDictionary.Value[key];
        }

        throw new HttpResponseException(HttpStatusCode.NotFound);
    }

    return base.SelectController(request);
}

private bool IsVersionRoute(IHttpRouteData routeData, out string version)
{
    version = String.Empty;
    var prevRouteTemplate = "api/{controller}/{id}";
    object outVersion;
    if(routeData.Values.TryGetValue(RouteVersionKey, out outVersion))   //先找符合新规则的路由版本
    {
        version = outVersion.ToString();
        return true;
    }

    if (routeData.Route.RouteTemplate.Contains(prevRouteTemplate))  //不符合再比对是否符合原先的api路由
    {
        version = DefaultVersion;
        return true;
    }

    return false;
}

完了这一个类后,我们去WebApiConfig.Register中举办轮换操作:

config.Services.Replace(typeof(IHttpControllerSelector), new VersionHttpControllerSelector(config));

ok,再度打开浏览器,输入 和
,那时应该能看到科学的推行:

金沙注册送58 7

金沙注册送58 8

随着找到rails项指标消除办法,安装rack-cors那些gem包

@TargetApi() 只屏蔽某1新api中才能利用的诀窍报的android lint错误

写在结尾

后天大家制作了叁个不难易行符合webapi版本号更新迭代的ControllerSelector,可是还不是很周全,因为许多都是hard
code,后边笔者会做贰个援助配置的ControllerSelector放到github上。

事先从来在切磋eShopOnContrainers,近日也在商量,可是工作确实有点忙,见谅见谅,借使大家.Net有哪些难点要么喜欢技术交友的,都足以加QQ群:37624805四

具体方法如下:

举个例证,某些方法中选拔了api玖新加入的秘诀,而项目安装的android:minSdkVersion=八,此时在措施上加@SuppressLint(“NewApi”)

Gemfile中加入

和@TargetApi(Build.VERSION_CODES.GINGERBREAD)都得以,以上是通用的情形。

gem 'rack-cors', :require => 'rack/cors'

而当您在此格局中又引述了四个api1一才到场的办法时,@TargetApi(Build.VE奥德赛SION_CODES.GINGERBREAD)注明的秘诀又报错了,而

  终端运维  bundle

@SuppressLint(“NewApi”)不会报错,那就是分别。

在application.rb中进入以下代码

 

config.middleware.insert_before 0, Rack::Cors do
      allow do
        origins '*'
        resource '*',
                 :headers => :any,
                 :methods => :any,
                 :expose => ['access-token', 'expiry', 'token-type', 'uid', 'client']
      end
 end

当然,不管您使用了哪个证明,成效只是是屏蔽android
lint错误,所以在艺术中还要判断版本做不相同的操作,比如:

 重启项目即可缓解此题材

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD) {  
            //  
} else {// Pre GINGERBREAD  
            //  
}  

 

相关文章

网站地图xml地图