README.md
    Fn
    

    Fn Apache2.0
    Maven

    介绍

    开放接口封装 的 spring boot starter,这个starter是为了方便将开放接口进行封装并提供给外部调用。 以注解方式进行快速封装,并且支持丰富的自定义扩展。 点击查看使用案例

    兼容性
    version spring boot version java version
    2.0.2 2.6.2 1.8
    maven
    <dependency>
        <groupId>cn.fntop</groupId>
        <artifactId>open-api-spring-boot-starter</artifactId>
        <version>2.0.2</version>
    </dependency>
    gradle
    //方式1
    implementation 'cn.fntop:open-api-spring-boot-starter:2.0.2'
    //方式2
    implementation group: 'cn.fntop', name: 'open-api-spring-boot-starter', version: '2.0.2'

    友善提示

    img.png

    配置

    
    fn:
    #接口网关,域名+your-context,如果没有context就不用加context,尾部一定要加上`/`
      open-gateway: http://xxx.com/your-context/ 
      #代理
      proxy-domain: xxx
      proxy-port: xxx

    配置说明

    配置项 默认值 说明
    fn.open-gateway http://xxx.com/your-context/ 接口调用网关,默认http://127.0.0.1:8080/。末尾一定要加"/"
    fn.proxy-domain 127.0.0.1 代理主机
    fn.proxy-port 38672 代理端口

    默认调用

    添加依赖项后自动注入OpenApiService即可

    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    @Service
    @RequiredArgsConstructor
    public class Demo {
        private final OpenApiService openApiService;
    }
    
    //或者
    @Service
    public class Demo {
        @Autowired
        private OpenApiService openApiService;
        public Object method1(){
            //参数为接口地址
            openApiService.get("hello/custom");
        }
    }
    //OpenApiService 默认封装的接口,如需扩展继续往下阅读
    public interface OpenApi {
        //更多注解的使用方式请参考注解附录大纲
        @HTTP(method = "GET")
        Single<Object> get(@Url String suffix);
    
        @HTTP(method = "GET")
        Single<Object> get(@Url String suffix, @Path(value = "name") String name);
    
        @HTTP(method = "GET")
        Single<Object> get(@Url String suffix, @Query(value = "query") String query, boolean isQuery);
    
        @HTTP(method = "POST", hasBody = true)
        Single<Object> post(@Url String suffix, @Body Object object);
    
        @Multipart
        @HTTP(method = "POST", hasBody = true)
        Single<Object> post(@Url String suffix,  @Query(value = "folder") String folder, @Part MultipartBody.Part... file);
    
    }
    

    自定义扩展

    1、自定义配置

    @Configuration
    @RequiredArgsConstructor
    public class CustomConfig {
        private final OpenApiProperties properties;
        @Bean
        public CustomOpenApiService customOpenApiService() {
            return (CustomOpenApiService) CustomOpenApiService.getInstance(properties, CustomOpenApi.class, CustomOpenApiService.class);
        }
    }

    2、自定义开放接口 extends OpenApi

    public interface CustomOpenApi extends OpenApi {
        @GET("hello/custom")
        Single<Object> callCustom();
    }

    3、自定义Service extends OpenApiService , 继承后可沿用OpenApiService默认方法

    public class CustomOpenApiService extends OpenApiService {
        private CustomOpenApi api;
        public CustomOpenApiService() {
            this.api = (CustomOpenApi) OpenApiService.api;
        }
        public Object callCustom() {
            return execute(api.callCustom());
        }
    }

    4、写好工具类后发布到私服。第三方调用直接通过依赖你发布到私服的jar包并通过Spring注入你自定义的customOpenApiService即可调用。

    @Service
    @RequiredArgsConstructor
    public class Demo {
        private final CustomOpenApiService customOpenApiService;
    }
    

    多Service

    CustomConfig定义多个@Bean,新增OpenApi子类和OpenApiService子类

    @Configuration
    @RequiredArgsConstructor
    public class CustomConfig {
        private final OpenApiProperties properties;
        @Bean
        public CustomOpenApiService customOpenApiService() {
            return (CustomOpenApiService) CustomOpenApiService.getInstance(properties, CustomOpenApi.class, CustomOpenApiService.class);
        }
        @Bean
        public OtherOpenApiService otherOpenApiService() {
            return (OtherOpenApiService) OtherOpenApiService.getInstance(properties, OtherOpenApi.class, OtherOpenApiService.class);
        }
    }

    支持自动注入和上下文调用

    @Component
    @RequiredArgsConstructor
    public class ApiService {
        private final OpenApiService openApiService;
        private final CustomOpenApiService customOpenApiService;
        public Object callDefault() {
            return openApiService.get("hello/test");
        }
    
        public Object callCustom() {
            return customOpenApiService.callCustom();
        }
    
        public Object callOther() {
            return OpenApiContext.get(OtherOpenApiService.class).other();
        }
    }

    自定义实例

    @Bean
    public CustomOpenApiService customOpenApiService() {
        Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(properties.getProxyDomain(), properties.getProxyPort()));
        return (CustomOpenApiService) CustomOpenApiService.custom(properties, CustomOpenApi.class, CustomOpenApiService.class, null, null, proxy, null);
    }

    自定义序列化策略

    @Bean
    public CustomOpenApiService customOpenApiService() {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        mapper.setPropertyNamingStrategy(PropertyNamingStrategy.LOWER_CAMEL_CASE);
        return (CustomOpenApiService) CustomOpenApiService.custom(properties, CustomOpenApi.class, CustomOpenApiService.class, mapper);
    }

    支持多线程

    public class OtherOpenApiService extends OpenApiService {
        private OtherOpenApi api;
        public OtherOpenApiService() {
            this.api = (OtherOpenApi) OpenApiService.api;
        }
        public SmsResponse other(SmsRequest request) {
            //使用内部封装的多线程
            OtherOpenApiService.setExecutorService(Executors.newCachedThreadPool());
            OtherOpenApiService.setDefaultExecutorTimeout(500);
            OtherOpenApiService.setResponseTimeout(30);
            return execute(api.other(request));
        }
    }
    //也可以自己写个多线程。
    @SneakyThrows
    public SmsResponse other(SmsRequest request) {
        ExecutorService executor = Executors.newCachedThreadPool();
        SmsResponse response = executor.submit(() -> execute(api.other(request))).get(30, TimeUnit.SECONDS);
        try {
            //先停止接收任务,然后再等待一定的时间让所有的任务都执行完毕,如果超过了给定的时间,则立刻结束任务。
            executor.shutdown();
            if (!executor.awaitTermination(800, TimeUnit.MILLISECONDS)) {
                executor.shutdownNow();
            }
        } catch (InterruptedException e) {
            executor.shutdownNow();
        }
        return response;
    }
    

    注意事项

    1、只需要扩写CustomOpenApi接口和CustomOpenApiService接口即可,如果请求和响应是对象换成自定义的实体类即可

    2、返回的对象基本上是Single<T>或者Call<T>(用于stream) ,具体查看com.theokanning.openai.OpenApiService

    注解附录

    注解项 参数 描述与使用说明
    @GET(value = "") value为请求url 有两种方式如果请求url是 /xx/xx/{id},参数注解使用@Path,如果是/xx/xx?a=1,注解使用@Query
    @POST(value = "") value为请求url 参数使用@Body 参数为对象
    @HTTP(method = "POST", hasBody = true) method为请求方式,hasBody为TRUE时,请求方式只能是post,否则只能是get 动态url使用方式,第一个参数是Controller的动态url参数
    @HTTP(method = "POST", hasBody = true)
    Single post(@url String suffix, @Body Object object);

    更多注解说明参考如下

    
    Create an implementation of the API endpoints defined by the service interface.
    The relative path for a given method is obtained from an annotation on the method describing the request type. The built-in methods are GET, PUT, POST, PATCH, HEAD, DELETE and OPTIONS. You can use a custom HTTP method with @HTTP. For a dynamic URL, omit the path on the annotation and annotate the first parameter with @Url.
    Method parameters can be used to replace parts of the URL by annotating them with @Path. Replacement sections are denoted by an identifier surrounded by curly braces (e.g., "{foo}"). To add items to the query string of a URL use @Query.
    The body of a request is denoted by the @Body annotation. The object will be converted to request representation by one of the Converter.Factory instances. A RequestBody can also be used for a raw representation.
    Alternative request body formats are supported by method annotations and corresponding parameter annotations:
    @FormUrlEncoded - Form-encoded data with key-value pairs specified by the @Field parameter annotation.
    @Multipart - RFC 2388-compliant multipart data with parts specified by the @Part parameter annotation.
    Additional static headers can be added for an endpoint using the @Headers method annotation. For per-request control over a header annotate a parameter with @Header.
    By default, methods return a Call which represents the HTTP request. The generic parameter of the call is the response body type and will be converted by one of the Converter.Factory instances. ResponseBody can also be used for a raw representation. Void can be used if you do not care about the body contents.
    For example:
      public interface CategoryService {
        @POST("category/{cat}/")
        Call<List<Item>> categoryList(@Path("cat") String a, @Query("page") int b);
      }
    

    常见问题

    使用阿里云镜像无法拉取

    尝试如下代码,central没用的话改成*all试试

        <mirrors>	
    	    <mirror>
                <id>alimaven</id>
                <name>aliyun maven</name>
                <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
                <mirrorOf>central</mirrorOf>
            </mirror>
        </mirrors>

    更新说明

    2023-08-14

    • 废弃2.0.1版本调用自定义方法实现多线程的逻辑,替换为在Service层进行实现
    • 删除所有自定义方法custom方法中ExecutorService 参数
    • 2.0.1的多线程模式是可用的,但不能通过custom方法初始化,必须使用Service进行调用。

    2023-08-14

    • 优化封装逻辑
    • 支持多线程
    • 如果继承OpenApiService,可沿用其方法。如果继承 OpenApiServiceAbstract ,则为独立功能

    2023-08-10

    • 支持自定义序列化策略(解决1.2.0版本接口调用部分字段无法传递问题,1.2.0版本的字段序列化对象命名规则是app_id,如果命名成appId属性无法传递)
    • 对象序列化策略-- 2.0.0版本默认策略:PropertyNamingStrategy.LOWER_CAMEL_CASE (小写驼峰 》 appId) || 1.2.0以下版本默认策略:PropertyNamingStrategy.SNAKE_CASE (小写下划线 》 app_id)

    2023-08-04

    • 支持自定义实例

    2023-08-04

    • 支持多Service功能(无需添加@Primary)

    2023-08-03

    • 依赖 java1.8
    • 依赖 spring-boot2.6.2
    • 依赖 hutool-all5.8.11
    • 新增 get,post默认请求方法调用
    • 支持自定义接口扩展,只支持单Service配置(单个Service配置@Bean,还需要添加@Primary)

    项目简介

    一个轻量级企业接口封装SDK,以简单的方式提供接口给外部调用

    发行版本

    当前项目没有发行版本

    贡献者 1

    开发语言

    • Java 100.0 %