Introdução a Swagger
Swagger é realmente uma coisa boa. Ele pode gerar automaticamente documentos de interface da API com base no código comercial, especialmente para projetos em estilo RESTful. Os desenvolvedores dificilmente podem ter que manter a API de repouso especificamente. Essa estrutura pode gerar automaticamente APIs de estilo RESTFUT para o seu código comercial e também fornece uma interface de teste correspondente para exibir automaticamente a resposta no formato JSON. Isso facilita muito os custos de comunicação e coordenação entre os desenvolvedores de back-end e o front-end.
Introdução ao Springfox-Swagger
Com as poderosas funções de Swagger, a grande estrutura de Big Spring Industry Java se manteve rapidamente. Ele utilizou totalmente suas próprias vantagens, integrou o Swagger em seu próprio projeto e integrou um Spring-Swagger, que mais tarde evoluiu para o Springfox. O Springfox em si usa apenas suas próprias características da AOP e integra o Swagger no plugue. Sua própria geração de APIs de negócios ainda depende da arrogância para alcançá -la.
Há relativamente pouca informação sobre essa estrutura, e a maioria deles é um uso simples de nível básico. Encontrei muitas armadilhas no processo de integrar essa estrutura ao meu projeto. Para resolver essas armadilhas, tive que desenterrar seu código -fonte para ver o que era. Este artigo descreve minha compreensão do Springfox e o que precisa ser prestado a atenção durante o uso do Springfox.
O princípio geral do Springfox
O princípio geral do Springfox é que, no processo de inicialização do projeto, durante o processo de inicialização do contexto da primavera, a estrutura carrega automaticamente alguns grãos relacionados a swagger no contexto atual de acordo com a configuração e digitaliza automaticamente as classes que podem precisar gerar documentos de API no sistema e gerar cache de informações correspondentes. Se a camada de controle do MVC do projeto usar o SpringMVC, ele digitalizará automaticamente todas as classes de controlador para gerar documentos da API correspondentes de acordo com os métodos nessas classes de controlador.
Como meu projeto é SpringMVC, este artigo usa a Integração do MVC Spring Springfox como exemplo para discutir o uso e os princípios do Springfox.
Passos para integrar Springmvc ao Springfox
Primeiro, o projeto precisa adicionar as três dependências a seguir:
<!-- sring mvc dependency--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.2.8.RELEASE</version> </dependency><!-- swagger2 core dependency--> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.6.1</version> </dependency> <!-- swagger-ui provides API display and testing interface for projects --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.6.1</version> </dependency>
As três dependências acima são as dependências mais básicas para a integração do projeto Springmvc e Springfox, e outras dependências são omitidas aqui. O primeiro é a dependência básica do SpringMVC, a segunda é a dependência de swagger e a terceira é a dependência relacionada à interface. Isso não é necessário. Se você não deseja usar a interface da API que vem com o Springfox, também não pode usar isso e escrever um conjunto de interfaces adequadas ao seu projeto. Depois de adicionar essas dependências, o sistema adicionará automaticamente alguns pacotes JAR relacionados a Springfox e Swagger. Dei uma breve olhada e descobri que há principalmente o seguinte:
Springfox-Swagger2-2.6.1.jar
Swagger-Annotações-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
Spring-Plug-Metadata-1.2.0.release.jar
Spring-Swagger-Ui-12.6.1.jar
Jackson-Databind-2.2.3.jar
Jackson-Annotações-2.2.3.Jar
O exposto acima são os frascos que eu acho visualmente que o Springfox pode precisar e pode não ilustrar completamente todos os frascos que o Springfox precisa. Do jar acima, podemos ver que, além de confiar em Swagger, o pringfox também requer goiaba, plugue da mola, Jackson e outras dependências (observe que Jackson é um pacote de jar necessário para gerar JSON. Se essa dependência não for adicionada ao próprio projeto, a fim de integrar swagger, essa dependência deve ser adicionada).
Uso simples de Springfox
Se você usar apenas a configuração padrão do Springfox, a integração do SpringMVC é muito simples. Basta escrever uma classe semelhante ao código a seguir e colocá -lo em seu projeto. O código é o seguinte:
@Configuration@EnableWebmvc@enablewagger2publicClass apiconfig {}Observe que acima é um arquivo de classe Java vazio, o nome da classe pode ser especificado à vontade, mas as três anotações marcadas @configuration, @enablewebmvc e @enableswagger2 na classe acima devem ser adicionadas. Isso completa a integração básica do SpringMVC e Springfox. Com três anotações, após o início do projeto, você pode usar diretamente um endereço semelhante ao seguinte para visualizar a lista de API: http://127.0.0.1:8080/jaddemo/swagger-ui.html
Este é realmente um efeito muito mágico. Com três anotações simples, o sistema exibirá automaticamente todas as APIs de todas as classes de controlador no projeto. Agora, vamos começar com essa classe de configuração e simplesmente analisar seus princípios. Não há código nesta classe e é óbvio que as três anotações desempenham um papel crucial. Entre eles, a anotação @Configuration já está disponível na estrutura da primavera. É uma anotação identificada pela meta -anotação @Component. Portanto, com esta anotação, a primavera instanciará automaticamente a classe em um feijão e a registrará no contexto da primavera. A segunda anotação @enablewebmvc, portanto, significa que o SRPINGMVC está ativado. Clique nesta anotação no Eclipse para uma breve olhada. É para enfiar um feijão do tipo DelegatingWebMVCConfiguration no contexto da primavera através da meta anotação @import (DelegatingWebmvcConfiguration.class). Eu acho que o objetivo desta classe deve ser fornecer a Swagger alguma configuração do SpringMVC. A terceira anotação: @EnableSwagger2. Você pode pensar no nome. É usado para integrar o Swagger 2. Através da meta -anotação: @import ({swagger2DocumentationConfiguration.class}), introduziu um swagger2DocumentationConfiguration Type Configuration Bean, e esta é a configuração principal da swagger. O código dentro é o seguinte:
@Configuration@import ({springfoxwebmvcconfiguration.class, swaggercommonConfiguration.class})@componentsCan (BasEpackages = {"springfox.documentation.swagger2.readers.parameter", "springfox.documentation.swagger.wagger2.wager2.wagerners.parameter", springfox.documentation.swagger.wagger2.wager2.wagers.parameter ", springfox.documentation.swagger2.wagger2.wager. "springfox.documentation.swagger2.mappers"}) publicClassSwagger2DocumentationConfiguration {@Bean public JacksonModuleReGistrar swagger2module () {returnNewswagger2jacksonModule (); }}Este cabeçalho de classe usa algumas anotações e depois apresenta a classe SpringfoxwebmvcConfiguration e a classe SwaggerCommonConfiguration e digitaliza automaticamente os grãos relacionados ao Springfox .swagger2 no contexto da primavera através da anotação dos componentes. Aqui, o que mais me interessa é a classe SpringfoxwebmvcConfiguration. Eu acho que essa classe deve ser a configuração mais central do MVC integrado Springfox. Clique e veja o seguinte código:
@Configuration@import ({ModelsConfiguration.class})@componentsCan (BasePackages = { "springfox.documentation.spring.web.nscanners", "springfox.documentation.spring.web.readers.operation", "springfox.documentation.spring.web.readers.operation", "springfox.documentation.spring.parameter", "springfox.documentation.spring.web.plugins", "springfox.documentation.spring.web.paths"})@enableplugInGistries ({{ DocumentationPlugin.class, ApilistingBuilderPlugin.class, OperaçãoBuilderPlugin.class, ParameterBuilderplugin.class, ExpandedParameterBuilderplugin.Class, RecursoGroPoustrategy.Class, OperationModelsProvidarplugin.Class, DefraGuPRanderPrateply.Cllass, OperationModelsProvidarplugin.Class, DefultCoRoupPiderPrateply, PathDecorator.class}) publicClassSPRINGFOXWEBMVCCONFIGURAÇÃO {}O código a seguir nesta classe nada mais é do que adicionar alguns grãos novos através da anotação @Bean. Não estou muito interessado nisso. O que mais me interessa é as coisas adicionadas à cabeça nos @enablepluginRecirs. O Springfox é baseado no mecanismo de plug de primavera para integrar Swagger. Como o Spring-Plug é implementado? Ainda não tenho tempo para estudar o princípio do Spring-Plug. Mas abaixo, vou mencionar que escrevo um plug -in para estender a funcionalidade do Swagger. O plugue adicionado acima através do @EnablePlugInRegistries ainda não está disponível. Os códigos que eu vi incluem principalmente apilistingbuilderplugin.class, OperationBuilderplugin.class, parameterbuilderplugin.class, expandidaParameterBuilderplugin.class, expandirParameterBuilderplugin.class,
O primeiro ApilistingBuilderPlugin, que possui duas classes de implementação, a saber, o ApilistingReader e o SwaggerApilistingReader. Entre eles, o ApilistingReader gerará automaticamente uma lista de API de acordo com o tipo de controlador, e o SwaggerApilistingReader gerará uma lista de API de acordo com a classe identificada pela anotação @API. O plug -in OperaçãoBuilderPlugin é usado para gerar documentos API específicos. Esse tipo de plug -in possui muitas classes de implementação. Cada um deles divide seu trabalho e faz suas próprias coisas. Não olhei para os detalhes com cuidado, mas apenas focei em uma das classes de implementação: OperationParameterReader. Esta classe é um plug -in usado para ler os parâmetros da API. Ele depende da classe de ferramentas ModelAttributEParameTerexpander, que pode analisar automaticamente objetos de comando do tipo não simples nos parâmetros do método da interface no controlador para obter uma lista de parâmetros que contém todos os atributos (há um poço aqui que pode causar informações infinitas, introduzidas abaixo). O plug-in expandido do PARAMETERBUILDERPLUGIN é usado principalmente para estender algumas funções dos parâmetros de interface, como determinar o tipo de dados desse parâmetro e se é um parâmetro necessário para essa interface, etc. No geral, todo o springfox-Swagger é realmente transportado por esta série de plugues. Quando o sistema é iniciado, eles são sintonizados, alguns são usados para digitalizar a lista de interface, alguns são usados para ler parâmetros de interface, etc. Seu objetivo comum é digitalizar todas as interfaces da API no sistema e armazená -las para os usuários visualizarem. Então, como esta série de plugues de tabela são ajustados e onde estão suas entradas de execução?
Colocamos nosso ponto de atenção no conteúdo da anotação do componente no cabeçalho do código da classe SpringfoxwebmvcConfiguration acima. Nesta anotação, um pacote chamado springfox.documentation.spring.web.plugins é digitalizado. Este pacote pode ser encontrado no Springfox-Spring-Web-2.6.1.jar. Sob este pacote, descobrimos que existem duas classes muito importantes, a saber, documentationpluginsmanager e documentationpluginsbootstrapper. Para a primeira documentação PLUGINSMANAGER, é um feijão que não implementa nenhuma interface, mas possui muitas propriedades do tipo de plug -segistry, e todas elas são injetadas no valor da propriedade através da anotação @Autowired. Combinando seu nome de classe, é fácil pensar que este é um gerente que gerencia todos os plugues. É fácil de entender, devido à configuração da anotação dos componentes, todas as instâncias de plug serão instantadas em um feijão na primavera e depois injetadas nesta instância DocumentationPluginsManager e gerenciadas uniformemente. Outra classe importante neste pacote DocumentationPluginsBootStrapper, você pode adivinhar, olhando para o nome, pode ser a classe de inicialização do plug. Quando você clica e observa os detalhes, você descobrirá que é realmente um componente identificado pelo @Component, e seu método de construção injeta a instância DocumentationPluginsManager que acaba de descrever, e o mais crítico é que ele também implementa a interface SmartLifecycle. Quem conhece o ciclo de vida dos grãos de primavera sabe que quando esse componente é instanciado em um feijão e é gerenciado no contexto de Srping, seu método Start () será chamado automaticamente. Quando você clica em Start () para olhar para o código, você descobrirá que ele possui uma linha de escandocumentação de código (BuildContext (cada)); que é usado para digitalizar documentos da API. Ao rastrear ainda mais o código deste método, você pode descobrir que esse método acabará por usar sua propriedade DocumentationPluginsManager para ajustar todos os plugues para digitalizar todo o sistema e gerar documentos da API. Os resultados da varredura são armazenados em cache em uma propriedade de mapa da classe DocumentationCache.
O exposto acima é o princípio geral do SRPINGMVC integrando Springfox. Injeta principalmente uma série de feijões no contexto de Srping através da anotação EnablesWagger2 e digitaliza automaticamente a classe de controlador do sistema quando o sistema inicia, gera informações de API correspondentes e armazenam em cache. Além disso, ele injeta algumas classes de controlador identificadas pela Anotação @Controller como a entrada do módulo da interface do usuário para acessar a lista de API. Por exemplo, a classe Swagger2Controller no pacote Springfox-Swagger2-2.6.1.jar. Este controlador é o endereço de interface usado no módulo da interface do usuário para acessar a lista de API. Quando você visita o endereço http://127.0.0.1:8080/jaddemo/swagger-ui.html para visualizar a lista de APIs, você pode ver através do navegador que ele está obtendo assíncrono http://127.0.0.1:8080/jaddemo/v2/api-docs?group=sysGroup e exibindo-o na interface. A entrada do controlador correspondente ao plano de fundo deste endereço é a classe Swagger2Controller acima. Depois de receber a solicitação, esta classe busca diretamente as informações da API do cache que foi inicializado com antecedência para gerar um retorno de string json.
Depois de entender os princípios do Springfox, vamos dar uma olhada em que armadilhas que encontrei durante o uso do Springfox.
O primeiro grande poço do Springfox: o feijão gerado pela classe de configuração deve compartilhar o mesmo contexto que o Spring MVC.
Como descrito acima, no projeto Springmvc, a integração do Springfox é apenas para escrever uma classe de configuração simples, como segue sem nenhum código comercial no projeto.
@Configuration@EnableWebmvc@enablewagger2publicClass apiconfig {}Devido à anotação @Configuration, a Spring o instanciará automaticamente em um feijão e o injetará no contexto. Mas uma armadilha a ser observada é que o contexto em que esse feijão deve estar no mesmo contexto que o MVC da primavera. Como entender? Como nos projetos reais do MVC da primavera, geralmente existem dois contextos, um está seguindo o contexto e o outro é o Spring MVC (é um subcontexto que segue o contexto). O contexto é o ouvinte org.springframework.web.context.request.requestContextListener relacionado à primavera no arquivo web.xml. O contexto carregado é geralmente escrito como um arquivo de configuração chamado spring content.xml. Os grãos aqui serão inicializados no contexto. Inclui principalmente serviço, DAO e outros feijões no sistema, bem como fontes de dados, coisas etc. Outro contexto é o Spring MVC, que é carregado através do org.springframework.web.servlet.dispatherServlet relacionado ao mvc spring no web.xml. Geralmente possui um arquivo de configuração chamado spring-mvc.xml. Ao gravar a classe Apiconfig, se decidirmos carregá-la com a anotação @Configuration, devemos garantir que o caminho dessa classe esteja dentro do escopo da pacote básico da configuração de scan do componente no Springmvc. Porque quando o Apiconfig é carregado pela primavera, uma série de feijões será injetada. Nesses feijões, para digitalizar automaticamente todas as classes de controlador, alguns grãos precisam confiar em alguns feijões no SpringMVC. Se o projeto separar o contexto do srpingMVC do contexto como um subcontexto do contexto. Se você acidentalmente deixar esse tipo de apiconfig ser carregado com o texto anterior, porque não há classes de configuração no contexto do MVC da primavera no contexto raiz.
Na verdade, não concordo em configurar o Swagger através da anotação @Configuration, porque acho que a funcionalidade da API da Swagger é opcional para projetos de produção. Nossa arrogância é frequentemente usada para testar ambientes para o desenvolvimento de equipes de front-end do projeto ou para outros sistemas para integrar interfaces. Uma vez que o sistema estiver online, é provável que essas listas de API estejam ocultas no sistema de produção. Mas se a configuração for gravada no código Java através da anotação @Configuration, quando você deseja remover essa função quando estiver on -line, será embaraçoso e você precisará modificar o código Java para recompilar. Com base nisso, recomendo um método para configurar o arquivo XML mais tradicional pela primavera. O método específico é remover a anotação @Configuration e, em seguida, grava uma configuração de feijão semelhante a <bean/> no arquivo de configuração XML da primavera. Em um projeto em que o contexto raiz é separado do contexto do MVC, ele é configurado diretamente no spring-mvc.xml, o que garante que ele deve estar no mesmo contexto do contexto Springmvc.
O segundo maior poço de Springfox: os parâmetros da classe do controlador, preste atenção para evitar a recursão infinita.
O Spring MVC possui um poderoso mecanismo de ligação de parâmetros, que pode vincular automaticamente parâmetros de solicitação a um objeto de comando personalizado. Portanto, para ser preguiçoso, muitos desenvolvedores usam diretamente um objeto de entidade como um parâmetro do método do controlador ao escrever um controlador. Por exemplo, o código de exemplo a seguir:
@RequestMapping (value = "update") public string update (menuvomenuvo, modelo modelo) {}Este é o código que a maioria dos programadores gosta de escrever no controlador para modificar uma entidade. Ao integrar com Swagger, há um grande poço aqui. Se todas as propriedades do Menuvo são tipos básicos, tudo bem, nada dá errado. Mas se houver outros atributos de tipo personalizado nesta classe, e esse atributo existe direta ou indiretamente, existe atributos de seu próprio tipo, haverá problemas. Por exemplo: se a classe Menuvo for uma aula de menu, também contém um pai da propriedade do tipo Menuvo que representa seu menu pai. Dessa forma, o módulo Swagger relatará diretamente um erro quando o sistema iniciar porque não pode carregar a API. O motivo do erro é que, ao carregar esse método, os parâmetros do método de atualização serão analisados. Quando o parâmetro Menuvo não é um tipo simples, todos os atributos de sua classe serão interpretados automaticamente recursivamente. Isso facilita a queda em um laço morto de recursão infinita.
Para resolver esse problema, acabei de escrever uma classe de implementação de plug-in da OperationParameterReader e a classe de ferramentas ModelAttributEParameTerexpander de que depende. Ele substitui as duas classes originais do SrpingFox por meio da configuração, substitui a lógica de analisar a análise de parâmetros como uma coluna e evita a recursão infinita. Obviamente, isso é equivalente a uma maneira de modificar o nível do código -fonte. Ainda não encontrei uma solução mais perfeita para esse problema, então só posso recomendar que você tente evitar essa recursão infinita ao usar o Spring-Fox Swagger. Afinal, isso não cumpre as especificações dos objetos de comando Springmvc. Os objetos de comando com o parâmetro Springmvc são preferencialmente atributos de tipo básico simples.
O terceiro grande poço de Springfox: Relacionado ao agrupamento da API, instâncias de documento não podem ser carregadas latentemente
O Springfox dividirá todas as APIs em um grupo por padrão. Quando acessado através de um endereço semelhante a http://127.0.0.1:8080/jaddemo/swagger-ui.html, todas as listas de API serão carregadas na mesma página. Dessa forma, se o sistema for um pouco maior e a API for um pouco mais, a página será falsa até a morte, por isso é muito necessário agrupar a API. O agrupamento da API é definido pela anotação @Bean no arquivo de configuração do Apiconf. As configurações comuns na Internet são as seguintes:
@Enablewebmvc@enablewagger2publicclass apiconfig {@bean public docket customDocket () {return newdocket (documentationType.swagger_2) .apiinfo (apiinfo ()); }}No código acima, um registro é injetado através do @Bean. Esta configuração não é necessária. Se essa configuração não estiver disponível, a estrutura gerará uma instância de boletim padrão por si só. O objetivo desta instância de registro é especificar as informações públicas de todas as APIs que ele pode gerenciar, como informações básicas como versão da API, autor etc. e especificar quais APIs estão listadas apenas (filtradas por endereços ou anotações da API).
Pode haver várias instâncias de registro, como o seguinte código:
@Enablewebmvc@enableswagger2publicClass apiconfig {@Bean public Docket CustomDocket1 () {return newDocket (documentationType.swagger_2) .groupName ("apigroup1"). Apiinfo (apiinfo (). Select (). } @Bean public Docket CustomDocket2 () {Return newDocket (documentationType.swagger_2) .groupName ("APIGROUP2"). Apiinfo (apiinfo ()). SElect (). Paths (PathSelectors.ant ("/shop/**")); }}Quando várias instâncias de registro são configuradas no projeto, a API pode ser agrupada, por exemplo, o código acima divide a API em dois grupos. Nesse caso, cada grupo deve receber um nome diferente, como "Apigroup1" e "Apigroup2" no código acima. Cada grupo pode usar os caminhos para especificar qual grupo gerenciar quais APIs através da expressão de endereço de formigas. Por exemplo, na configuração acima, o primeiro grupo de endereços de gerenciamento são APIs com o início de /sys /. O segundo grupo de APIs de gerenciamento com o início de /shop /. Obviamente, existem muitos outros métodos de filtragem, como anotação de classe, anotação de métodos, endereços de expressões regulares etc. Após o agrupamento, você pode selecionar diferentes grupos de API na opção suspensa no canto superior direito da interface da lista de API. Isso dispersará a lista de API do projeto para diferentes páginas. Isso facilitará o gerenciamento sem fingir estar morto porque a página precisa carregar muitas APIs.
No entanto, como usar o @configuration, não concordo em usar o @Bean para configurar instâncias de registro para agrupar as APIs. Por esse motivo, o código também será escrito até a morte. Então, eu recomendo configurar sua própria instância de documento no arquivo XML para implementar essas funções semelhantes. Obviamente, considerando os muitos atributos no documento, é mais problemático configurar diretamente os feijões. Você pode escrever um FactoryBean para o registro e configurar o FactoryBean no arquivo XML. No entanto, ao configurar o Docket em XML. Você encontrará outro grande poço, ou seja, o método de carregamento de mola no feijão é preguiçoso carregado por padrão. Depois de configurar diretamente esses feijões de instância no XML. Você descobrirá que não há efeito e não há item de agrupamento na lista suspensa no canto superior esquerdo da página.
Esse problema me incomodou por várias horas. Posteriormente, com base na experiência, especulou -se que pode ser porque o feijão da mola é um carregamento preguiçoso por padrão, e essa instância de boletim não foi carregada no contexto da mola. Como se vê, meu palpite está correto. Não sei se isso é um bug no Springfox, ou se eu não deveria ter movido a configuração de boletim do código Java original para o arquivo de configuração XML.
Outras armadilhas em Springfox: Existem outras armadilhas em Springfox. Por exemplo, na anotação @apioperation, se o atributo httpmethod não for especificado como um determinado método GET ou POST, todos os métodos como GET, POST, excluir, colocar serão listados na lista de APIs, para que a lista de API seja duplicada demais, o que é muito feio. Além disso, durante os testes, encontrei problemas de permissão de login, etc. Essas pilhas de pequenos poços que são mais fáceis de resolver, por causa do espaço limitado, não vou dizer muito. Há também o uso de anotações como @api, @apioperation e @apiparam. Não vou repetir muitos documentos sobre isso online.
O exposto acima é todo o conteúdo deste artigo. Espero que seja útil para o aprendizado de todos e espero que todos apoiem mais o wulin.com.