本文档描述了一个Java类`RemoteOperationWithAttachment`,用于实现第三方系统远程上传单据及附件到苍穹系统的功能。类中定义了苍穹系统的访问地址、单据标识、应用标识等常量,并提供了主方法`main`用于测试上传流程。上传流程包括获取应用令牌(`appToken`)和用户访问令牌(`accessToken`),然后调用`remoteSaveWithAttachments`方法上传文件及单据数据。该方法中,首先上传文件到苍穹系统,然后封装单据数据并调用业务保存接口。上传结果通过解析返回的JSON字符串来判断是否成功,并输出相应信息。此外,还提供了`AppLoginService`和`UserLoginService`类用于获取应用和用户令牌。
标签:第三方系统,文件上传
实现方案:
/**
* 第三方系统远程上传单据&附件到苍穹系统
*
*/
public class RemoteOperationWithAttachment {
// 苍穹系统访问地址,需修改
private static final String REMOTEHOST = "http://127.0.0.1:8080/ierp";
// 苍穹系统中,对应单据的标识,需修改
private static final String FORMID = "kded_document";
// 苍穹系统中,对应单据所属应用的标识,需修改
private static final String APPID = "kded_apps";
/**
* 测试入口
*
*/
public static void main(String[] args) {
RemoteOperationWithAttachment remoteOperation = new RemoteOperationWithAttachment();
// 获取连接信息,需修改(在方法体内)
String appToken = AppLoginService.getService().getAppToken(REMOTEHOST);
String accessToken = UserLoginService.getService().getAccessToken(REMOTEHOST, appToken);
// 远程上传单据&附件
// try {
remoteOperation.remoteSaveWithAttachments (accessToken);
// } catch (Exception e) {
e.printStackTrace();
// }
}
/**
* 远程上传单据&附件到苍穹系统
* 参考资料:https://www.cnblogs.com/zwqh/p/9635176.html
* https://blog.csdn.net/zzq900503/article/details/72920914/
*
*/
private void remoteSaveWithAttachments(String accessToken) throws Exception {
// 第三方系统中待上传到苍穹系统的文件,需修改
File file = new File("E:\\test.txt");
// 上传可能需要传的参数
Map<String, Object> param = new HashMap<String, Object>();
String responseStr = null;
JSONObject responseJson = null;
String url = REMOTEHOST + "/attachment/uploadFile.do";
// 上传文件
responseStr = FileUploadService.getService().postFile(url, param, file, accessToken);
// 封装第三方系统中待上传到苍穹系统的单据数据
Map<String, Object> formData = new HashMap<String, Object>();
// 单据标识符,需修改(苍穹系统中需要该参数,如第三方系统没有该参数,可自行新建,格式:开发商标识符+单据名称,英文或者数字,附:开发商标识符可在苍穹系统中查询到)
formData.put("formId", FORMID);
formData.put("appId", APPID);
formData.put("fileName", file.getName());
formData.put("fileSize", file.length());
formData.put("description", "");
formData.put("bizType", "upload");
// 单据数据,按实际业务自行修改
formData.put("billno", "test20210705");
formData.put("billstatus", "B");
formData.put("desc", "测试");
formData.put("qtyfield1", "12");
responseStr = BizOperateService.getService().BizSave(REMOTEHOST, accessToken, formData, responseStr, null);
responseJson = JSONObject.parseObject(responseStr);
Boolean success = Boolean.valueOf(responseJson.getString("success"));
if (success) {
System.out.println("上传成功!");
} else {
String message = responseJson.getJSONObject("data").getString("message");
throw new Exception(message);
}
}
}
/*
* 获取APPTOKEN
*/
public class AppLoginService {
private static final String path = "/api/getAppToken.do";
private static final AppLoginService service = new AppLoginService();
private AppLoginService() {}
//静态工厂方法
public static AppLoginService getService() {
return service;
}
public String getAppToken(String REMOTEHOST) {
//获取APPTOKEN
String url = REMOTEHOST + path;
// appId & appSecuret & tenantid & accountId 需修改
String data = "{\"appId\": \"EAS\""
+ ",\"appSecuret\": \"123456\""
+ ",\"tenantid\": \"ierp\""
+ ",\"accountId\": \"1557233840063393244\""
+ ",\"language\": \"zh_CN\"}";
String responseStr = null;
try {
responseStr = HttpService.getService().doPostByHttpClient(url, data);
} catch (Exception e) {
e.printStackTrace();
}
JSONObject json = JSONObject.parseObject(responseStr);
String appToken = json.getJSONObject("data").getString("app_token");
return appToken;
}
}
public class UserLoginService {
private static final String path = "/api/login.do";
private UserLoginService() {}
private static final UserLoginService service = new UserLoginService();
//静态工厂方法
public static UserLoginService getService() {
return service;
}
public String getAccessToken(String REMOTEHOST, String appToken) {
//获取用户token
String url = REMOTEHOST + path;
// user & tenantid & accountId 需修改
String data = "{\"user\": \"17299999999\""
+ ",\"apptoken\": \""+appToken+"\""
+ ",\"tenantid\": \"ierp\""
+ ",\"accountId\": \"1557233840063393244\""
+ ",\"usertype\": \"Mobile\"}";
String responseStr = null;
try {
responseStr = HttpService.getService().doPostByHttpClient(url, data);
} catch (Exception e) {
e.printStackTrace();
}
JSONObject json = JSONObject.parseObject(responseStr);
String accessToken = json.getJSONObject("data").getString("access_token");
return accessToken;
}
}
public class FileUploadService {
private static final FileUploadService service = new FileUploadService();
private static final String BOUNDARY = "----WebKitFormBoundaryBHp47SjGMxpHX0X6--";
private FileUploadService() {}
//静态工厂方法
public static FileUploadService getService() {
return service;
}
public String postFile(String url, Map<String, Object> param, File file, String accessToken) throws Exception {
HttpPost httppost = new HttpPost(url);
httppost.addHeader("api", "true");
httppost.addHeader("accessToken", accessToken);
//设置boundary,文件解析用
httppost.addHeader("Content-Type", "multipart/form-data; boundary="+BOUNDARY);
MultipartEntity entry = this.getMutipartEntry(param, file);
httppost.setEntity(entry);
return HttpService.getService().doExecuteByHttpClient(httppost, new ResponseHandler<String>() {
@Override
public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
HttpEntity entity = response.getEntity();
String rtn = EntityUtils.toString(entity, "UTF-8");
JSONObject json = JSONObject.parseObject(rtn);
String url = json.getString("url");
return url;
}
});
}
private MultipartEntity getMutipartEntry(Map<String, Object> param, File file)
throws UnsupportedEncodingException, FileNotFoundException {
if (file == null) {
throw new IllegalArgumentException("文件不能为空");
}
MultipartEntity multipartEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE, BOUNDARY, Charset.forName("UTF-8"));
multipartEntity.addPart("file", new InputStreamBody(new FileInputStream(file), file.getName()));
if (param != null) {
Iterator<String> iterator = param.keySet().iterator();
while (iterator.hasNext()) {
String key = iterator.next();
FormBodyPart field = new FormBodyPart(key, new StringBody((String) param.get(key)));
multipartEntity.addPart(field);
}
}
return multipartEntity;
}
}
public class BizOperateService {
private static final BizOperateService service = new BizOperateService();
private static final String relativePath = "/kapi/app/sys/BizCustomSave";
private BizOperateService() {}
//静态工厂方法
public static BizOperateService getService() {
return service;
}
/**
* 远程上传单据数据 & 附件文件到苍穹系统
* @param remotehost 苍穹系统访问地址
* @param accessToken
* @param formData 单据数据
* @param attchmentsUrl 附件在苍穹系统中的保存地址
* @param attchmentpanles 第三方系统中附件面板的标识,如无可传null
* @return
* @throws URISyntaxException
*/
public String BizSave(String remotehost, String accessToken, Map<String, Object> formData, String attchmentsUrl, List<String> attchmentpanles)
throws URISyntaxException {
List<String> attchmentsUrlList = new ArrayList<String>();
attchmentsUrlList.add(attchmentsUrl);
// 默认一个附件面板
attchmentpanles = (attchmentpanles == null) ? new ArrayList<String>() : attchmentpanles;
if (attchmentpanles.size() == 0) {
attchmentpanles.add("attachmentpanel");
}
// 自定义开放平台接口路径
String url = remotehost + relativePath;
// 附件信息
Map<String, Object> attachmentInfo = new HashMap<String, Object>();
List<Map<String, Object>> attachments = null;
Map<String, Object> attachment = null;
StringBuffer uid = new StringBuffer("rc-upload-");
uid.append(new Date().getTime());
uid.append("-");
int index = (int) (1 + Math.random()*10);
// 多个附件面板
for (String tempattchmentpanle : attchmentpanles) {
attachments = new ArrayList<Map<String, Object>>();
// 多个附件
for (String attchmentUrl : attchmentsUrlList) {
attachment = new HashMap<String, Object>();
attachment.put("name", formData.get("fileName"));
attachment.put("url", attchmentUrl);
uid.append(index);
attachment.put("uid", uid);
index++;
attachment.put("size", formData.get("fileSize"));
attachment.put("description", formData.get("description"));
attachments.add(attachment);
}
attachmentInfo.put(tempattchmentpanle, attachments);
}
// 封装数据
JSONObject body = new JSONObject();
body.put("accessToken", accessToken);
body.put("bizObject", formData);
body.put("attachmentInfo", attachmentInfo);
String responseStr = null;
try {
responseStr = HttpService.getService().doGetByHttpClient(url, body);
} catch (Exception e) {
e.printStackTrace();
}
return responseStr;
}
}
public class HttpService {
private static final HttpService service = new HttpService();
private HttpService() {}
// 静态工厂方法
public static HttpService getService() {
return service;
}
/**
* POST方式发送请求
* @param url
* @param data
* @return
* @throws Exception
*/
public String doPostByHttpClient(String url, String data) throws Exception {
StringEntity se = new StringEntity(data, "UTF-8");
se.setContentType("text/json");
se.setContentEncoding(new BasicHeader("Content-Type", "application/json; charset=UTF-8"));
HttpPost httpPost = new HttpPost(url);
httpPost.addHeader("Content-Type", "application/json; charset=UTF-8");
httpPost.setEntity(se);
return doExecuteByHttpClient(httpPost,new ResponseHandler<String>() {
@Override
public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) {
try {
throw new Exception("连接服务器发生错误!");
} catch (Exception e) {
e.printStackTrace();
}
}
return EntityUtils.toString(response.getEntity());
}
});
}
public <T> T doExecuteByHttpClient(HttpUriRequest httpPost, ResponseHandler<? extends T> responseHandler) throws Exception {
try {
CloseableHttpClient httpClient = HttpClientFactory.getHttpClient();
T rtn = httpClient.execute(httpPost, responseHandler);
return rtn;
} catch (Exception e) {
e.printStackTrace();
System.out.println(" ===== doPostByHttpClient() ERROR ===== ");
throw new Exception(e.getMessage());
} finally {
System.clearProperty("javax.net.debug");
}
}
/**
* GET方式发送请求
* @param url
* @param param
* @return
* @throws Exception
*/
public String doGetByHttpClient(String url, JSONObject param) throws Exception {
URIBuilder builder = new URIBuilder(url);
if (param != null) {
builder.addParameter("body", param.toJSONString());
}
URI uri = builder.build();
HttpGet httpGet = new HttpGet(uri);
return doExecuteByHttpClient(httpGet, new ResponseHandler<String>() {
@Override
public String handleResponse(HttpResponse response) throws ClientProtocolException, IOException {
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK && statusCode != HttpStatus.SC_CREATED) {
try {
throw new Exception("连接服务器发生错误!");
} catch (Exception e) {
e.printStackTrace();
}
}
return EntityUtils.toString(response.getEntity());
}
});
}
}
/*
* 高并发HttpClient
*/
public class HttpClientFactory {
private static CloseableHttpClient httpClient ;
public static CloseableHttpClient getHttpClient() throws InstantiationException, IllegalAccessException
{
if(httpClient == null ) {
synchronized (HttpClientFactory.class)
{
if(httpClient == null) {
httpClient = create();
}
}
}
return httpClient;
}
private static CloseableHttpClient create() {
ConnectionKeepAliveStrategy myStrategy = new ConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(HttpResponse response, HttpContext context) {
HeaderElementIterator it = new BasicHeaderElementIterator
(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
while (it.hasNext()) {
HeaderElement he = it.nextElement();
String param = he.getName();
String value = he.getValue();
if (value != null && param.equalsIgnoreCase
("timeout")) {
return Long.parseLong(value) * 1000;
}
}
return 60 * 1000;//如果没有约定,则默认定义时长为60s
}
};
// 配置一个PoolingHttpClientConnectionManager
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
connectionManager.setMaxTotal(500);
connectionManager.setDefaultMaxPerRoute(50);//例如默认每路由最高50并发,具体依据业务来定
//设置一个线程隔一段时间关闭超时连接
IdleConnectionMonitorThread thread = new IdleConnectionMonitorThread(connectionManager);
thread.start();
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(connectionManager)
.setKeepAliveStrategy(myStrategy)
.setDefaultRequestConfig(RequestConfig.custom().setStaleConnectionCheckEnabled(true).build())
.build();
HttpParams params = new BasicHttpParams();
//设置连接超时时间
Integer CONNECTION_TIMEOUT = 2 * 1000; //设置请求超时2秒钟 根据业务调整
Integer SO_TIMEOUT = 2 * 1000; //设置等待数据超时时间2秒钟 根据业务调整
//定义了当从ClientConnectionManager中检索ManagedClientConnection实例时使用的毫秒级的超时时间
//这个参数期望得到一个java.lang.Long类型的值。如果这个参数没有被设置,默认等于CONNECTION_TIMEOUT,因此一定要设置。
Long CONN_MANAGER_TIMEOUT = 500L; //在httpclient4.2.3中我记得它被改成了一个对象导致直接用long会报错,后来又改回来了
params.setIntParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, CONNECTION_TIMEOUT);
params.setIntParameter(CoreConnectionPNames.SO_TIMEOUT, SO_TIMEOUT);
params.setLongParameter(ClientPNames.CONN_MANAGER_TIMEOUT, CONN_MANAGER_TIMEOUT);
//在提交请求之前 测试连接是否可用
params.setBooleanParameter(CoreConnectionPNames.STALE_CONNECTION_CHECK, true);
//另外设置http client的重试次数,默认是3次;当前是禁用掉(如果项目量不到,这个默认即可)
// httpClient.setHttpRequestRetryHandler(new DefaultHttpRequestRetryHandler(0, false));
return httpClient;
}
public static class IdleConnectionMonitorThread extends Thread {
private final HttpClientConnectionManager connMgr;
private volatile boolean shutdown;
public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
super();
this.connMgr = connMgr;
}
@Override
public void run() {
try {
while (!shutdown) {
synchronized (this) {
wait(5000);
// Close expired connections
connMgr.closeExpiredConnections();
// Optionally, close connections
// that have been idle longer than 30 sec
connMgr.closeIdleConnections(30, TimeUnit.SECONDS);
}
}
} catch (InterruptedException ex) {
// terminate
}
}
public void shutdown() {
shutdown = true;
synchronized (this) {
notifyAll();
}
}
}
}
第三方系统上传文件demo.zip(12.80KB)
推荐阅读