Forest 轻量级 HTTP 客户端开源项目

我要开发同款
匿名用户2018年03月30日
67阅读
开发技术Java
所属分类程序开发、网络工具包
授权协议MIT

作品详情

Forest是一个高层的、极简的轻量级HTTP调用API框架。相比于直接使用Httpclient您不再用写一大堆重复的代码了,而是像调用本地方法一样去发送HTTP请求。

文档和示例:

项目主页

中文文档

JavaDoc

Demo工程

Forest有哪些特性?以Httpclient和OkHttp为后端框架通过调用本地方法的方式去发送Http请求,实现了业务逻辑与Http协议之间的解耦因为针对第三方接口,所以不需要依赖SpringCloud和任何注册中心支持所有请求方法:GET,HEAD,OPTIONS,TRACE,POST,DELETE,PUT,PATCH支持文件上传和下载支持灵活的模板表达式支持拦截器处理请求的各个生命周期支持自定义注解支持OAuth2验证支持过滤器来过滤传入的数据基于注解、配置化的方式定义Http请求支持Spring和Springboot集成JSON字符串到Java对象的自动化解析XML文本到Java对象的自动化解析JSON、XML或其他类型转换器可以随意扩展和替换支持JSON转换框架:Fastjson,Jackson,Gson支持JAXB形式的XML转换可以通过OnSuccess和OnError接口参数实现请求结果的回调配置简单,一般只需要@Request一个注解就能完成绝大多数请求的定义支持异步请求调用极速开始以下例子基于SpringBoot

第一步:添加Maven依赖直接添加以下maven依赖即可

<dependency><groupId>com.dtflys.forest</groupId><artifactId>forest-spring-boot-starter</artifactId><version>1.5.0-RC7</version></dependency>第二步:创建一个interface就以高德地图API为栗子吧

packagecom.yoursite.client;importcom.dtflys.forest.annotation.Request;importcom.dtflys.forest.annotation.DataParam;publicinterfaceAmapClient{/***聪明的你一定看出来了@Get注解代表该方法专做GET请求*在url中的${0}代表引用第一个参数,${1}引用第二个参数*/@Get("https://ditu.amap.com/service/regeo?longitude=${0}&latitude=${1}")MapgetLocation(Stringlongitude,Stringlatitude);}第三步:扫描接口在SpringBoot的配置类或者启动类上加上@ForestScan注解,并在basePackages属性里填上远程接口的所在的包名

@SpringBootApplication@Configuration@ForestScan(basePackages="com.yoursite.client")publicclassMyApplication{publicstaticvoidmain(String[]args){SpringApplication.run(MyApplication.class,args);}}第四步:调用接口OK,我们可以愉快地调用接口了

//注入接口实例@AutowiredprivateAmapClientamapClient;...//调用接口Mapresult=amapClient.getLocation("121.475078","31.223577");System.out.println(result);发送JSON数据/***将对象参数解析为JSON字符串,并放在请求的Body进行传输*/@Post("/register")StringregisterUser(@JSONBodyMyUseruser);/***将Map类型参数解析为JSON字符串,并放在请求的Body进行传输*/@Post("/test/json")StringpostJsonMap(@JSONBodyMapmapObj);/***直接传入一个JSON字符串,并放在请求的Body进行传输*/@Post("/test/json")StringpostJsonText(@JSONBodyStringjsonText);发送XML数据/***将一个通过JAXB注解修饰过的类型对象解析为XML字符串*并放在请求的Body进行传输*/@Post("/message")StringsendXmlMessage(@XMLBodyMyMessagemessage);/***直接传入一个XML字符串,并放在请求的Body进行传输*/@Post("/test/xml")StringpostXmlBodyString(@XMLBodyStringxml);文件上传/***用@DataFile注解修饰要上传的参数对象*OnProgress参数为监听上传进度的回调函数*/@Post("/upload")Mapupload(@DataFile("file")StringfilePath,OnProgressonProgress);可以用一个方法加Lambda同时解决文件上传和上传的进度监听

