一、介绍

  • JDK-Timer,简单无门槛,Timer位于java.util包下,其内部包含且仅包含一个后台线程(TimeThread)对多个业务任务(TimeTask)进行定时定频率的调度。因此Timer存在管理并发任务的缺陷:所有任务都是由同一个线程来调度,所有任务都是串行执行,意味着同一时间只能有一个任务得到执行,而前一个任务的延迟或者异常会影响到之后的任务。 但在JDK5之后便提供了基于线程池的定时任务调度:ScheduledExecutorService。每一个被调度的任务都会被线程池中的一个线程去执行,因此任务可以并发执行,而且相互之间不受影响。

总结下Timer的缺点:

  1. Java定时器没有持久化机制,如果Timer抛出RuntimeException,那么Timer会停止所有任务的运行。
  2. Java定时器的日程管理不够灵活(只能设置开始时间、重复的间隔,设置特定的日期、时间等
  3. Java定时器没有使用线程池(每个Java定时器使用一个线程)
  4. Java定时器没有切实的管理方案,你不得不自己完成存储、组织、恢复任务的措施
  • Quartz,分布式集群开源工具,功能强大,可以让你的程序在指定时间执行,也可以按照某一个频度执行,支持数据库、监听器、插件、集群。相较于Timer,Quartz增加了很多功能:
  1. 持久性作业 - 就是保持调度定时的状态;
  2. 作业管理 - 对调度作业进行有效的管理;
  3. cron表达式 - 强大的调度配置,胜任适合复杂任务的调度;

缺点:

  1. Quartz是一个重量级框架,使用起来不方便,学习成本比Timer高。
  • spring-task,Spring3.0以后自主开发的定时任务工具,spring task,可以将它比作一个轻量级的Quartz,而且使用起来很简单,除spring相关的包外不需要额外的包。默认单线程串行同步执行,一个任务执行完上一次之后,才会执行下一次调度,多任务并行执行需要设置线程池 。

  • Spring Quartz,Spring对Quartz作了一个封装,默认多线程异步执行,一个任务在上一次调度未完成执行,下一次调度时间到时,会另起一个线程开始新的调度。在业务繁忙时。一个任务或许会有多个线程在执行,导致数据处理异常的情况,这样也根据需要是否可以开启单任务同步配置属性。如果是多个任务同时运行,任务之间没有直接的影响,多任务执行的快慢取决于CPU的性能。

  • 分布式调度框架比较

分布式调度框架比较

二、使用

  • spring-quartz的使用,其主要步骤如下:
0. 导入需要的jar包或添加依赖,主要有spring-context-support、spring-tx、quartz;

1. 编写被调度类和被调度方法,即需要定时执行的类和方法;

2. 在spring容器中注册被调度类,单个注册或包扫描均可;

3. 在spring容器中注册作业类(MethodInvokingjOBdetailFactoryBean),并注入被调度类和被调度方法,一般每个被调度方法需要注册一个作业类;

4. 在spring容器中注册触发器,并注入对应的作业类和触发条件,一般每个作业类需要注册一个触发器;触发器是用来指定被调度方法的执行时间的,根据触发条件的不同,有两个类可以选择:

(1) SimpleTriggerFactoryBean,只能指定间隔固定时长执行,例如每隔5秒钟执行一次;

(2) CronTriggerFactoryBean,既可以指定间隔固定时长执行,也可以指定某个或某几个时刻执行,例如每周三下午16点;

5. 在spring容器中注册调度工厂(ScheduerFactoryBean),并注入需要的触发器,可以注入一个或多个触发器。
  • spring-task的使用,其主要步骤如下:
1.在spring配置文件头中添加命名空间及描述

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:task="http://www.springframework.org/schema/task"
    。。。。。。
    xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd">

2. 开启Spring注解扫描,将Bean的创建交由Spring进行管理。用于创建Scheduler声明
<context:component-scan base-package="com.unben.scheduler" />
3. 创建TreadPoolTaskScheduler实例,并指定该线程池初始大小。
  <task:scheduler id="taskScheduler" pool-size="5" />
4. 如果使用注解方式则配置注解配置,如果使用xml配置则需要配置具体任务。
   方式1:开启SpringTask注解驱动。作用:识别Task相关注解,如“@Scheduled”
配置:<task:annotation-driven/>
代码:
    @Scheduled(cron = "0 0 3 * * ?")
    public void job1() {
        System.out.println(“任务进行中。。。”);
    }
   方式2:spring配置文件中设置具体的任务
     <task:scheduled-tasks>
        <task:scheduled ref="taskJob" method="job1" cron="0 * * * * ?"/>
    </task:scheduled-tasks>
注意:SpringTask的触发器实现方案有两种,一种是基于Cron表达式的CronTrigger触发器,方式是使用cron属性;另一种是基于接受固定周期的PeriodicTrigger触发器,方式是使用initial-delay、fixed-delay、fixed-rate属性。

三、参考资料

  1. 任务调度的方式:Timer、ScheduledExecutorService、spring task、quartz、XXL-JOB、Elastic-Job

  2. 分布式定时任务调度系统技术解决方案(xxl-job、Elastic-job、Saturn)

  3. cron表达式在线生成工具

  4. Quartz Spring与Spring Task总结

第一章 一个好点子出炉了
  • 凯恩斯的两套经济规律:微观层面(与个人及家庭生活相关)、宏观层面(与国家和政府相关)。凯恩斯的核心观点是在经济的不景气,通过扩大货币供给和财政赤字,来缓和自由市场的波动。

  • 经济学术语中,资本指的是一种设备,这种设备的建设和使用本身没有什么意义,其意义在于利用设备建设和制造其他需要的东西。

  • 努力是有限的资源(每种资源都是有限的)产生最大的效益以尽可能满足人类的需求,这就是经济这一概念最简单的定义。工具、资本以及创新是实现这一目标的关键。

  • 经济增长的原因:找到了生产人类所需物品的更好方式。不管一个经济体最后变得多么强大,这个原因是不会改变的。

第二章 把财富分享给别人
  • 需求只是刺激经济增长的必要而非充分条件。

  • 追求更多的是人类的本性。

  • 只有增加供给才能切实满足人们更多的需求。

第三章 信用卡的多种用途
  • 如果消费贷款不能提高产能的话,这笔贷款无论是对贷款人还是借款人来说都是一种负担。

  • 商业贷款并非社会储蓄的唯一选择,还可以选择其他贷款形式——消费贷款和应急贷款。

  • 贷款总额受到储蓄总量的制约。所以政府总是会通过各种形式干预储蓄配置,包括政府贷款担保、公司及个人税收减免以及税务罚款等,有了这些手段,个人与企业业务更愿意申请某些类型的贷款,而银行也更愿意批准这些类型的贷款。

第四章 经济到底是如何发展的
  • 只有当我们能够生产出额外的食物时,我们才有时间做其他事情。

  • 我们的消费不能长期超过产能,我们的借款不能超过存款,至少不能超期这样。

  • 储蓄不只是提高个人消费能力的手段,还是防止经济受到意外因素影响的重要缓冲器。

第五章 在鱼被指定为货币之后
  • 在一个经济体中,如果工人们有所分工,从事不同的商业和服务活动,其结果一定会比所有人都做同一种工作要好。分工增加产量,高产量又能提高生活水平。

  • 由于生产率的提高(储蓄、创新和投资的结果),产品的价格便随之下降,昔日的奢侈品也会变成普通消费品。

  • 技术创新是个单向的过程。除非人们失去记忆,否则生产效率必然会越来越高。因此,价格具有随着时间推移而降低的趋势。

  • 劳动的价值通常取决于劳动者所使用的资本,资本越优化,劳动的价值就越大。

  • 丰厚的利润正说明一个企业很擅长满足客户的需要,对这样的企业应当予以鼓励,而不应恶意诋毁。

  • 一名员工的具体价值主要取决于三个方面:需求(雇主是否需要这名员工所掌握的技能)、供应(有多少人具备这些技能)以及生产力(这名员工对那些任务的完成程度如何)。要想获得较高的薪资,这位员工必须提高其自身价值,要么掌握极少数人具备的急需技能(如医生),要么通过对本职工作精益求精来提高生产力,根本无捷径可走。

  • 通货紧缩被定义为一段时间内价格的全面下降。如果货币供应稳定,生产率的提高会促使价格的下降。如果消费者不愿意消费,刺激需求的最好办法是让物价降到更合理的水平。

第六章 为什么会有储蓄
  • 银行储蓄的安全与便捷促使人们增加储蓄、延迟消费,从而为投资项目提供资金,有助于增加未来的产量并提高生活水平。

  • 生产率大幅提高,储蓄就会增加,贷款利率也比较低,当储蓄量大时就导致了存款利率降低,从而抑制储蓄。

  • 储蓄是提高个人消费能力的手段,也是防止经济意外受损的重要缓冲器。

第七章 基础设施与贸易。
  • 基础设施建设投资会对经济产生巨大的影响。然而,只有在收益大于支出时,这种投资才有效果。反之,这些项目就是在浪费资源并阻碍经济增长。

  • 国际贸易与个人劳动分工没有什么区别。每个人或者每个国家都用自己多余的或者擅长生产的产品,换取自己缺乏的或者不擅长生产的产品。

  • 提供就业岗位并非经济的目的,经济的目的是不断提高生产力。

第八章 一个共和国就这样诞生了

无法自由地失败,也就是无法自由地成功。

第九章 政府的职能开始转变了
第十章 不断缩水的鱼就像货币一样
  • 高就业率(部分归功于政府提供的就业岗位)和繁荣的经济一起促使对鱼的需求增加,推动了物价上涨。

  • 通过膨胀就是货币供应量增加,与其相反的情况即使通货紧缩,意指货币供应量收紧。从以一个方面来说,价格自身其实不会膨胀或紧缩,只会上涨或下跌,所以膨胀的不是价格,而是货币供应。

第十一章 中岛帝国:远方的生命线
  • 国际贸易和个人劳动分工没有本质的区别。每个人或每个国家用自己多余的东西或者擅长生产的产品,换取自己不足的东西或不擅长生产的东西。
第十二章 服务业是如何崛起的
  • 在国际贸易中,出口大于进口,称作贸易顺差;进口大于出口,称作贸易逆差。

  • 如果一个国家处于贸易顺差状态,也就是说其出口量大于进口量,就会在国际上形成对其货币的需求。如果你想要该国的产品,你就需要该国的货币。所以,强势的贸易地位会使一国货币坚挺。反过来,弱势的贸易地位会导致该国货币疲软。如果没有人想购买你的产品,也就没有人需要你的货币。

第十三章 鱼本位的破灭
  • 纸币本身没有内在价值,是因为政府的命令而具有价值。
第十四章 棚屋价格是如何涨上去的
第十五章 快了!快了!棚屋市场要崩溃了
第十六章 情形怎么变得如此糟糕
  • 如果企业因为误读市场而蒙受损失,投资者就会及时抽身。如果企业顺应市场要求并获得利润,就会吸引更多的资金,从而扩大产能。

  • 一国的经济不会因为人们的消费而增长,而是经济增长带动人们的消费。

第十七章 缓兵之计
  • 向金融市场不断注入新的资金,推动价格上涨,即实行所谓的量化宽松,其实质是通货膨胀的委婉表达,是美联储将政府债券货币化的隐秘手段。“量化宽松”中的“量化”指将会创造指定金额的货币,而“宽松”则指减低银行的资金压力。

  • 增加货币供应量固然会鼓励人们消费,但扩大需求却毫无裨益,而需求才是促进经济增长的真正动力。

第十八章 占领华孚街
  • 量化宽松的真正面目:它是延长经济衰退的办法,而不是促进经济复兴的良法。
第十九章 无鱼不起浪
  • 政府可以利用通货膨胀避免艰难的抉择,还可以神不知鬼不觉地赖掉债务。政府可以通过加印钞票在名义上偿还债务,但是这样做的代价是本国货币的贬值。债权人收回了债务,可是却不值多少钱,如果碰上超级通货膨胀,那会是血本无归。

1.HttpURLConnection

优点:HttpURLConnection是一种多用途、轻量极的HTTP客户端,使用它来进行HTTP操作可以适用于大多数的应用程序。虽然HttpURLConnection的API提供的比较简单,但是同时这也使得我们可以更加容易地去使用和扩展它。比较轻便,灵活,易于扩展。

缺点:HttpURLConnection是java的标准类,什么都没封装,用起来太原始,不方便,比如重访问的自定义,以及一些高级功能等。 在android 2.2及以下版本中HttpUrlConnection存在着一些bug,所以建议在android2.3以后使用HttpUrlConnection,2.3之前使用HttpClient。

private static String getResult(String urlStr, String content, String encoding) {
	URL url = null;
	HttpURLConnection connection = null;
	try {
		url = new URL(urlStr);
		connection = (HttpURLConnection) url.openConnection();// 新建连接实例
		connection.setConnectTimeout(1000);// 设置连接超时时间,单位毫秒
		connection.setReadTimeout(1000);// 设置读取数据超时时间,单位毫秒
		connection.setDoOutput(true);// 是否打开输出流 true|false
		connection.setDoInput(true);// 是否打开输入流true|false
		connection.setRequestMethod("POST");// 提交方法POST|GET
		connection.setUseCaches(false);// 是否缓存true|false
		connection.connect();// 打开连接端口
		DataOutputStream out = new DataOutputStream(connection
				.getOutputStream());// 打开输出流往对端服务器写数据
		out.writeBytes(content);// 写数据,也就是提交你的表单 name=xxx&pwd=xxx
		out.flush();// 刷新
		out.close();// 关闭输出流
		BufferedReader reader = new BufferedReader(new InputStreamReader(
				connection.getInputStream(), encoding));// 往对端写完数据对端服务器返回数据
		// ,以BufferedReader流来读取
		StringBuffer buffer = new StringBuffer();
		String line = "";
		while ((line = reader.readLine()) != null) {
			buffer.append(line);
		}
		reader.close();
		return buffer.toString();
	} catch (IOException e) {
		e.printStackTrace();
	} finally {
		if (connection != null) {
			connection.disconnect();// 关闭连接
		}
	}
	return null;
}

2.HttpClient

优点:apache httpclient高效稳定,有很多API

缺点:由于API太多,很难在不破坏兼容性的情况下对它进行升级和扩展,维护成本高,故android 开发团队不愿意在维护该库而是转投更为轻便的httpurlconnection。Apache HttpClient早就不推荐httpclient,5.0之后干脆废弃,后续会删除。6.0删除了HttpClient。Java开发用HttpClient,官方推荐Android开发用HttpUrlConnection。

1.post常用方式

public static String sendPost(String memberId,String params, String requestUrl,
                                  String authorization) throws Exception {

    String result;
    InputStream inputStream=null,soapResponseStream =null;
    PostMethod postMethod =null;
	try {
		HttpClient httpClient = new HttpClient(new MultiThreadedHttpConnectionManager());// 客户端实例化
		byte[] requestBytes = params.getBytes("utf-8"); // 将参数转为二进制流
		postMethod = new PostMethod(requestUrl);
		//设置请求头Authorization
		postMethod.setRequestHeader("Authorization", "Basic " + authorization);
		// 设置请求头  Content-Type
	 	postMethod.setRequestHeader("Content-Type", "application/json");
		 //请求头信息中添加关闭连接
		postMethod.addRequestHeader("Connection", "close");
		inputStream = new ByteArrayInputStream(requestBytes, 0,
		        requestBytes.length);
		RequestEntity requestEntity = new InputStreamRequestEntity(inputStream,
		        requestBytes.length, "application/json; charset=utf-8"); // 请求体
		postMethod.setRequestEntity(requestEntity);
		httpClient.executeMethod(postMethod);// 执行请求
		soapResponseStream = postMethod.getResponseBodyAsStream();// 获取返回的流
		byte[] datas = readInputStream(soapResponseStream);// 从输入流中读取数据
		//连发三次机制
	    httpClient.getParams().setBooleanParameter("http.protocol.expect-continue", false);
		result = new String(datas, "UTF-8");
	} catch (Exception e) {
		throw new Exception(e);
	}finally {
		//释放连接
		if(postMethod!=null){
			postMethod.releaseConnection();
		}
    }
    return result;

}

2.带连接池的post调用

//整个连接池的最大连接数默认是20,连接池的每个路由的最大连接数默认是2,可设置超时,可设置重试
public static String doPost(String url, String data) throws Exception {
    StringBuilder result = new StringBuilder();
    CloseableHttpClient httpclient = HttpClients.createDefault();
    HttpPost httpPost = new HttpPost(url);

    try {
    	logger.info("executing request" + httpPost.getRequestLine());
    	if (StringUtils.isNotBlank(data)) {
    		httpPost.setEntity(new StringEntity(data, "UTF-8"));
    	}
    	CloseableHttpResponse response = httpclient.execute(httpPost);
    	try {
    		HttpEntity entity = response.getEntity();
    		logger.info(response.getStatusLine());
    		if (entity != null) {
    			System.out.println("Response content length: " + entity.getContentLength());
    			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(entity.getContent(), "UTF-8"));
    			String text;
    			while ((text = bufferedReader.readLine()) != null) {
    				result.append(text);
    			}
    		}
    		EntityUtils.consume(entity);
    	} catch (Exception e) {
    		logger.error(e, e);
    	} finally {
    		response.getEntity().getContent().close();
    		response.close();
    		httpPost.releaseConnection();
    	}
    } finally {
    	httpclient.close();
    }
    return result.toString();
    }

