Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/305.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swagger Codegen CLI Java客户端-如何正确使用它_Java_Rest_Swagger_Swagger 2.0_Swagger Codegen - Fatal编程技术网

Swagger Codegen CLI Java客户端-如何正确使用它

Swagger Codegen CLI Java客户端-如何正确使用它,java,rest,swagger,swagger-2.0,swagger-codegen,Java,Rest,Swagger,Swagger 2.0,Swagger Codegen,我现在正在玩我的球衣休息服务。为了更好地概述给定的服务(描述、类型等),我大量使用了swagger(swagger-jersey2-jaxrs)。 因此,我可以生成我的服务描述(swagger.json),并可以通过swagger用户界面查看和浏览它们 现在我需要创建一些客户机来使用这些服务。我遇到了swagger codegen cli,它是一个很好的工具,可以生成您的客户端和许多不同的语言(在我的例子中是java)。我能够生成api客户端和正在使用的模型 这里我面临第一个问题。REST服务和

我现在正在玩我的球衣休息服务。为了更好地概述给定的服务(描述、类型等),我大量使用了swagger(swagger-jersey2-jaxrs)。 因此,我可以生成我的服务描述(swagger.json),并可以通过swagger用户界面查看和浏览它们

现在我需要创建一些客户机来使用这些服务。我遇到了swagger codegen cli,它是一个很好的工具,可以生成您的客户端和许多不同的语言(在我的例子中是java)。我能够生成api客户端和正在使用的模型

这里我面临第一个问题。REST服务和swagger描述受http基本身份验证保护。我读了这篇文章,它给了我一些提示,说明有可能使用basicauth。在这一点上,我必须提到,从我的观点来看,文档非常糟糕。它说:

-a,-auth 远程获取招摇过市定义时添加授权标头。传入一个URL编码的字符串name:header,该字符串用逗号分隔多个值

我想到的第一件事是像在http头中一样传递一个字符串,但这不起作用,甚至在Google上搜索如何在swagger cli中使用basic auth也没有得到明确的答案。经过多次尝试和错误(我使用的是CLI 2.1.2),我终于找到了正确的格式:

java-jar swagger-codegen-cli-2.1.2.jar generate-a“授权:基本YWRtaW46YWRtaW4=“-i-l java-o restclient

其中YWRtaW46YWRtaW4=在我的例子中是admin:admin的base64编码值

到目前为止还不错。生成的java客户端还必须使用基本身份验证。我查看了ApiClient中的方法,找到了setUsername和setPassword。我认为这种方法使客户端能够使用基本的auth,但没有运气

因此,我深入研究了生成的类,特别是ApicClient和几个生成的ApisService类。 我发现setUsername和setPassword无效,原因如下:

/**
   * Helper method to set username for the first HTTP basic authentication.
   */
  public void setUsername(String username) {
    for (Authentication auth : authentications.values()) {
      if (auth instanceof HttpBasicAuth) {
        ((HttpBasicAuth) auth).setUsername(username);
        return;
      }
    }
    throw new RuntimeException("No HTTP basic authentication configured!");
  }
// Setup authentications (key: authentication name, value: authentication).
authentications = new HashMap<String, Authentication>();
// Prevent the authentications from being modified.
authentications = Collections.unmodifiableMap(authentications);
String[] authNames = new String[] {  };
String response = apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames);
其中,HashMap同时定义如下:

/**
   * Helper method to set username for the first HTTP basic authentication.
   */
  public void setUsername(String username) {
    for (Authentication auth : authentications.values()) {
      if (auth instanceof HttpBasicAuth) {
        ((HttpBasicAuth) auth).setUsername(username);
        return;
      }
    }
    throw new RuntimeException("No HTTP basic authentication configured!");
  }
// Setup authentications (key: authentication name, value: authentication).
authentications = new HashMap<String, Authentication>();
// Prevent the authentications from being modified.
authentications = Collections.unmodifiableMap(authentications);
String[] authNames = new String[] {  };
String response = apiClient.invokeAPI(path, "POST", queryParams, postBody, headerParams, formParams, accept, contentType, authNames);
3) 将auth对象添加到apiClients身份验证哈希映射:

ApiClient apiClient = new ApiClient();
apiClient.setBasePath(basePath);
apiClient.getAuthentications().put("basic", authentication);
4) 修改invokeApi方法(ApiClient.java)

另一种可能的解决方案是在每个API服务中定义authentications hashmap的密钥,如:

