zhzhenqin 3 лет назад
Родитель
Сommit
423b218e18

+ 169 - 0
httpclient/RestApiIOUtils.java

@@ -0,0 +1,169 @@
+package com.primeton.dgs.web.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.google.common.net.HttpHeaders;
+import com.google.common.net.MediaType;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.StringReader;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ *
+ * Rest 服务转换. Add:METQI-45,Http RestApi 输入输出工具类
+ *
+ * <pre>
+ *
+ * Created by zhaopx.
+ * User: zhaopx
+ * Date: 2019/9/5
+ * Time: 09:21
+ *
+ * </pre>
+ *
+ * @author zhaopx
+ */
+public class RestApiIOUtils {
+
+
+    /**
+     * 把 Java Bean 转为 JSON 字符串
+     * @param bean
+     * @return
+     */
+    public static String convertString(Object bean) {
+        if(bean instanceof JSON) {
+            // 如果是 JSON 对象
+            return ((JSON)bean).toJSONString();
+        }
+        if(bean instanceof Array || bean instanceof Collection) {
+            // 集合类型、数组类型返回 array 数组
+            return JSONArray.toJSONString(bean);
+        }
+        return JSONObject.toJSONString(bean);
+    }
+
+
+    /**
+     * 把 Java Bean 转为 JSON 字符串
+     * @param bean
+     * @return
+     */
+    public static <T> void output(T bean, OutputStream out) throws IOException {
+        IOUtils.copy(new StringReader(convertString(bean)), out);
+    }
+
+
+    /**
+     * 把 Java Bean 转为 JSON 字符串
+     * @param bean
+     * @return
+     */
+    public static void output(Object bean, Writer out) throws IOException {
+        IOUtils.copy(new StringReader(convertString(bean)), out);
+    }
+
+
+    /**
+     * 把 Java Bean 转为 JSON 字符串,并从 HttpServletResponse 输出
+     * @param bean
+     * @return
+     */
+    public static void output(Object bean,
+                              HttpServletResponse response) {
+        output(bean, response, "UTF-8");
+    }
+
+
+    /**
+     * 把 Java Bean 转为 JSON 字符串,并从 HttpServletResponse 输出
+     * @param bean
+     * @return
+     */
+    public static void output(Object bean,
+                              HttpServletResponse response,
+                              String charset) {
+        response.setHeader(HttpHeaders.CONTENT_TYPE, MediaType.JSON_UTF_8.toString());
+        response.setCharacterEncoding(charset);
+        try {
+            IOUtils.copy(new StringReader(convertString(bean)), response.getWriter());
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+    /**
+     * 把 Rest API 中提交的 JSON 表单数据,转为 clazz 指定的 Bean 类型的 LIST 集合
+     * @param request HttpRestAPI
+     * * @param clazz JSON 能转换的 Class
+     * @return
+     */
+    public static <T> List<T> beanArray(HttpServletRequest request,
+                                        Class<T> clazz) {
+        String contentType = request.getHeader(HttpHeaders.CONTENT_TYPE);
+        try {
+            String json = StringUtils.trim(IOUtils.toString(request.getReader()));
+            // Rest API 接口
+            if(json.startsWith("[") && json.endsWith("]")) {
+                return JSONObject.parseArray(json, clazz);
+            }
+            throw new IllegalArgumentException("错误的数组消息实体。" + json);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+
+    /**
+     * 把 Rest API 中提交的 JSON 表单数据,转为 clazz 指定的 Bean 类型
+     * @param request HttpRestAPI
+     * @param clazz JSON 能转换的 Class
+     * @return
+     */
+    public static <T> T beanObject(HttpServletRequest request,
+                                        Class<T> clazz) {
+        String contentType = request.getHeader(HttpHeaders.CONTENT_TYPE);
+        try {
+            String json = StringUtils.trim(IOUtils.toString(request.getReader()));
+            // Rest API 接口
+            if(json.startsWith("{") && json.endsWith("}")) {
+                return JSONObject.parseObject(json, clazz);
+            }
+            throw new IllegalArgumentException("错误的消息对象实体。" + json);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    /**
+     * 把 Rest API 中提交的 JSON 表单数据,转为 JSON 类型
+     * @param request HttpRestAPI
+     * @return
+     */
+    public static JSON jsonObject(HttpServletRequest request) {
+        String contentType = request.getHeader(HttpHeaders.CONTENT_TYPE);
+        try {
+            String json = StringUtils.trim(IOUtils.toString(request.getReader()));
+            // Rest API 接口
+            if(json.startsWith("{") && json.endsWith("}")) {
+                return JSONObject.parseObject(json);
+            } else if(json.startsWith("[") && json.endsWith("]")) {
+                return JSON.parseArray(json);
+            }
+            throw new IllegalArgumentException("错误的消息对象实体。" + json);
+        } catch (IOException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+}

+ 277 - 4
httpclient/RestApiUtils.java

@@ -4,8 +4,15 @@ package com.yiidata.intergration.api.utils;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
+import com.google.common.io.ByteStreams;
+import com.google.common.net.HttpHeaders;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.apache.http.Header;
+import org.apache.http.HeaderElement;
 import org.apache.http.HttpEntity;
 import org.apache.http.HttpResponse;
+import org.apache.http.NameValuePair;
 import org.apache.http.client.HttpClient;
 import org.apache.http.client.config.RequestConfig;
 import org.apache.http.client.methods.CloseableHttpResponse;
@@ -18,6 +25,7 @@ import org.apache.http.conn.socket.ConnectionSocketFactory;
 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
 import org.apache.http.entity.StringEntity;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
 import org.apache.http.impl.client.BasicCookieStore;
 import org.apache.http.impl.client.CloseableHttpClient;
 import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
@@ -31,7 +39,15 @@ import org.slf4j.LoggerFactory;
 import javax.net.ssl.SSLContext;
 import javax.net.ssl.TrustManager;
 import javax.net.ssl.X509TrustManager;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
 import java.security.cert.CertificateException;
@@ -58,7 +74,7 @@ import java.util.Map;
 public class RestApiUtils {
 
 
-    static Logger log = LoggerFactory.getLogger(com.yiidata.intergration.api.utils.RestApiUtils.class);
+    static Logger log = LoggerFactory.getLogger(RestApiUtils.class);
 
     /**
      * http client
@@ -174,15 +190,42 @@ public class RestApiUtils {
     }
 
 
+    /**
+     * POST 请求,执行远程
+     * @param url
+     * @param jsonStr
+     * @param not200ThrowError
+     * @return
+     * @throws IOException
+     */
     public static Map<String, Object> post(String url, String jsonStr, boolean not200ThrowError) throws IOException {
+        return post(url, jsonStr, new HashMap<>(), not200ThrowError);
+    }
+
+
+    /**
+     * POST 请求执行远程链接
+     * @param url
+     * @param jsonStr 请求 Body 体
+     * @param header 请求头
+     * @param not200ThrowError
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> post(String url, String jsonStr, Map<String, String> header, boolean not200ThrowError) throws IOException {
         HttpPost post = new HttpPost(url);
         StringEntity entity = new StringEntity(jsonStr, "UTF-8");
         entity.setContentType("application/json");
         post.setEntity(entity);
+        if(header != null && !header.isEmpty()) {
+            for (Map.Entry<String, String> entry : header.entrySet()) {
+                post.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
         CloseableHttpResponse resp = null;
         try {
             resp = httpClient.execute(post);
-            log.info("execute url {} return code: {}", url, resp.getStatusLine().getStatusCode());
+            log.info("execute[post] url {} return code: {}", url, resp.getStatusLine().getStatusCode());
             HttpEntity entity1 = resp.getEntity();
             String result = EntityUtils.toString(entity1);
             EntityUtils.consume(entity1);
@@ -250,6 +293,18 @@ public class RestApiUtils {
      * @throws IOException
      */
     public static Map<String, Object> get(String url, Map<String, Object> json, boolean not200ThrowError) throws IOException {
+        return get(url, json, new HashMap<>(), not200ThrowError);
+    }
+
+    /**
+     * 通过 Post 请求调用Rest 接口
+     * @param url
+     * @param json
+     * @param not200ThrowError 为 true 时,当返回不是 200,则抛出异常
+     * @return
+     * @throws IOException
+     */
+    public static Map<String, Object> get(String url, Map<String, Object> json, Map<String, String> header, boolean not200ThrowError) throws IOException {
         HttpGet get = new HttpGet(url);
         if(json != null && !json.isEmpty()) {
             BasicHttpParams params = new BasicHttpParams();
@@ -258,10 +313,15 @@ public class RestApiUtils {
             }
             get.setParams(params);
         }
+        if(header != null && !header.isEmpty()) {
+            for (Map.Entry<String, String> entry : header.entrySet()) {
+                get.addHeader(entry.getKey(), entry.getValue());
+            }
+        }
         CloseableHttpResponse resp = null;
         try {
             resp = httpClient.execute(get);
-            log.info("execute url {} return code: {}", url, resp.getStatusLine().getStatusCode());
+            log.info("execute[get] url {} return code: {}", url, resp.getStatusLine().getStatusCode());
             HttpEntity entity = resp.getEntity();
             String result = EntityUtils.toString(entity);
             EntityUtils.consume(entity);
@@ -285,11 +345,224 @@ public class RestApiUtils {
     }
 
 
+    /**
+     * 根据url下载文件,保存到filepath中
+     *
+     * @param url
+     * @param downloadDir
+     * @return 返回 下载的文件路径
+     */
+    public static String download(String url, File downloadDir) throws IOException {
+        return download(url, new HashMap<>(), downloadDir);
+    }
+
+    /**
+     * 根据url下载文件,保存到filepath中
+     *
+     * @param url
+     * @param downloadDir
+     * @return 返回 下载的文件路径
+     */
+    public static String download(String url, Map<String, String> headers, File downloadDir) throws IOException {
+        if(!downloadDir.exists()) {
+            if(!downloadDir.mkdirs()) {
+                throw new IOException(downloadDir.getAbsolutePath() + " not exists, do can not mkdir.");
+            }
+        }
+        // 构造 Header,并且绑定,下载时登录,其实只要绑定 SessionID 就可以了
+        HttpGet httpget = new HttpGet(url);
+        if(headers != null) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                httpget.setHeader(entry.getKey(), entry.getValue());
+            }
+        }
+
+        // 开始下载
+        HttpResponse response = httpClient.execute(httpget);
+        String fileName = null;
+        final Header contentType = response.getFirstHeader(HttpHeaders.CONTENT_TYPE);
+        if(StringUtils.contains(contentType.getValue(), "application/octet-stream") ||
+                StringUtils.contains(contentType.getValue(), "application/force-download")) {
+            // 下载文件
+            fileName = getFileName(response);
+            if(StringUtils.isBlank(fileName)) {
+                log.warn(response.getFirstHeader(HttpHeaders.CONTENT_DISPOSITION) + " can 'not found filename.");
+            }
+        }
+        if(StringUtils.isBlank(fileName)) {
+            fileName = getFileName(response);
+        }
+        if(StringUtils.isBlank(fileName)) {
+            //无法从 header中获得文件名,如果路径是 /path/for/bar.zip  以 bar.zip 为文件名
+            final String rawPath = httpget.getURI().getRawPath();
+            if(!rawPath.endsWith("/")) {
+                fileName = Paths.get(rawPath).getFileName().toString();
+            }
+            if(StringUtils.isBlank(fileName)) {
+                log.warn("can not found download filename, use system timestamp.");
+                fileName = String.valueOf(System.currentTimeMillis());
+            }
+        }
+        log.info("download filename: {}", fileName);
+        HttpEntity entity = response.getEntity();
+        File filepath = new File(downloadDir, fileName);
+
+        try(InputStream is = entity.getContent(); FileOutputStream fileout = new FileOutputStream(filepath);) {
+            ByteStreams.copy(is, fileout);
+            fileout.flush();
+        }
+        return filepath.getAbsolutePath();
+    }
+
+
+    /**
+     * 获取response header中Content-Disposition中的filename值
+     *
+     * @param response
+     * @return
+     */
+    private static String getFileName(HttpResponse response) {
+        Header contentHeader = response.getFirstHeader(HttpHeaders.CONTENT_DISPOSITION);
+        String filename = null;
+        if (contentHeader != null) {
+            HeaderElement[] values = contentHeader.getElements();
+            if (values.length >= 1) {
+                NameValuePair param = values[0].getParameterByName("filename");
+                if (param != null) {
+                    try {
+                        if(param.getValue() != null && param.getValue().contains("%")) {
+                            //filename = new String(param.getValue().toString().getBytes(), "utf-8");
+                            filename = URLDecoder.decode(param.getValue(), "UTF-8");
+                        } else {
+                            filename = param.getValue();
+                        }
+                    } catch (Exception e) {
+                        filename = param.getValue();
+                    }
+                }
+            }
+        }
+        return filename;
+    }
+
+
+    /**
+     * 根据url上传文件
+     *
+     * @param url
+     * @param uploadFile
+     * @return 返回 下载的文件路径
+     */
+    public static Map<String, Object> upload(String url,
+                                             File uploadFile) throws IOException {
+        return upload(url, null, null, uploadFile, true);
+    }
+
+    /**
+     * 根据url上传文件
+     *
+     * @param url
+     * @param uploadFile
+     * @return 返回 下载的文件路径
+     */
+    public static Map<String, Object> upload(String url,
+                                             Map<String, Object> json,
+                                             File uploadFile) throws IOException {
+        return upload(url, json, null, uploadFile, true);
+    }
+
+    /**
+     * 根据url上传文件
+     *
+     * @param url
+     * @param uploadFile
+     * @return 返回 下载的文件路径
+     */
+    public static Map<String, Object> upload(String url,
+                                             Map<String, Object> json,
+                                             Map<String, String> headers,
+                                             File uploadFile) throws IOException {
+        return upload(url, json, headers, uploadFile, true);
+    }
+
+    /**
+     * 根据url上传文件
+     *
+     * @param url
+     * @param uploadFile
+     * @return 返回 下载的文件路径
+     */
+    public static Map<String, Object> upload(String url,
+                                             Map<String, Object> json,
+                                             Map<String, String> headers,
+                                             File uploadFile,
+                                             boolean not200ThrowError) throws IOException {
+        // 文件夹 或者 是 文件不存在
+        if(!uploadFile.exists()) {
+            throw new FileNotFoundException(uploadFile.getAbsolutePath() + " can not found!");
+        }
+        if(uploadFile.isDirectory()) {
+            throw new IllegalStateException("upload payload must be file, but found directory.");
+        }
+
+        HttpPost httpPost = new HttpPost(url);
+        RequestConfig requestConfig = RequestConfig.custom()
+                .setConnectTimeout(30000)  // 服务器端链接超时设置 30s
+                .setSocketTimeout(10 * 60 * 1000)  // 上传等待 10 分钟
+                .build();
+        httpPost.setConfig(requestConfig);
+        if(headers != null) {
+            for (Map.Entry<String, String> entry : headers.entrySet()) {
+                httpPost.setHeader(entry.getKey(), entry.getValue());
+            }
+        }
+
+        MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
+        multipartEntityBuilder.setCharset(StandardCharsets.UTF_8);
+
+        //multipartEntityBuilder.addBinaryBody("file", file,ContentType.create("image/png"),"abc.pdf");
+        //当设置了setSocketTimeout参数后,以下代码上传PDF不能成功,将setSocketTimeout参数去掉后此可以上传成功。上传图片则没有个限制
+        //multipartEntityBuilder.addBinaryBody("file",file,ContentType.create("application/octet-stream"),"abd.pdf");
+        multipartEntityBuilder.addBinaryBody("file", uploadFile);
+        if(json != null) {
+            for (Map.Entry<String, Object> entry : json.entrySet()) {
+                multipartEntityBuilder.addTextBody(entry.getKey(), (String) entry.getValue());
+            }
+        }
+        HttpEntity httpEntity = multipartEntityBuilder.build();
+        httpPost.setEntity(httpEntity);
+
+        CloseableHttpResponse httpResponse = null;
+        try {
+            httpResponse = httpClient.execute(httpPost);
+            HttpEntity responseEntity = httpResponse.getEntity();
+            int statusCode = httpResponse.getStatusLine().getStatusCode();
+            String result = EntityUtils.toString(responseEntity);
+            EntityUtils.consume(responseEntity);
+            if (not200ThrowError && httpResponse.getStatusLine().getStatusCode() != 200) {
+                throw new IOException(result);
+            }
+            Object jsonResult = JSON.parse(result);
+            JSONObject jsonObject = new JSONObject(2);
+            if (jsonResult instanceof JSONArray) {
+                jsonObject.put("result", jsonResult);
+            } else {
+                jsonObject = (JSONObject) jsonResult;
+            }
+            jsonObject.put("status_code", statusCode);
+            return jsonObject;
+        } finally {
+            if(httpResponse != null) {
+                httpResponse.close();
+            }
+        }
+    }
+
     /**
      * 关闭 RPC 调用
      * @throws IOException
      */
-    public void shutdown() throws IOException {
+    public static void shutdown() throws IOException {
         httpClient.close();
     }
 }

+ 3 - 3
jpa-sqltemplate/DAOServiceImpl.java

@@ -264,7 +264,7 @@ public class DAOServiceImpl implements IDAOService {
 	 */
 	@Override
 	public List queryById(String id, Map<String, Object> params, Class entityClass) {
-		final String sql = getSQL(id);
+		final String sql = getSQL(id, params);
 		if(StringUtils.isBlank(sql)) {
 			throw new IllegalArgumentException("undefined statement id: " + id);
 		}
@@ -291,7 +291,7 @@ public class DAOServiceImpl implements IDAOService {
 	 */
 	@Override
 	public List queryById(String id, Map<String, Object> params, Class entityClass, final int firstResult, final int maxResult) {
-		final String sql = getSQL(id);
+		final String sql = getSQL(id, params);
 		if(StringUtils.isBlank(sql)) {
 			throw new IllegalArgumentException("undefined statement id: " + id);
 		}
@@ -417,7 +417,7 @@ public class DAOServiceImpl implements IDAOService {
 
 	@Override
 	public int updateById(String id, Map<String, Object> params) {
-		final String sql = getSQL(id);
+		final String sql = getSQL(id, params);
 		if(StringUtils.isBlank(sql)) {
 			throw new IllegalArgumentException("undefined statement id: " + id);
 		}

+ 4 - 0
jpa-sqltemplate/DatabaseRecognizer.java

@@ -91,6 +91,10 @@ public class DatabaseRecognizer implements InitializingBean {
 		}
 		for (Iterator<String> it = databaseNames.keySet().iterator(); it.hasNext();) {
 			String key = it.next();
+			// 忽略大小写,匹配一次
+			if(StringUtils.equalsIgnoreCase(dbFullName, key)) {
+				return databaseNames.get(key);
+			}
 			// 正则表达式匹配,如DB2的产品名称可能返回不一样,如:DB2/NT, DB2/LINUX, DB2/SUN
 			if (dbFullName.matches(key)) {
 				return databaseNames.get(key);

+ 94 - 0
spring-zuul/ApiGatewayConfig.java

@@ -0,0 +1,94 @@
+package com.yiidata.dataops.server.config;
+
+import com.yiidata.dataops.server.modules.gateway.entity.OpsGatewayServer;
+import com.yiidata.dataops.server.modules.gateway.service.OpsGatewayServerService;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.web.ServerProperties;
+import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
+import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+/**
+ * <pre>
+ *
+ * Created by zhenqin.
+ * User: zhenqin
+ * Date: 2022/4/25
+ * Time: 下午7:08
+ * Vendor: yiidata.com
+ *
+ * </pre>
+ *
+ * @author zhenqin
+ */
+@Slf4j
+@Configuration
+public class ApiGatewayConfig implements InitializingBean {
+
+
+    @Autowired
+    OpsGatewayServerService opsGatewayServerService;
+
+    @Autowired
+    ServerProperties serverProperties;
+
+
+    @Autowired
+    ZuulProperties zuulProperties;
+
+
+    @Override
+    public void afterPropertiesSet() throws Exception {
+        final List<OpsGatewayServer> gatewayServers = opsGatewayServerService.list();
+        final Map<String, List<OpsGatewayServer>> listMap = gatewayServers.stream()
+                .collect(Collectors.groupingBy(OpsGatewayServer::getApiRouter));
+
+        for (Map.Entry<String, List<OpsGatewayServer>> entry : listMap.entrySet()) {
+            if(entry.getValue() == null || entry.getValue().isEmpty()) {
+                continue;
+            }
+
+            // 代理地址
+            String url = entry.getValue().stream()
+                    .map(OpsGatewayServer::getApiUrl)
+                    .map(StringUtils::trimToNull)
+                    .filter(StringUtils::isNotBlank)
+                    .collect(Collectors.joining(","));
+
+            // 代理路由
+            String path = Optional.ofNullable(StringUtils.trimToNull(entry.getValue().get(0).getApiPath())).orElse("/" + entry.getKey() + "/**");
+            final ZuulProperties.ZuulRoute route = new ZuulProperties.ZuulRoute();
+            route.setId(entry.getKey());
+            route.setPath(path);
+            route.setUrl(url);
+
+            log.info("add router {} to path: {}", path, url);
+            zuulProperties.getRoutes().putIfAbsent(entry.getKey(), route);
+        }
+
+        // 初始化
+        zuulProperties.init();
+    }
+
+
+
+    /**
+     * 支持简单的负载均衡
+     * @return
+     */
+    @Bean
+    public SimpleRouteLocator simpleRouteLocator() {
+        return new ApiRouteLocator(this.serverProperties.getServlet().getContextPath(),
+                this.zuulProperties);
+    }
+
+}

+ 94 - 0
spring-zuul/ApiRouteLocator.java

@@ -0,0 +1,94 @@
+package com.yiidata.dataops.server.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.netflix.zuul.filters.Route;
+import org.springframework.cloud.netflix.zuul.filters.SimpleRouteLocator;
+import org.springframework.cloud.netflix.zuul.filters.ZuulProperties;
+
+import java.util.Random;
+
+/**
+ * <pre>
+ *
+ * Created by zhenqin.
+ * User: zhenqin
+ * Date: 2022/4/25
+ * Time: 下午7:12
+ * Vendor: yiidata.com
+ *
+ * </pre>
+ *
+ * @author zhenqin
+ */
+@Slf4j
+public class ApiRouteLocator extends SimpleRouteLocator {
+
+    /**
+     * zull 配置
+     */
+    final ZuulProperties properties;
+
+
+    /**
+     * 随机策略
+     */
+    final Random r = new Random();
+
+    public ApiRouteLocator(String servletPath, ZuulProperties properties) {
+        super(servletPath, properties);
+        this.properties = properties;
+    }
+
+
+    @Override
+    protected Route getRoute(ZuulProperties.ZuulRoute route, String path) {
+        if (route == null) {
+            return null;
+        }
+        if (log.isDebugEnabled()) {
+            log.debug("route matched=" + route);
+        }
+        String targetPath = path;
+        String prefix = this.properties.getPrefix();
+        if (prefix.endsWith("/")) {
+            prefix = prefix.substring(0, prefix.length() - 1);
+        }
+        if (path.startsWith(prefix + "/") && this.properties.isStripPrefix()) {
+            targetPath = path.substring(prefix.length());
+        }
+        if (route.isStripPrefix()) {
+            int index = route.getPath().indexOf("*") - 1;
+            if (index > 0) {
+                String routePrefix = route.getPath().substring(0, index);
+                targetPath = targetPath.replaceFirst(routePrefix, "");
+                prefix = prefix + routePrefix;
+            }
+        }
+        Boolean retryable = this.properties.getRetryable();
+        if (route.getRetryable() != null) {
+            retryable = route.getRetryable();
+        }
+
+        // 如果包含逗号,说明有多个地址,需要负载均衡
+        if(route.getLocation().contains(",")) {
+            final String[] segs = route.getLocation().split(",");
+            // 随机策略
+            String loc = segs[r.nextInt(segs.length)];
+            //log.info("loc->> " + loc);
+            return new Route(route.getId(),
+                    targetPath,
+                    loc,
+                    prefix,
+                    retryable,
+                    route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
+                    route.isStripPrefix());
+        }
+        return new Route(route.getId(),
+                targetPath,
+                route.getLocation(),
+                prefix,
+                retryable,
+                route.isCustomSensitiveHeaders() ? route.getSensitiveHeaders() : null,
+                route.isStripPrefix());
+    }
+}

+ 1 - 1
springjdbc-sql-template/DAOService.java

@@ -154,7 +154,7 @@ public class DAOService {
      * @return 返回 ResultTransformer 的转换结果
      */
     public <T> List<T> queryById(String id, Map<String, Object> params, Class<T> entityClass) {
-        final String sql = getSQL(id);
+        final String sql = getSQL(id, params);
         if (StringUtils.isBlank(sql)) {
             throw new IllegalArgumentException("undefined statement id: " + id);
         }

+ 283 - 0
zip/UncompressFactory.java

@@ -0,0 +1,283 @@
+package com.yiidata.parcel.utils;
+
+import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang.StringUtils;
+import org.apache.tools.tar.TarEntry;
+import org.apache.tools.tar.TarInputStream;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.FileSystem;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardOpenOption;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+/**
+ * Created by sssd on 2017/8/18.
+ */
+public abstract class UncompressFactory {
+
+
+    protected static Logger logger = LoggerFactory.getLogger(UncompressFactory.class);
+
+
+    private UncompressFactory() {
+
+    }
+
+    /**
+     *  定义解压抽象方法
+     * @param hdfsinput   hdfs 输入路径
+     * @param fs          hadaoop confit
+     * @param uncompressPath    解压后输出路径
+     * @return
+     */
+    public abstract  List<String> uncompress(Path hdfsinput, FileSystem fs, Path uncompressPath);
+
+    /**
+     * 根据文件扩展名,返回对应的解压方法。
+     * @param sub
+     * @return
+     */
+    public static UncompressFactory getUncompressFactory(String sub) {
+        if("zip".equals(sub)) {
+            return new ZipUncompress();
+        } else if("tar".equals(sub)) {
+            return new TarUncompress();
+        } else if("gzip".equals(sub)) {
+            return new TgzUncompress();
+        } else if("tgz".equals(sub)) {
+            return new TgzUncompress();
+        } else if("gz".equals(sub)) {
+            return new TgzUncompress();
+        }
+        return null;
+    }
+
+    /**
+     *   .zip解压
+     */
+    static class ZipUncompress extends UncompressFactory {
+
+        @Override
+        public List<String> uncompress(Path hdfsinput, FileSystem fs, Path uncompressPath) {
+            try {
+                return uncompressZip(fs, hdfsinput, uncompressPath);   // hadoop, hdfs输入路径, 解压保存路径
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+
+    /**
+     * .tar 解压
+     */
+    static class TarUncompress extends UncompressFactory {
+
+        @Override
+        public List<String> uncompress(Path hdfsinput, FileSystem fs, Path uncompressPath) {
+            try {
+                return uncompressTar(fs, hdfsinput, uncompressPath);   // hadoop, hdfs输入路径, 解压保存路径
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+    /**
+     * .tgz 解压
+     */
+    static class TgzUncompress extends UncompressFactory {
+
+        @Override
+        public List<String> uncompress(Path hdfsinput, FileSystem fs, Path uncompressPath) {
+            try {
+                Path temp = uncompressTgz(fs, hdfsinput);
+                return uncompressTar(fs, temp, uncompressPath);   // hadoop, hdfs输入路径, 解压保存路径
+            } catch (IOException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+    }
+
+
+    /**
+     * zip解压
+     * @param fs
+     * @param input
+     * @param uncompressPath
+     * @return
+     * @throws IOException
+     */
+    public static List<String> uncompressZip(FileSystem fs, Path input, Path uncompressPath) throws IOException {
+        OutputStream out = null;
+        List<String> paths = new ArrayList<String>();
+        ZipInputStream zipInputStream = null;
+        try {
+            if (!Files.exists(input)) {
+                throw new IllegalArgumentException(input.toString() + " does not exist");
+            }
+            zipInputStream = new ZipInputStream(Files.newInputStream(input));
+            ZipEntry zipEntry = null;
+            Path path = null;
+            while ((zipEntry = zipInputStream.getNextEntry()) != null ) {
+                String entryName = zipEntry.getName();
+                if (zipEntry.isDirectory()) {
+                    // 如果是文件夹,创建文件夹并加速循环
+                    path = Paths.get(uncompressPath.toString(), entryName);
+                    Files.createDirectories(path);
+                    continue;
+                }
+                path = Paths.get(uncompressPath.toString(), entryName);
+                out = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW);
+                IOUtils.copy(zipInputStream, out);
+                out.flush();
+                zipInputStream.closeEntry();
+                paths.add(path.toString());
+                logger.info("解压文件: {} 成功!", entryName);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            if(out != null){
+                try {
+                    out.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if(zipInputStream != null){
+                try {
+                    zipInputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return paths;
+    }
+
+
+    /**
+     *  .Tar 解压
+     * @param fs
+     * @param input
+     * @param uncompressPath
+     * @return
+     * @throws IOException
+     */
+    public static List<String> uncompressTar(FileSystem fs, Path input, Path uncompressPath) throws IOException {
+        OutputStream out = null;
+        List<String> paths = new ArrayList<String>();
+        TarInputStream tarInputStream = null;
+        if (!Files.exists(input)) {
+            throw new IllegalArgumentException(input.toString() + " does not exist");
+        }
+        try {
+            tarInputStream = new TarInputStream(Files.newInputStream(input));
+            TarEntry entry = null;
+            Path path = null;
+            while ( ( entry = tarInputStream.getNextEntry()) != null ){
+                String entryName = entry.getName();
+                if(entry.isDirectory()){
+                    path = Paths.get(uncompressPath.toString(), entryName);
+                    Files.createDirectories(path);
+                    continue;
+                }
+                path = Paths.get(uncompressPath.toString(), entryName);
+                out = Files.newOutputStream(path, StandardOpenOption.CREATE_NEW);
+                IOUtils.copy(tarInputStream, out);
+                out.flush();
+                paths.add(path.toString());
+                logger.info("解压文件: {} 成功!", entryName);
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if ( out != null){
+                try {
+                    out.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if(tarInputStream != null){
+                try {
+                    tarInputStream.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return paths;
+    }
+
+
+    /**
+     * .tgz 解压
+     * @param fs
+     * @param input
+     * @return
+     * @throws IOException
+     */
+    public static Path uncompressTgz(FileSystem fs, Path input) throws IOException {
+        int buffersize = 2048;
+        OutputStream out = null;
+        GzipCompressorInputStream gzin = null;
+        InputStream hdfsinput = null;
+        String temppath = null;
+        Path outPath = null;
+        if (!Files.exists(input)) {
+            throw new IllegalArgumentException(input.toString() + " does not exist");
+        }
+        int i = input.toString().lastIndexOf("/");
+        if ( i > 0){
+            temppath = StringUtils.trimToNull(input.toString().substring(0,i));
+        }
+        try {
+            hdfsinput = Files.newInputStream(input);
+            BufferedInputStream in = new BufferedInputStream(hdfsinput);
+            outPath = Paths.get(temppath, "tmp-" + System.currentTimeMillis() + ".tar");
+            if( Files.exists(outPath)){
+                Files.delete(outPath);
+            }
+            out = Files.newOutputStream(outPath);
+            gzin = new GzipCompressorInputStream(in);
+            final byte[] buffer = new byte[buffersize];
+            int n = 0;
+            while (-1 != (n = gzin.read(buffer))) {
+                out.write(buffer, 0, n);
+            }
+            logger.info("临时文件的保存路径为:" + outPath.toString());
+        } catch (IOException e) {
+            e.printStackTrace();
+        } finally {
+            if(hdfsinput != null){
+                try {
+                    hdfsinput.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+            if(out!= null){
+                try {
+                    out.close();
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        return outPath;
+    }
+}