1、HttpPoolProperties 类
@Component
//@PropertySource(value= {"classpath:properties/httpConfig.properties"})
//@ConfigurationProperties(prefix = "http.pool.conn")
@Data
public class HttpPoolProperties {
// 最大连接数
private Integer maxTotal = 20;
// 同路由并发数
private Integer defaultMaxPerRoute =20 ;
private Integer connectTimeout = 2000;
private Integer connectionRequestTimeout=2000;
private Integer socketTimeout= 2000;
// 线程空闲多久后进行校验
private Integer validateAfterInactivity= 2000;
// 重试次数
private Integer retryTimes = 2;
// 是否开启重试
private boolean enableRetry = true;
// 重试的间隔:可实现 ServiceUnavailableRetryStrategy 接口
private Integer retryInterval= 2000;
}
2、HttpClientPoolUtils 类
@Configuration
public class HttpClientPoolUtils {
@Autowired
private HttpPoolProperties httpPoolProperties;
/**
* 首先实例化一个连接池管理器
* 设置最大连接数、并发连接数
* @return
*/
@Bean(name = "httpClientConnectionManager")
public PoolingHttpClientConnectionManager getHttpClientConnectionManager(){
Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
.register("http", PlainConnectionSocketFactory.getSocketFactory())
.register("https", SSLConnectionSocketFactory.getSocketFactory())
.build();
PoolingHttpClientConnectionManager httpClientConnectionManager = new PoolingHttpClientConnectionManager(registry);
//最大连接数
httpClientConnectionManager.setMaxTotal(httpPoolProperties.getMaxTotal());
//并发数
httpClientConnectionManager.setDefaultMaxPerRoute(httpPoolProperties.getDefaultMaxPerRoute());
httpClientConnectionManager.setValidateAfterInactivity(httpPoolProperties.getValidateAfterInactivity());
return httpClientConnectionManager;
}
/**
* 实例化连接池,设置连接池管理器。
* 这里需要以参数形式注入上面实例化的连接池管理器
* @param httpClientConnectionManager
* @return
*/
@Bean(name = "httpClientBuilder")
public HttpClientBuilder getHttpClientBuilder(@Qualifier("httpClientConnectionManager")PoolingHttpClientConnectionManager httpClientConnectionManager){
//HttpClientBuilder中的构造方法被protected修饰,所以这里不能直接使用new来实例化一个HttpClientBuilder,可以使用HttpClientBuilder提供的静态方法create()来获取HttpClientBuilder对象
HttpClientBuilder httpClientBuilder = HttpClientBuilder.create();
httpClientBuilder.setConnectionManager(httpClientConnectionManager);
if (httpPoolProperties.isEnableRetry()){
// 重试次数
httpClientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler(httpPoolProperties.getRetryTimes(), true));
// 若需要自定义http 的重试策略,可以重新实现ServiceUnavailableRetryStrategy 或 HttpRequestRetryHandler接口,比如对指定异常或制定状态码进行重试,并指定充实的次数。
}else {
httpClientBuilder.disableAutomaticRetries();
}
// 另外httpClientBuilder 可以设置长连接策略,dns解析器,代理,拦截器以及UserAgent等等。可根据业务需要进行实现
return httpClientBuilder;
}
/* 注入连接池,用于获取httpClient
* @param httpClientBuilder
* @return
*/
@Bean("httpClient")
public CloseableHttpClient httpClient(@Qualifier("httpClientBuilder") HttpClientBuilder httpClientBuilder){
return httpClientBuilder.build();
}
/**
* Builder是RequestConfig的一个内部类
* 通过RequestConfig的custom方法来获取到一个Builder对象
* 设置builder的连接信息
* 这里还可以设置proxy,cookieSpec等属性。有需要的话可以在此设置
* @return
*/
@Bean(name = "builder")
public RequestConfig.Builder getBuilder(){
RequestConfig.Builder builder = RequestConfig.custom();
return builder.setConnectTimeout(httpPoolProperties.getConnectTimeout()) //连接上服务器(握手成功)的时间,超出抛出connect timeout
//从连接池中获取连接的超时时间,超时间未拿到可用连接,会抛出org.apache.http.conn.ConnectionPoolTimeoutException: Timeout waiting for connection from pool
.setConnectionRequestTimeout(httpPoolProperties.getConnectionRequestTimeout())
//服务器返回数据(response)的时间,超过抛出read timeout
.setSocketTimeout(httpPoolProperties.getSocketTimeout());
}
/**
* 使用builder构建一个RequestConfig对象
* @param builder
* @return
*/
@Bean
public RequestConfig getRequestConfig(@Qualifier("builder") RequestConfig.Builder builder){
return builder.build();
}
/**
* RestTemplate 指定httpClient 及连接池
*
* @param httpClient
* @return
*/
@Bean(name = "httpClientTemplate")
public RestTemplate restTemplate(@Qualifier("httpClient") CloseableHttpClient httpClient) {
HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
factory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate();
restTemplate.setRequestFactory(factory);
restTemplate.getMessageConverters().add(new StringHttpMessageConverter());
return restTemplate;
}
// pool监测线程,定期移除过期连接、空闲连接
/*
public static class IdleConnectionMonitorThread extends Thread {
private final HttpClientConnectionManager connMgr;
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
super();
this.connMgr = connMgr;
}
@Override
public void run() {
try {
while (true) {
synchronized (this) {
Thread.sleep(5000);
connMgr.closeExpiredConnections();
connMgr.closeIdleConnections(5, TimeUnit.SECONDS);
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
*/
}
3、IdleConnectionEvictor 类
@Component
public class IdleConnectionEvictor extends Thread{
@Autowired
private HttpClientConnectionManager connMgr;
private volatile boolean shutdown;
public IdleConnectionEvictor() {
super();
super.start();
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000);
// 关闭失效的连接
connMgr.closeExpiredConnections();
}
}
} catch (InterruptedException ex) {
// 结束
}
}
//关闭清理无效连接的线程
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
4、Service 类
public interface Service<T> {
public void UploadFile(List<T> list);
}
5、ServiceImpl 类
@Service
@Transactional(rollbackFor = Exception.class)
public class ServiceImpl<T> implements Service<T> {
@Autowired
private RestTemplate httpClientTemplate;
@Async
@Override
public void UploadFile(List<T> list) {
if(list.size() == 0){
return;
}else{
final String url = "http://localhost:8888/fileManager/gz";
// 设置请求头
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
// 设置请求体,注意是 LinkedMultiValueMap
MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
list.forEach(e->{
form.add("file",new FileSystemResource(e.toString()));
});
HttpEntity<MultiValueMap<String, Object>> files = new HttpEntity<>(form, headers);
httpClientTemplate.postForObject(url, files, JSONObject.class);
}
}
}
6、FileManagerController 接收Controller
@RestController
@RequestMapping("/fileManager")
public class FileManagerController {
@RequestMapping("/gz")
public Map fileUpload(@RequestParam("file") MultipartFile[] files, HttpServletRequest request) throws Exception {
for (MultipartFile file : files) {
if (!file.isEmpty() && file.getSize() > 0) {
String fileName = file.getOriginalFilename();
File dest = new File(new File("C:\\files").getAbsolutePath()+ "/" + fileName);
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
file.transferTo(dest);
}
}
Map<String,String> map = new HashMap<>();
map.put("200","ok");
return map;
}
}
7、测试类
@SpringBootTest(classes= IndexApplication.class)
@RunWith(SpringRunner.class)
public class IndexTest {
@Resource
private Service service;
@Test
public void testUploadFile(){
List<String> list = new ArrayList<>();
list.add("C:\\Users\\Pictures\\Saved Pictures\\tupian\\图片1.png");
list.add("C:\\Users\\Pictures\\Saved Pictures\\tupian\\图片2.png");
service.UploadFile(list);
}
}