|
|
@@ -0,0 +1,306 @@
|
|
|
+package com.uas.report.service.impl;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileOutputStream;
|
|
|
+import java.io.IOException;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.net.URI;
|
|
|
+import java.net.URISyntaxException;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Date;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+import org.apache.commons.collections.CollectionUtils;
|
|
|
+import org.apache.commons.io.IOUtils;
|
|
|
+import org.apache.http.HttpResponse;
|
|
|
+import org.apache.http.NameValuePair;
|
|
|
+import org.apache.http.client.ClientProtocolException;
|
|
|
+import org.apache.http.client.HttpClient;
|
|
|
+import org.apache.http.client.methods.HttpGet;
|
|
|
+import org.apache.http.client.methods.HttpRequestBase;
|
|
|
+import org.apache.http.client.utils.URIBuilder;
|
|
|
+import org.apache.http.impl.client.HttpClients;
|
|
|
+import org.apache.http.message.BasicNameValuePair;
|
|
|
+import org.apache.log4j.Logger;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import com.alibaba.fastjson.JSONObject;
|
|
|
+import com.uas.report.model.Resource;
|
|
|
+import com.uas.report.service.ResourceService;
|
|
|
+import com.uas.report.support.JasperserverRestAPIConf;
|
|
|
+
|
|
|
+/**
|
|
|
+ * 管理报表模板、图片等资源
|
|
|
+ *
|
|
|
+ * @author sunyj
|
|
|
+ * @since 2016年9月23日 下午5:23:42
|
|
|
+ */
|
|
|
+@Service
|
|
|
+public class ResourceServiceImpl implements ResourceService {
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private JasperserverRestAPIConf jsRestAPIConf;
|
|
|
+
|
|
|
+ private Logger logger = Logger.getLogger(getClass());
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Resource> syncResources(String userName)
|
|
|
+ throws ClientProtocolException, URISyntaxException, IOException {
|
|
|
+ logger.info("Synchronizing resources...");
|
|
|
+ List<Resource> synchronizingResources = getSynchronizingResources(userName);
|
|
|
+ if (!CollectionUtils.isEmpty(synchronizingResources)) {
|
|
|
+ for (Resource synchronizingResource : synchronizingResources) {
|
|
|
+ downloadFile(synchronizingResource);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ logger.info("Synchronized");
|
|
|
+ return synchronizingResources;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 与本地进行比较,返回需要同步的资源
|
|
|
+ *
|
|
|
+ * @param resources
|
|
|
+ * 用于比较的资源
|
|
|
+ * @param userName
|
|
|
+ * 账套名
|
|
|
+ * @return 需要进行同步的资源
|
|
|
+ * @throws IOException
|
|
|
+ * @throws URISyntaxException
|
|
|
+ * @throws ClientProtocolException
|
|
|
+ */
|
|
|
+ private List<Resource> getSynchronizingResources(String userName)
|
|
|
+ throws ClientProtocolException, URISyntaxException, IOException {
|
|
|
+ List<Resource> synchronizingResources = new ArrayList<>();
|
|
|
+ List<Resource> remoteResources = getRemoteResources("/" + userName);
|
|
|
+ if (CollectionUtils.isEmpty(remoteResources)) {
|
|
|
+ return synchronizingResources;
|
|
|
+ }
|
|
|
+
|
|
|
+ List<Resource> localResources = getLocalResources(userName);
|
|
|
+ for (Resource remoteResource : remoteResources) {
|
|
|
+ if (needSynchronized(remoteResource, localResources)) {
|
|
|
+ synchronizingResources.add(remoteResource);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return synchronizingResources;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 比较远程资源是否需要同步
|
|
|
+ *
|
|
|
+ * @param remoteResource
|
|
|
+ * jasperserver库里的资源
|
|
|
+ * @param localResources
|
|
|
+ * 本地路径下的资源列表
|
|
|
+ * @return 远程资源是否需要同步
|
|
|
+ */
|
|
|
+ private boolean needSynchronized(Resource remoteResource, List<Resource> localResources) {
|
|
|
+ // 如果资源不是文件夹,并且不含"."(无后缀名),不进行比较,直接认为不需要同步
|
|
|
+ if (!remoteResource.isFolder() && !remoteResource.getUri().contains(".")) {
|
|
|
+ logger.error("Resource is invalid: " + remoteResource + "\n");
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (Resource localResource : localResources) {
|
|
|
+ if (remoteResource.getUri().equals(localResource.getUri())) {
|
|
|
+ // 如果远程资源比本地资源更新
|
|
|
+ if (remoteResource.getUpdateDate().after(localResource.getUpdateDate())) {
|
|
|
+ return true;
|
|
|
+ } else {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 本地并没有该资源
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取本地指定账套下的所有资源
|
|
|
+ *
|
|
|
+ * @param userName
|
|
|
+ * @return 资源列表
|
|
|
+ */
|
|
|
+ private List<Resource> getLocalResources(String userName) {
|
|
|
+ return getLocalResources(new File(jsRestAPIConf.getLocalBaseDir() + File.separator + userName));
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取本地指定路径下的所有资源
|
|
|
+ *
|
|
|
+ * @param dir
|
|
|
+ * 指定的路径,可能是文件夹或文件
|
|
|
+ * @return 资源列表
|
|
|
+ */
|
|
|
+ private List<Resource> getLocalResources(File dir) {
|
|
|
+ List<Resource> resources = new ArrayList<>();
|
|
|
+ if (dir == null || !dir.exists()) {
|
|
|
+ return resources;
|
|
|
+ }
|
|
|
+ if (dir.isDirectory()) {
|
|
|
+ // 递归获取所有资源
|
|
|
+ File[] files = dir.listFiles();
|
|
|
+ for (File file : files) {
|
|
|
+ resources.addAll(getLocalResources(file));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ resources.add(convertToResource(dir));
|
|
|
+ return resources;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将本地文件(夹)转为Resource对象
|
|
|
+ *
|
|
|
+ * @param file
|
|
|
+ * 本地文件(夹)
|
|
|
+ * @return 转换的资源
|
|
|
+ */
|
|
|
+ private Resource convertToResource(File file) {
|
|
|
+ Resource resource = new Resource();
|
|
|
+ resource.setLabel(file.getName());
|
|
|
+ resource.setUpdateDate(new Date(file.lastModified()));
|
|
|
+ // 替换"\"为"/"
|
|
|
+ String absolutePath = file.getAbsolutePath().replace("\\", "/");
|
|
|
+ // 去除文件绝对路径中前半部分,只保留自账套开始的路径
|
|
|
+ resource.setUri(absolutePath.replace(jsRestAPIConf.getLocalBaseDir(), ""));
|
|
|
+ return resource;
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public List<Resource> getRemoteResources(String folderPath)
|
|
|
+ throws ClientProtocolException, URISyntaxException, IOException {
|
|
|
+ HttpGet httpGet = new HttpGet();
|
|
|
+ // 返回json类型数据
|
|
|
+ httpGet.setHeader("Accept", "application/json");
|
|
|
+ List<NameValuePair> parameters = new ArrayList<>();
|
|
|
+ // 设置连接参数
|
|
|
+ parameters.add(new BasicNameValuePair("folderUri", folderPath));
|
|
|
+ HttpResponse response = sendRequest(httpGet, null, parameters);
|
|
|
+ InputStream inputStream = response.getEntity().getContent();
|
|
|
+ String jsonStr = IOUtils.toString(inputStream);
|
|
|
+ // 将返回的json数据格式化为Resource列表
|
|
|
+ List<Resource> resources = JSONObject.parseArray(JSONObject.parseObject(jsonStr).getString("resourceLookup"),
|
|
|
+ Resource.class);
|
|
|
+ inputStream.close();
|
|
|
+ return resources;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据资源的信息下载相应文件
|
|
|
+ *
|
|
|
+ * @param resource
|
|
|
+ * 资源信息
|
|
|
+ * @throws ClientProtocolException
|
|
|
+ * @throws URISyntaxException
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private void downloadFile(Resource resource) throws ClientProtocolException, URISyntaxException, IOException {
|
|
|
+ // 如果资源是文件夹,在本地创建
|
|
|
+ if (resource.isFolder()) {
|
|
|
+ new File(jsRestAPIConf.getLocalBaseDir() + resource.getUri()).mkdirs();
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ String localBaseDir = jsRestAPIConf.getLocalBaseDir();
|
|
|
+ // 如果本地资源根路径最后以资源分隔符结尾
|
|
|
+ if (localBaseDir.endsWith(File.separator)) {
|
|
|
+ localBaseDir = localBaseDir.substring(0, localBaseDir.length() - 1);
|
|
|
+ }
|
|
|
+ String uri = resource.getUri();
|
|
|
+ // 从资源的uri中获取账套名(如"/UAS/jrxml/Purchase.jrxml",第一个"UAS"就是账套)
|
|
|
+ String userName = uri.split("/")[1];
|
|
|
+ // 从uri中获取资源的名称(不能使用label,其只用于方便用户查看,并不能用于标识)
|
|
|
+ String resourceName = uri.substring(uri.lastIndexOf("/"));
|
|
|
+
|
|
|
+ StringBuilder stringBuilder = new StringBuilder();
|
|
|
+ stringBuilder.append(localBaseDir).append("/").append(userName);
|
|
|
+
|
|
|
+ // 下载jrxml文件(即使该远程资源并不在jrxml根路径下,比如在嵌套文件夹下),放在localBaseDir+userName+localJrxmlDir下
|
|
|
+ if (uri.endsWith(Resource.JRXML_RESOURCE_TYPE)) {
|
|
|
+ stringBuilder.append(jsRestAPIConf.getLocalJrxmlDir()).append(resourceName);
|
|
|
+ downloadFile(uri, Resource.JRXML_MIME_TYPE, stringBuilder.toString());
|
|
|
+ }
|
|
|
+ // 除jrxml之外的资源视为图片,放在localBaseDir+userName+localImagesDir下
|
|
|
+ else {
|
|
|
+ stringBuilder.append(jsRestAPIConf.getLocalImagesDir()).append(resourceName);
|
|
|
+ downloadFile(uri, Resource.IMAGE_MIME_TYPE, stringBuilder.toString());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void downloadFile(String filePath, String mimeType, String exportPath)
|
|
|
+ throws ClientProtocolException, URISyntaxException, IOException {
|
|
|
+ HttpGet httpGet = new HttpGet();
|
|
|
+ // 设置MIME类型
|
|
|
+ httpGet.setHeader("MIME", mimeType);
|
|
|
+ HttpResponse response = sendRequest(httpGet, filePath, null);
|
|
|
+ // 获取文件二进制数据
|
|
|
+ byte[] data = IOUtils.toByteArray(response.getEntity().getContent());
|
|
|
+ File exportFile = new File(exportPath);
|
|
|
+ // 该文件所在的路径不存在,创建
|
|
|
+ if (!exportFile.getParentFile().exists()) {
|
|
|
+ exportFile.getParentFile().mkdirs();
|
|
|
+ }
|
|
|
+ FileOutputStream fos = new FileOutputStream(exportFile);
|
|
|
+ fos.write(data);
|
|
|
+ fos.close();
|
|
|
+ logger.info("Download resource to " + exportPath + "\n");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 发送Http请求,获得结果
|
|
|
+ *
|
|
|
+ * @param request
|
|
|
+ * Http请求
|
|
|
+ * @param path
|
|
|
+ * 资源路径
|
|
|
+ * @param parameters
|
|
|
+ * 参数
|
|
|
+ * @return 服务器的响应结果
|
|
|
+ * @throws URISyntaxException
|
|
|
+ * @throws ClientProtocolException
|
|
|
+ * @throws IOException
|
|
|
+ */
|
|
|
+ private HttpResponse sendRequest(HttpRequestBase request, String path, List<NameValuePair> parameters)
|
|
|
+ throws URISyntaxException, ClientProtocolException, IOException {
|
|
|
+ HttpClient httpClient = HttpClients.createDefault();
|
|
|
+ request.setURI(createURI(path, parameters));
|
|
|
+ // 采用HTTP Basic验证
|
|
|
+ request.setHeader("Authorization", "Basic " + jsRestAPIConf.getAuthorization());
|
|
|
+ HttpResponse response = httpClient.execute(request);
|
|
|
+ logger.info(request.getMethod() + " " + request.getURI() + " " + response.getStatusLine());
|
|
|
+ return response;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建URI
|
|
|
+ *
|
|
|
+ * @param path
|
|
|
+ * 资源路径
|
|
|
+ * @param parameters
|
|
|
+ * 参数
|
|
|
+ * @return URI对象
|
|
|
+ * @throws URISyntaxException
|
|
|
+ */
|
|
|
+ private URI createURI(String path, List<NameValuePair> parameters) throws URISyntaxException {
|
|
|
+ StringBuilder stringBuilder = new StringBuilder();
|
|
|
+ // 拼接资源全路径
|
|
|
+ stringBuilder.append("/").append(jsRestAPIConf.getContextRoot()).append("/").append(jsRestAPIConf.getRest())
|
|
|
+ .append("/").append(jsRestAPIConf.getResources());
|
|
|
+ if (path != null) {
|
|
|
+ stringBuilder.append(path);
|
|
|
+ }
|
|
|
+ URIBuilder uriBuilder = new URIBuilder();
|
|
|
+ // 协议、主机名、端口号、资源全路径
|
|
|
+ uriBuilder.setScheme(jsRestAPIConf.getSchema()).setHost(jsRestAPIConf.getHost())
|
|
|
+ .setPort(jsRestAPIConf.getPort()).setPath(stringBuilder.toString());
|
|
|
+ // 设置参数
|
|
|
+ if (parameters != null) {
|
|
|
+ uriBuilder.setParameters(parameters);
|
|
|
+ }
|
|
|
+ return uriBuilder.build();
|
|
|
+ }
|
|
|
+
|
|
|
+}
|