3.RestTemplate

RestTemplate是 Spring 提供的用于访问Rest服务的客户端, RestTemplate 提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率。

引入jar包:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

添加初始化配置(也可以不配,有默认的)–注意RestTemplate只有初始化配置,没有什么连接池

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class ApiConfig {
    @Bean
    public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
        return new RestTemplate(factory);
    }

    @Bean
    public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();//默认的是JDK提供http连接,需要的话可以//通过setRequestFactory方法替换为例如Apache HttpComponents、Netty或//OkHttp等其它HTTP library。
        factory.setReadTimeout(5000);//单位为ms
        factory.setConnectTimeout(5000);//单位为ms
        return factory;
    }
}

(1)get请求(不带参的即把参数取消即可)

// 1-getForObject()
User user1 = this.restTemplate.getForObject(uri, User.class);

// 2-getForEntity()
ResponseEntity<User> responseEntity1 = this.restTemplate.getForEntity(uri, User.class);
HttpStatus statusCode = responseEntity1.getStatusCode();
HttpHeaders header = responseEntity1.getHeaders();
User user2 = responseEntity1.getBody();

// 3-exchange()
RequestEntity requestEntity = RequestEntity.get(new URI(uri)).build();
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);
User user3 = responseEntity2.getBody();
方式一: ``` Notice notice = restTemplate.getForObject("http://fantj.top/notice/list/{1}/{2}"
            , Notice.class,1,5); ```