Mapresult=myClient.upload("D:\\TestUpload\\xxx.jpg",progress->{System.out.println("progress:"+Math.round(progress.getRate()*100)+"%");//已上传百分比if(progress.isDone()){//是否上传完成System.out.println("--------UploadCompleted!--------");}});多文件批量上传/***上传Map包装的文件列表,其中${_key}代表Map中每一次迭代中的键值*/@Post("/upload")ForestRequest<Map>uploadByteArrayMap(@DataFile(value="file",fileName="${_key}")Map<String,byte[]>byteArrayMap);/***上传List包装的文件列表,其中${_index}代表每次迭代List的循环计数(从零开始计)*/@Post("/upload")ForestRequest<Map>uploadByteArrayList(@DataFile(value="file",fileName="test-img-${_index}.jpg")List<byte[]>byteArrayList);文件下载下载文件也是同样的简单

/***在方法上加上@DownloadFile注解*dir属性表示文件下载到哪个目录*OnProgress参数为监听上传进度的回调函数*${0}代表引用第一个参数*/@Get("https://localhost:8080/images/xxx.jpg")@DownloadFile(dir="${0}")FiledownloadFile(Stringdir,OnProgressonProgress);调用下载接口以及监听下载进度的代码如下:

Filefile=myClient.downloadFile("D:\\TestDownload",progress->{System.out.println("progress:"+Math.round(progress.getRate()*100)+"%");//已下载百分比if(progress.isDone()){//是否下载完成System.out.println("--------DownloadCompleted!--------");}});基本签名验证@Post("/hello/user?username=${username}")@BasicAuth(username="${username}",password="bar")Stringsend(@DataVariable("username")Stringusername);OAuth2.0@OAuth2(tokenUri="/auth/oauth/token",clientId="password",clientSecret="xxxxx-yyyyy-zzzzz",grantType=OAuth2.GrantType.PASSWORD,scope="any",username="root",password="xxxxxx")@Get("/test/data")StringgetData();自定义注解Forest允许您根据需要自行定义注解,不但让您可以简单优雅得解决各种需求,而且极大得扩展了Forest的能力。

定义一个注解/***用Forest自定义注解实现一个自定义的签名加密注解*凡用此接口修饰的方法或接口,其对应的所有请求都会执行自定义的签名加密过程*而自定义的签名加密过程,由这里的@MethodLifeCycle注解指定的生命周期类进行处理*可以将此注解用在接口类和方法上*/@Documented/**重点:@MethodLifeCycle注解指定该注解的生命周期类*/@MethodLifeCycle(MyAuthLifeCycle.class)@RequestAttributes@Retention(RetentionPolicy.RUNTIME)/**指定该注解可用于类上或方法上*/@Target({ElementType.TYPE,ElementType.METHOD})public@interfaceMyAuth{/***自定义注解的属性:用户名*所有自定注解的属性可以在生命周期类中被获取到*/Stringusername();/***自定义注解的属性:密码*所有自定注解的属性可以在生命周期类中被获取到*/Stringpassword();}定义注解生命周期类/***MyAuthLifeCycle为自定义的@MyAuth注解的生命周期类*因为@MyAuth是针对每个请求方法的,所以它实现自MethodAnnotationLifeCycle接口*MethodAnnotationLifeCycle接口带有泛型参数*第一个泛型参数是该生命周期类绑定的注解类型*第二个泛型参数为请求方法返回的数据类型,为了尽可能适应多的不同方法的返回类型,这里使用Object*/publicclassMyAuthLifeCycleimplementsMethodAnnotationLifeCycle<MyAuth,Object>{/***当方法调用时调用此方法,此时还没有执行请求发送*次方法可以获得请求对应的方法调用信息,以及动态传入的方法调用参数列表*/@OverridepublicvoidonInvokeMethod(ForestRequestrequest,ForestMethodmethod,Object[]args){System.out.println("InvokeMethod'"+method.getMethodName()+"'Arguments:"+args);}/***发送请求前执行此方法,同拦截器中的一样*/@OverridepublicbooleanbeforeExecute(ForestRequestrequest){//通过getAttribute方法获取自定义注解中的属性值//getAttribute第一个参数为request对象,第二个参数为自定义注解中的属性名Stringusername=(String)getAttribute(request,"username");Stringpassword=(String)getAttribute(request,"password");//使用Base64进行加密Stringbasic="MyAuth"+Base64Utils.encode("{"+username+":"+password+"}");//调用addHeader方法将加密结构加到请求头MyAuthorization中request.addHeader("MyAuthorization",basic);returntrue;}/***此方法在请求方法初始化的时候被调用*/@OverridepublicvoidonMethodInitialized(ForestMethodmethod,BasicAuthannotation){System.out.println("Method'"+method.getMethodName()+"'Initialized,Arguments:"+args);}}使用自定义的注解/***在请求接口上加上自定义的@MyAuth注解*注解的参数可以是字符串模板,通过方法调用的时候动态传入*也可以是写死的字符串*/@Get("/hello/user?username=${username}")@MyAuth(username="${username}",password="bar")Stringsend(@DataVariable("username")Stringusername);详细文档请看:https://forest.dtflyx.com/
声明:本文仅代表作者观点,不代表本站立场。如果侵犯到您的合法权益,请联系我们删除侵权资源!如果遇到资源链接失效,请您通过评论或工单的方式通知管理员。未经允许,不得转载,本站所有资源文章禁止商业使用运营!
下载安装【程序员客栈】APP
实时对接需求、及时收发消息、丰富的开放项目需求、随时随地查看项目状态

评论