package com.cpic.home.governor.service.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import com.alibaba.fastjson.JSON;
import com.cpic.caf.compon.tech.utils.CharsetUtil;
import com.cpic.home.governor.service.JobSchedulerService;
import feign.Feign;
import feign.Param;
import feign.RequestLine;
import feign.RequestTemplate;
import feign.Response;
import feign.Util;
import feign.codec.Decoder;
import feign.codec.Encoder;
import feign.gson.GsonDecoder;
/**
* 该类为 JobSchedulerService 实例,因需要调用 JobScheduler, 需远程执行接口。
*
*
*
*
* Created by zhenqin.
* User: zhenqin
* Date: 2019/3/26
* Time: 18:43
* Vendor: primeton.com
* To change this template use File | Settings | File Templates.
*
*
*
* @author zhenqin
*/
@Component("jobSchedulerService")
public class JobSchedulerServiceImpl implements InitializingBean, FactoryBean,
MethodInterceptor {
/**
* JobScheduler 地址
*/
@Value("${jobscheduler.url}")
String jobSchedulerUrl;
private HttpClient httpclient = null;
static Logger logger = LoggerFactory.getLogger(JobSchedulerServiceImpl.class);
@Override
public void afterPropertiesSet() throws Exception {
HttpClient httpclient = HttpClientBuilder.create().build();
this.httpclient = httpclient;
}
@Override
public JobSchedulerService getObject() throws Exception {
JobSchedulerService jobSchedulerService = Feign.builder()
.encoder(feignEncoder())
.decoder(feignDecoder())
.target(JobSchedulerService.class, jobSchedulerUrl);
// AOP,拦截上传文件的接口
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.addAdvice(this);
proxyFactory.setTarget(jobSchedulerService);
// 获得代理类
return (JobSchedulerService) proxyFactory.getProxy();
}
@Override
public Class> getObjectType() {
return JobSchedulerService.class;
}
/**
* AOP 织入
*
* @param invocation
* @return
* @throws Throwable
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Object[] arguments = invocation.getArguments();
boolean isMutilForm = false;
for (Object argument : arguments) {
// 文件
isMutilForm = argument instanceof File || argument instanceof MultipartFile;
if (isMutilForm) {
// 有一个是文件的,则是上传
break;
}
}
Object result = null;
if (!isMutilForm) {
// 普通表单
result = invocation.proceed();
} else {
// 文件上传
result = new HashMap<>();
Method method = invocation.getMethod();
RequestLine requestLine = method.getAnnotation(RequestLine.class);
if (requestLine != null) {
String[] split = requestLine.value().split("\\s+");
String url = jobSchedulerUrl + split[1];
Map form = new HashMap<>();
Parameter[] parameters = method.getParameters();
Annotation[][] annotations = method.getParameterAnnotations();
int i = 0;
for (Parameter parameter : parameters) {
form.put(getFormName(parameter, annotations[i]), invocation.getArguments()[i]);
i++;
}
// 提交表单
return executeRest(url, form);
}
}
return result;
}
/**
* 提交表单
*
* @param form 提交表单,携带文件
* @return
*/
public Map executeRest(String url, Map form) {
HttpPost request = new HttpPost(url);
MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
InputStream in = null;
try {
for (Map.Entry entry : form.entrySet()) {
if (entry.getValue() instanceof File || entry.getValue() instanceof MultipartFile) {
if (entry.getValue() instanceof File) {
String name = ((File) entry.getValue()).getName();
multipartEntityBuilder.addPart(entry.getKey(), new FileBody((File) entry.getValue()));
multipartEntityBuilder.addPart("name", new StringBody(name, ContentType.MULTIPART_FORM_DATA));
} else {
MultipartFile uploadFile = (MultipartFile) entry.getValue();
in = uploadFile.getInputStream();
String name = ((MultipartFile) entry.getValue()).getOriginalFilename();
multipartEntityBuilder.addPart(entry.getKey(), new InputStreamBody(in, ContentType.MULTIPART_FORM_DATA, name));
multipartEntityBuilder.addPart("name", new StringBody(name, ContentType.MULTIPART_FORM_DATA));
}
} else {
multipartEntityBuilder.addPart(entry.getKey(),
(entry.getValue() instanceof String ? new StringBody((String) entry.getValue(), ContentType.MULTIPART_FORM_DATA) :
new StringBody(String.valueOf(entry.getValue()), ContentType.MULTIPART_FORM_DATA)));
}
}
request.setEntity(multipartEntityBuilder.build());
HttpResponse response = httpclient.execute(request);
if (response.getStatusLine().getStatusCode() == 200) {
String json = EntityUtils.toString(response.getEntity(), CharsetUtil.CHARSET_UTF_8);
logger.info(json);
return JSON.parseObject(json);
} else {
logger.error("execute {} error.", request.getURI());
}
} catch (IOException e) {
logger.error("execute rest api error.", e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
}
}
}
return new HashMap<>();
}
/**
* 获取该 参数的名称,@Param 注解名称,若没有选择字段名称
*
* @param parameter
* @param param
* @return
*/
String getFormName(Parameter parameter, Annotation[] param) {
if (param == null || param.length == 0) {
return parameter.getName();
}
// 选择 param 的名称
Param params = (Param) param[0];
return params.value();
}
public void setJobSchedulerUrl(String jobSchedulerUrl) {
this.jobSchedulerUrl = jobSchedulerUrl;
}
public static Decoder feignDecoder() {
// JSON
GsonDecoder gsonDecoder = new GsonDecoder();
return (Response response, Type type) -> {
Response.Body body = response.body();
if (body == null) {
return null;
}
if (String.class.equals(type)) {
return Util.toString(body.asReader());
}
return gsonDecoder.decode(response, type);
};
}
public static Encoder feignEncoder() {
// JSON
return (Object object, Type bodyType, RequestTemplate template) -> {
if (bodyType == String.class) {
template.body((String)object);
} else if (bodyType == byte[].class) {
template.body((byte[]) object, CharsetUtil.CHARSET_UTF_8);
} else if (object instanceof Number) {
template.body(String.valueOf(object));
}
template.body(JSON.toJSONString(object));
};
}
}