方式二: ``` Map<String,String> map = new HashMap();
    map.put("start","1");
    map.put("page","5");
    Notice notice = restTemplate.getForObject("http://fantj.top/notice/list/"
            , Notice.class,map); ```

(2)post请求:

// 1-postForObject()
User user1 = this.restTemplate.postForObject(uri, user, User.class);

// 2-postForEntity()
ResponseEntity<User> responseEntity1 = this.restTemplate.postForEntity(uri, user, User.class);

// 3-exchange()
RequestEntity<User> requestEntity = RequestEntity.post(new URI(uri)).body(user);
ResponseEntity<User> responseEntity2 = this.restTemplate.exchange(requestEntity, User.class);

方式一:

String url = "http://demo/api/book/";
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        String requestJson = "{...}";
        HttpEntity<String> entity = new HttpEntity<String>(requestJson,headers);
        String result = restTemplate.postForObject(url, entity, String.class);
        System.out.println(result);

方式二:

@Test
public void rtPostObject(){
    RestTemplate restTemplate = new RestTemplate();
    String url = "http://47.xxx.xxx.96/register/checkEmail";
    HttpHeaders headers = new HttpHeaders();
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    MultiValueMap<String, String> map= new LinkedMultiValueMap<>();
    map.add("email", "844072586@qq.com");

    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
    ResponseEntity<String> response = restTemplate.postForEntity( url, request , String.class );
    System.out.println(response.getBody());
}
其它:还支持上传和下载功能;