String[] authNames = new String[] { "basic" };
在做了所有的修改之后,一切都按照预期工作,但我认为这不是自动生成的rest客户机背后的想法。 所以我的问题是:我是否遗漏了一些要点,或者我是否应该将swagger生成的客户机(在本例中为java)看作是一个正在开发的测试版解决方案?
请告诉我,我认为整个swagger框架(jersey2支持、openapi、swaggerui、codegen)这是一件伟大的事情,我感谢开发人员的努力,但我想正确使用codegen,我不认为背后的想法是必须以这种方式自定义生成的ApiClient和ApiServices。

问题是您的规范没有提到您想要使用的安全类型(也称为安全定义)或者哪个安全定义适用于哪个端点

paths:
  /:
    get:
      security:
       - basic: []
      responses:
        200:
          description:  OK
招摇过市的规范是,但它并没有说明全部情况

你需要做的是1。设置安全性定义。下面是一个简单的基本http身份验证定义:

securityDefinitions:
  basic:
    type: basic
    description: HTTP Basic Authentication. 
二,。在端点中使用该安全性定义

paths:
  /:
    get:
      security:
       - basic: []
      responses:
        200:
          description:  OK

然后重新生成您的swagger客户端代码。它应该正确设置不可变映射和authNames数组。

如前所述,如果不想修改现有代码,可以在自定义配置中扩展
ApiClient
,例如

@Configuration
public class Config {

  @Value("${baseUrl}")
  private String baseUrl;

  protected class AuthApiClient extends ApiClient {

    public AuthApiClient() {
      super();
    }

    @Override
    public <T> T invokeAPI(final String path, final HttpMethod method,
            final MultiValueMap<String, String> queryParams, final Object body,
            final HttpHeaders headerParams, final MultiValueMap<String, Object> formParams,
            final List<MediaType> accept, final MediaType contentType,
            final String[] authNames, final ParameterizedTypeReference<T> returnType)
            throws RestClientException {

            final HttpBasicAuth auth = new HttpBasicAuth();
            auth.setUsername("myUsername");
            auth.setPassword("myPassword");
            auth.applyToParams(queryParams, headerParams);

      return super.invokeAPI(path, method, queryParams, body, headerParams, formParams,
                accept, contentType, authNames, returnType);
    }
  }

  @Bean
  @Primary
  @Qualifier("MyApiClient")
  public AuthApiClient myApiClient() {
    final AuthApiClient apiClient = new AuthApiClient();
    apiClient.setBasePath(this.baseUrl);
    return apiClient;
  }
}
@配置
公共类配置{
@值(“${baseUrl}”)
私有字符串baseUrl;
受保护的类AuthApiClient扩展了ApiClient{
公共授权客户端(){
超级();
}
@凌驾
public T invokeAPI(最终字符串路径,最终HttpMethod方法,
最终多值映射查询参数,最终对象体,
最终HttpHeaders headerParams,最终多值映射formParams,
最终列表接受,最终媒体类型contentType,
最终字符串[]身份验证名,最终参数化类型引用返回类型)
抛出RestClientException{
最终HttpBasicAuth auth=新的HttpBasicAuth();
auth.setUsername(“myUsername”);
验证设置密码(“我的密码”);
授权应用参数(查询参数、标题参数);
返回super.invokeAPI(路径、方法、queryParams、body、headerParams、formParams、,
accept、contentType、AuthName、returnType);
}
}
@豆子
@初级的
@限定词(“MyApiClient”)
公共授权客户端myApiClient(){
final AuthApiClient apiClient=新的AuthApiClient();
apiClient.setBasePath(this.baseUrl);
归还客户;
}
}

是,但执行此操作时,生成的代码不是线程安全的,这意味着每个请求只有一个用户名/密码。如果您将请求代理到另一个API,并且需要根据当前用户动态更改身份验证,则无法使用该API。。。如果
authentications
映射是可变的,那么您至少可以添加自己的类(实现身份验证接口)并以任何方式进行身份验证。e、 g:调用服务以获取当前用户用户名和密码,并生成要添加到请求中的BasicAuth头。添加您自己的身份验证类对我来说很好。你有一个如何做到这一点的例子吗?正如这里所建议的,我相信
APIClient
的生成器方法可以解决这个问题。现在,作为一个快速解决方法,我只是定制了小胡子模板,并删除了
authentications=Collections.unmodifiableMap(authentications)部分,然后在
映射身份验证中用我自己的身份验证实现替换基本身份验证实现