最近自己写了一个发送http请求的组件,整个发送请求的实现是用的Okhttp,只是基于Okhttp基础上做了再次封装,使用起来和mybatis一样,只需要编写接口即可,业务层就可以直接调用,并且可以和spring集成。可以用于调用第三方API或者爬虫。
maven依赖
<dependency>
<groupId>com.github.zw201913</groupId>
<artifactId>simple-http</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
github地址:simple-http
springboot集成
1.下面来直接看看怎么和springboot集成:
import com.github.zw201913.simplehttp.annotation.EnableSimpleHttp;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//开启SimpleHttp
@EnableSimpleHttp
@SpringBootApplication
public class SimpleHttpApplication {
public static void main(String[] args) {
SpringApplication.run(SimpleHttpApplication.class, args);
}
}
开启SimpleHttp后,我们就先来使用它访问一下http://www.baidu.com试试:
@SimpleHttpService
public interface SimpleHttp {
/**
* 发送get请求访问http://www.baidu.com
* @return
*/
@Get("http://www.baidu.com")
String baidu();
}
接下来,我们就可以调用这个接口使用了:
@Service
public class TestService {
// 在spring中使用SimpleHttp
@Autowired private SimpleHttp simpleHttp;
public String baidu() {
return simpleHttp.baidu();
}
}
看到这里,就应该很明白了,我们的重点就在于如何编写SimpleHttp接口(ps:接口名称可以自己随便取)。
//如果想要url作为参数传入
@Get
String list(@Url String url);
//传入一个参数为id的字段
@Get
String find(@Url String url, @Field("id") Integer id);
//需要设置请求头的
@Get
String find(@Url String url, @Field("id") Integer id, @Header("Content-Type") String contentType);
//多个参数和请求头设置
@Get
String find(@Url String url, @Field Map<String, Object> params, @Header Map<String, String> headers);
如果是自定义对象:
//@Data是lombok的注解,可以避免手写get,set方法
// 请求参数实体类
@Data
public class PageParam {
private String search;
private int page;
private int size;
}
// 请求头实体类
@Data
public class RequestHeader {
private String cookie;
private String userAgent;
private String host;
}
@Get
String find(@Url String url, @Field PageParam params, @Header RequestHeader headers);
如果实体类中字段名称和实际请求名称不同:
// 请求参数实体类
@Data
public class PageParam {
@Field("name")
private String search;
private int page;
private int size;
}
// 请求头实体类
@Data
public class RequestHeader {
private String cookie;
@Header("User-Agent")
private String userAgent;
private String host;
}
你甚至还可以这样写:
@Data
public class PageParamAndRequestHeader {
@Field("name")
private String search;
@Field
private int page;
@Field
private int size;
@Header
private String cookie;
@Header("User-Agent")
private String userAgent;
@Header
private String host;
}
// 至于下面方法的参数修饰到底是使用@Field 还是@Header ,那就看你的心情了
@Get
String find(@Url String url, @Field PageParamAndRequestHeader paramsAndHeaders);
当然,除了Get请求,还有Post,Put,Delete,Patch......还有WebSocket
上传一个文件并且带参数:
// 带一个文件上传的,对应spring mvc里面的
// public User add(@RequestPart("user") User user, @RequestPart("image") MultipartFile[] image)
@Post
String add(@Url String url, @Field("user") Map<String, Object> user, @Field("image") File file);
// 和上面接口一样,只不过把Map改成了自定义的User
@Post
String add(@Url String url, @Field("user") User user, @Field("image") File file);
如果一个文件不够的话:
// 对应的服务端接口:
// public User add(@RequestPart("user") User user, @RequestPart("image1") MultipartFile[] image1, @RequestPart("image2") MultipartFile[] image2)
@Post
String add(@Url String url, @Field("user") User user, @Field("image1") File[] file, @Field("image2") File[] file);
以上接口,除文件外,参数也是一样可以多个的,使用方法同文件类似。
如果不需要上传文件,并且服务端是@RequestBody:
// 默认是对应服务端的@RequestBody,且格式化方式是JSON
// 如果发现有File或File[]参数,会自动对应@RequestPart,且携带的其他参数格式化方式是JSON
// 对应服务端接口
// public User add(@RequestBody User user)
@Post
String add(@Url String url, @Field User user);
// 同上
@Post
String add(@Url String url, @Field Map<String,Object> user);
如果需要监听文件上传进度怎么办?
import com.github.zw201913.simplehttp.core.http.ProgressListener;
// 添加ProgressListener上传进度监听器
@Post
String add(
@Field("user") User user,
@Field("image1") File[] file1,
@Field("image2") File[] file2, ProgressListener progressListener);
只要在参数中传一个进度监听器对象,即可获取当前进度,例如:
ProgressListener progressListener = (totalLength, currentLength) -> {
int progress = (int) (100 * currentLength / totalLength);
System.out.println(progress + "%");
}
当然,只有文件上传会有进度条。
你或许还需要发送异步请求:
import okhttp3.Callback;
// 添加异步回调Callback对象,这个时候方法就不需要返回值了
@Post
void add(@Url String url, @Field User user, Callback callback);
例如:
Callback callback = new Callback() {
@Override
public void onFailure(Call call, IOException e) {}
@Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
String result = response.body().string();
System.out.println(result);
}
}
})
很大一种可能,你发送的请求要求的数据格式不是JSON,可能是XML或是别的数据格式
public interface RequestParamsHandler {
String JSON_UTF8 = "application/json;charset=utf-8";
/**
* 处理请求参数
*
* @param params
* @param files
*/
RequestBody handle(Map<String, Object> params, Map<String, File[]> files);
}
例如需要将请求参数转换为XML格式,我们只需要实现自定义的RequestParamsHandler:
public class XMLRequestParamsHandler implements RequestParamsHandler {
@Override
public RequestBody handle(Map<String, Object> params, Map<String, File[]> files) {
//实现将params转换成XML格式,并且返回一个RequestBody对象
return null;
}
}
@Post(handler = XMLRequestParamsHandler.class)
String add(@Url String url, @Field User user)
这样的话,我们就可以发送数据格式化要求是XML的请求了。
除了请求参数可以自定义处理,我们还会希望返回结果也能自定义
目前默认的返回结果可以是void,String,Response,这三种返回结果程序会自动处理,不需要任何特殊设置。如果需要除此以外的返回类型,需要自定义ResponseHandler
public interface ResponseHandler {
/**
* 处理响应对象
*
* @param response
* @param <T>
* @return
*/
<T> T handle(Response response);
}
public class MyResponseHandler implements ResponseHandler {
@Override
public User handle(Response response) {
//处理Response,将返回数据转换成指定对象
return new User();
}
}
@Post
User add(@Url String url, @Field User user, ResponseHandler responseHandler)
如果想要自定义OkHttpClient,可以实现BaseOkHttpClientFactory:
public abstract class BaseOkHttpClientFactory {
/** final是为了保持单例 */
private final OkHttpClient client;
public BaseOkHttpClientFactory() {
this.client = httpClient();
}
/**
* 留给子类实现
*
* @return
*/
protected abstract OkHttpClient httpClient();
/**
* 获取创建好的OkHttpClient
*
* @return
*/
public OkHttpClient okHttpClient() {
return this.client;
}
}
public class DefaultOkHttpClientFactory extends BaseOkHttpClientFactory {
@Override
protected OkHttpClient httpClient() {
return new OkHttpClient();
}
}
上面是组件默认的。为什么要自定义OkHttpClient,是为了实现例如Https或者请求代理。
public class HttpProxyOkHttpClientFactory extends BaseOkHttpClientFactory {
@Override
protected OkHttpClient httpClient() {
OkHttpClient client = new OkHttpClient();
// 实现请求代理
return client;
}
}
@Post(clientFactory = HttpProxyOkHttpClientFactory.class)
String add(@Url String url, @Field User user);
最后,还有WebSocket:
import okhttp3.WebSocketListener;
// 创建WebSocket,url是ws://echo.websocket.org
@Ws("ws://echo.websocket.org")
WebSocket newWebSocket(WebSocketListener listener);
// 自定义url创建WebSocket
@Ws
WebSocket newWebSocket(@Url String url, WebSocketListener listener);
spring集成
其实simple-http和mybatis一样完全可以脱离spring框架单独允许:
public class DefaultHttpServiceFactory implements HttpServiceFactory {
/** 缓存代理对象 */
private static final Map<Class<?>, Object> proxyCache = Maps.newConcurrentMap();
/**
* 获取代理对象
*
* @param type
* @param <T>
* @return
*/
@Override
public <T> T getSimpleHttpService(Class<T> type) {
return cacheProxy(type);
}
/**
* 缓存代理对象
*
* @param type
* @param <T>
* @return
*/
private <T> T cacheProxy(Class<T> type) {
T proxy = (T) proxyCache.get(type);
if (Objects.isNull(proxy)) {
proxy = new HttpProxyFactory<>(type).newInstance();
proxyCache.put(type, proxy);
}
return proxy;
}
}
public interface SimpleHttp {
/**
* 发送get请求访问http://www.baidu.com
* @return
*/
@Get("http://www.baidu.com")
String baidu();
}
public class TestSimpleHttp {
private DefaultHttpServiceFactory factory = new DefaultHttpServiceFactory();
public static void main(String[] args) {
SimpleHttp simpleHttp = factory.getSimpleHttpService(SimpleHttp.class)
return simpleHttp.baidu();
}
}
根据上述案例,要和spring集成,我们只需要将DefaultHttpServiceFactory注入到spring的IOC容器中,无论是@Bean的方式还是XML配置:
import com.github.zw201913.simplehttp.core.DefaultHttpServiceFactory;
@Bean
public HttpServiceFactory httpServiceFactory(){
return new DefaultHttpServiceFactory();
}
或者
<bean id="httpServiceFactory" class="com.github.zw201913.simplehttp.core.DefaultHttpServiceFactory">
</bean>
使用方式:
@Service
public class TestService {
@Autowired
private DefaultHttpServiceFactory factory;
public String baidu() {
SimpleHttp simpleHttp = factory.getSimpleHttpService(SimpleHttp.class)
return simpleHttp.baidu();
}
}
以上就是Simple-http的简单使用。
网友评论