4.okhttp

OkHttp是一个高效的HTTP客户端,允许所有同一个主机地址的请求共享同一个socket连接;连接池减少请求延时;透明的GZIP压缩减少响应数据的大小;缓存响应内容,避免一些完全重复的请求。

当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。

(1)使用:它的请求/响应 API 使用构造器模式builders来设计,它支持阻塞式的同步请求和带回调的异步请求。

引入jar包:

<dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>3.10.0</version>
</dependency>

(2)配置文件:

import okhttp3.ConnectionPool;
import okhttp3.OkHttpClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.concurrent.TimeUnit;

@Configuration
public class OkHttpConfiguration {

    @Bean
    public OkHttpClient okHttpClient() {
        return new OkHttpClient.Builder()
                //.sslSocketFactory(sslSocketFactory(), x509TrustManager())
                .retryOnConnectionFailure(false)
                .connectionPool(pool())
                .connectTimeout(30, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .writeTimeout(30,TimeUnit.SECONDS)
                .build();
    }

    @Bean
    public X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }
            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {
            }
            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }

    @Bean
    public SSLSocketFactory sslSocketFactory() {
        try {
            //信任任何链接
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
            return sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Create a new connection pool with tuning parameters appropriate for a single-user application.
     * The tuning parameters in this pool are subject to change in future OkHttp releases. Currently
     */
    @Bean
    public ConnectionPool pool() {
        return new ConnectionPool(200, 5, TimeUnit.MINUTES);
    }
}

(3)util工具:

import okhttp3.*;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.util.Iterator;
import java.util.Map;

public class OkHttpUtil{
    private static final Logger logger = LoggerFactory.getLogger(OkHttpUtil.class);

    private static OkHttpClient  okHttpClient;

    @Autowired
    public OkHttpUtil(OkHttpClient  okHttpClient) {
        OkHttpUtil.okHttpClient= okHttpClient;
    }

    /**
     * get
     * @param url     请求的url
     * @param queries 请求的参数,在浏览器?后面的数据,没有可以传null
     * @return
     */
    public static  String get(String url, Map<String, String> queries) {
        String responseBody = "";
        StringBuffer sb = new StringBuffer(url);
        if (queries != null && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            Iterator iterator = queries.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                if (firstFlag) {
                    sb.append("?" + entry.getKey() + "=" + entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append("&" + entry.getKey() + "=" + entry.getValue());
                }
            }
        }
        Request request = new Request.Builder()
                .url(sb.toString())
                .build();
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
            int status = response.code();
            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (Exception e) {
            logger.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return responseBody;
    }

    /**
     * post
     *
     * @param url    请求的url
     * @param params post form 提交的参数
     * @return
     */
    public static String post(String url, Map<String, String> params) {
        String responseBody = "";
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request request = new Request.Builder()
                .url(url)
                .post(builder.build())
                .build();
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
            int status = response.code();
            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (Exception e) {
            logger.error("okhttp3 post error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return responseBody;
    }

    /**
     * get
     * @param url     请求的url
     * @param queries 请求的参数,在浏览器?后面的数据,没有可以传null
     * @return
     */
    public static String getForHeader(String url, Map<String, String> queries) {
        String responseBody = "";
        StringBuffer sb = new StringBuffer(url);
        if (queries != null && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            Iterator iterator = queries.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                if (firstFlag) {
                    sb.append("?" + entry.getKey() + "=" + entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append("&" + entry.getKey() + "=" + entry.getValue());
                }
            }
        }
        Request request = new Request.Builder()
                .addHeader("key", "value")
                .url(sb.toString())
                .build();
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
            int status = response.code();
            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (Exception e) {
            logger.error("okhttp3 put error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return responseBody;
    }

    /**
     * Post请求发送JSON数据....{"name":"zhangsan","pwd":"123456"}
     * 参数一:请求Url
     * 参数二:请求的JSON
     * 参数三:请求回调
     */
    public static String postJsonParams(String url, String jsonParams) {
        String responseBody = "";
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonParams);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
            int status = response.code();
            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (Exception e) {
            logger.error("okhttp3 post error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return responseBody;
    }

    /**
     * Post请求发送xml数据....
     * 参数一:请求Url
     * 参数二:请求的xmlString
     * 参数三:请求回调
     */
    public static String postXmlParams(String url, String xml) {
        String responseBody = "";
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/xml; charset=utf-8"), xml);
        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
        Response response = null;
        try {
            response = okHttpClient.newCall(request).execute();
            int status = response.code();
            if (response.isSuccessful()) {
                return response.body().string();
            }
        } catch (Exception e) {
            logger.error("okhttp3 post error >> ex = {}", ExceptionUtils.getStackTrace(e));
        } finally {
            if (response != null) {
                response.close();
            }
        }
        return responseBody;
    }
}

参考资料

  1. java常见的 http 请求库比较