hecheng 3 éve
szülő
commit
5afd84e4a8

+ 82 - 82
zd-gateway/pom.xml

@@ -115,88 +115,88 @@
             </plugin>
 
             <!-- docker的maven插件 -->
-            <plugin>
-                <groupId>io.fabric8</groupId>
-                <artifactId>docker-maven-plugin</artifactId>
-                <version>${docker.maven.verion}</version>
-                <executions>
-                    <!--执行 mvn package 时 自动构建docker镜像并推送到仓库 -->
-                    <execution>
-                        <id>default</id>
-                        <phase>package</phase>
-                        <goals>
-                            <!--删除老镜像-->
-                            <goal>remove</goal>
-                            <!--构建镜像-->
-                            <goal>build</goal>
-                            <!--推送镜像到阿里云-->
-<!--                            <goal>push</goal>-->
-                            <!--运行镜像-->
-                            <goal>run</goal>
-                        </goals>
-                    </execution>
-                </executions>
-                <configuration>
-                    <!-- docker主机 -->
-                    <dockerHost>tcp://192.168.1.88:2375</dockerHost>
-                    <authConfig>
-                        <!-- registry服务的认证-->
-                        <username>${docker.registry.username}</username>
-                        <password>${docker.registry.password}</password>
-                    </authConfig>
-                    <images>
-                        <image>
-                            <!-- [命名空间] / [镜像名称:版本号] -->
-                            <name>${docker.registry}/${docker.namespace}/${project.artifactId}</name>
-                            <!-- 仓库地址 -->
-                            <registry>${docker.registry}</registry>
-                            <build>
-                                <!-- dockerFile文件路径-->
-                                <dockerFile>${project.basedir}/Dockerfile</dockerFile>
-                                <tags>
-                                    <!-- 构建版本-->
-                                    <tag>${project.version}</tag>
-                                </tags>
-                            </build>
-                            <run>
-                                <!-- 环境变量配置-->
-                                <env>
-                                    <!-- 次数可参考 docker/zd/docker-compose.env 下的变量根据实际关联地址配置 -->
-                                    <NACOS_HOST>192.168.1.88</NACOS_HOST>
-                                    <REDIS_HOST>192.168.1.43</REDIS_HOST>
-                                </env>
-                                <!-- 端口映射-->
-                                <ports>
-                                    <port>9081:8080</port>
-                                </ports>
-                                <!-- 挂载卷-->
-                                <volumes>
-                                    <bind>
-                                        <!-- 可多配置-->
-                                        <volume>
-                                            /zd/logs/${project.artifactId}:/logs/${project.artifactId}
-                                        </volume>
-                                    </bind>
-                                </volumes>
-                                <autoRemove>false</autoRemove>
-                                <!-- 重启策略-->
-                                <restartPolicy>
-                                    <!-- 总是-->
-                                    <name>always</name>
-                                    <!-- 失败时重启-->
-<!--                                    <name>on-failure</name>-->
-                                    <!-- 重启次数,当上方name配置采用on-failure时生效-->
-<!--                                    <retry>3</retry>-->
-                                </restartPolicy>
-                            </run>
-                        </image>
-                    </images>
-                    <buildArgs>
-                        <!-- dockerfile参数,指定jar路径 -->
-                        <JAR_FILE>${project.artifactId}.jar</JAR_FILE>
-                    </buildArgs>
-                </configuration>
-            </plugin>
+<!--            <plugin>-->
+<!--                <groupId>io.fabric8</groupId>-->
+<!--                <artifactId>docker-maven-plugin</artifactId>-->
+<!--                <version>${docker.maven.verion}</version>-->
+<!--                <executions>-->
+<!--                    &lt;!&ndash;执行 mvn package 时 自动构建docker镜像并推送到仓库 &ndash;&gt;-->
+<!--                    <execution>-->
+<!--                        <id>default</id>-->
+<!--                        <phase>package</phase>-->
+<!--                        <goals>-->
+<!--                            &lt;!&ndash;删除老镜像&ndash;&gt;-->
+<!--                            <goal>remove</goal>-->
+<!--                            &lt;!&ndash;构建镜像&ndash;&gt;-->
+<!--                            <goal>build</goal>-->
+<!--                            &lt;!&ndash;推送镜像到阿里云&ndash;&gt;-->
+<!--&lt;!&ndash;                            <goal>push</goal>&ndash;&gt;-->
+<!--                            &lt;!&ndash;运行镜像&ndash;&gt;-->
+<!--                            <goal>run</goal>-->
+<!--                        </goals>-->
+<!--                    </execution>-->
+<!--                </executions>-->
+<!--                <configuration>-->
+<!--                    &lt;!&ndash; docker主机 &ndash;&gt;-->
+<!--                    <dockerHost>tcp://192.168.1.88:2375</dockerHost>-->
+<!--                    <authConfig>-->
+<!--                        &lt;!&ndash; registry服务的认证&ndash;&gt;-->
+<!--                        <username>${docker.registry.username}</username>-->
+<!--                        <password>${docker.registry.password}</password>-->
+<!--                    </authConfig>-->
+<!--                    <images>-->
+<!--                        <image>-->
+<!--                            &lt;!&ndash; [命名空间] / [镜像名称:版本号] &ndash;&gt;-->
+<!--                            <name>${docker.registry}/${docker.namespace}/${project.artifactId}</name>-->
+<!--                            &lt;!&ndash; 仓库地址 &ndash;&gt;-->
+<!--                            <registry>${docker.registry}</registry>-->
+<!--                            <build>-->
+<!--                                &lt;!&ndash; dockerFile文件路径&ndash;&gt;-->
+<!--                                <dockerFile>${project.basedir}/Dockerfile</dockerFile>-->
+<!--                                <tags>-->
+<!--                                    &lt;!&ndash; 构建版本&ndash;&gt;-->
+<!--                                    <tag>${project.version}</tag>-->
+<!--                                </tags>-->
+<!--                            </build>-->
+<!--                            <run>-->
+<!--                                &lt;!&ndash; 环境变量配置&ndash;&gt;-->
+<!--                                <env>-->
+<!--                                    &lt;!&ndash; 次数可参考 docker/zd/docker-compose.env 下的变量根据实际关联地址配置 &ndash;&gt;-->
+<!--                                    <NACOS_HOST>192.168.1.88</NACOS_HOST>-->
+<!--                                    <REDIS_HOST>192.168.1.43</REDIS_HOST>-->
+<!--                                </env>-->
+<!--                                &lt;!&ndash; 端口映射&ndash;&gt;-->
+<!--                                <ports>-->
+<!--                                    <port>9081:8080</port>-->
+<!--                                </ports>-->
+<!--                                &lt;!&ndash; 挂载卷&ndash;&gt;-->
+<!--                                <volumes>-->
+<!--                                    <bind>-->
+<!--                                        &lt;!&ndash; 可多配置&ndash;&gt;-->
+<!--                                        <volume>-->
+<!--                                            /zd/logs/${project.artifactId}:/logs/${project.artifactId}-->
+<!--                                        </volume>-->
+<!--                                    </bind>-->
+<!--                                </volumes>-->
+<!--                                <autoRemove>false</autoRemove>-->
+<!--                                &lt;!&ndash; 重启策略&ndash;&gt;-->
+<!--                                <restartPolicy>-->
+<!--                                    &lt;!&ndash; 总是&ndash;&gt;-->
+<!--                                    <name>always</name>-->
+<!--                                    &lt;!&ndash; 失败时重启&ndash;&gt;-->
+<!--&lt;!&ndash;                                    <name>on-failure</name>&ndash;&gt;-->
+<!--                                    &lt;!&ndash; 重启次数,当上方name配置采用on-failure时生效&ndash;&gt;-->
+<!--&lt;!&ndash;                                    <retry>3</retry>&ndash;&gt;-->
+<!--                                </restartPolicy>-->
+<!--                            </run>-->
+<!--                        </image>-->
+<!--                    </images>-->
+<!--                    <buildArgs>-->
+<!--                        &lt;!&ndash; dockerfile参数,指定jar路径 &ndash;&gt;-->
+<!--                        <JAR_FILE>${project.artifactId}.jar</JAR_FILE>-->
+<!--                    </buildArgs>-->
+<!--                </configuration>-->
+<!--            </plugin>-->
         </plugins>
     </build>
 

+ 2 - 1
zd-modules/zd-forward/src/main/java/com/zd/forward/ForwardApp.java

@@ -4,6 +4,7 @@ import com.zd.common.core.constant.Constants;
 import com.zd.common.core.properties.SnowflakeProperties;
 import com.zd.common.security.annotation.EnableCustomConfig;
 import com.zd.common.security.annotation.EnableRyFeignClients;
+import com.zd.forward.config.AlgorithmYml;
 import com.zd.forward.properties.FireProperties;
 import com.zd.forward.serivce.LoginService;
 import org.springframework.boot.SpringApplication;
@@ -20,7 +21,7 @@ import zd.common.mqtt.config.MqttProperties;
 @EnableCustomConfig
 @EnableRyFeignClients
 @SpringBootApplication(exclude = {DataSourceAutoConfiguration.class},scanBasePackages = {Constants.BASE_PACKAGE})
-@EnableConfigurationProperties({MqttProperties.class, FireProperties.class, SnowflakeProperties.class})
+@EnableConfigurationProperties({MqttProperties.class, FireProperties.class, SnowflakeProperties.class, AlgorithmYml.class})
 @EnableOpenApi
 public class ForwardApp {
 

+ 1 - 1
zd-modules/zd-forward/src/main/java/com/zd/forward/config/AlgorithmYml.java

@@ -286,7 +286,7 @@ public class AlgorithmYml {
         this.algorithmMap = algorithmMap;
     }
 
-    public AlgorithmYml.CheckValid getCheckValid(Integer code) {
+    public CheckValid getCheckValid(Integer code) {
         return Optional.ofNullable(getAlgorithmMap().get(code))
                 .orElseThrow(() -> new ServiceException("未配置对应算法code:" + code));
     }

+ 20 - 25
zd-modules/zd-forward/src/main/java/com/zd/forward/listener/StartListener.java

@@ -10,8 +10,6 @@ import org.springframework.stereotype.Component;
 
 import javax.annotation.Resource;
 import java.io.IOException;
-import java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.TimeUnit;
 
 /**
  * 监听Spring容器启动完成,完成后启动Netty服务器
@@ -25,35 +23,32 @@ public class StartListener implements CommandLineRunner {
     private FireImageService fireImageService;
     @Resource
     private FireProperties fireProperties;
-
-    @Resource
-    private ScheduledExecutorService scheduledExecutorService;
-
     @Resource
     private ThreadPoolTaskExecutor taskExecutor;
 
     @Override
     public void run(String... args) {
+        String streamUrl = fireProperties.getStreamUrl();
+        if (streamUrl == null) {
+            log.error("=========调用产生异常:未配置流媒体地址============");
+            return;
+        }
         //定时调度,无法使用scheduledExecutorService完成定时调度,scheduledExecutorService默认实现了jdk自动关闭策略,默认会杀死程序,此处手动实现延时调用
-//        taskExecutor.execute(new Runnable() {
-//            @Override
-//            public void run() {
-//                try {
-//                    String streamUrl = fireProperties.getStreamUrl();
-//                    if (streamUrl == null) {
-//                        throw new ServiceException("未配置流媒体地址");
-//                    }
-//                    while (true) {
-//                        fireImageService.catchImage();
-//                        Thread.sleep(fireProperties.getWaitTime() * 1000L);
-//                    }
-//                } catch (ServiceException | IOException | InterruptedException e) {
-//                    //异常回调,防止系统因异常问题被杀死
-//                    log.error("=========调用产生异常:{}============", e.getMessage());
-//                    run();
-//                }
-//            }
-//        });
+        taskExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                try {
+                    while (true) {
+                        fireImageService.catchImage();
+                        Thread.sleep(fireProperties.getWaitTime() * 1000L);
+                    }
+                } catch (ServiceException | IOException | InterruptedException e) {
+                    //异常回调,防止系统因异常问题被杀死
+                    log.error("=========调用产生异常:{}============", e.getMessage());
+                    run();
+                }
+            }
+        });
     }
 
 }

+ 0 - 1
zd-modules/zd-forward/src/main/java/com/zd/forward/serivce/CheckService.java

@@ -53,7 +53,6 @@ import java.util.*;
 import static com.zd.forward.utils.HttpUtils.*;
 
 @Service
-@EnableConfigurationProperties(AlgorithmYml.class)
 @RefreshScope
 public class CheckService {
     Logger logger = LoggerFactory.getLogger(CheckService.class);

+ 93 - 0
zd-modules/zd-forward/src/main/java/com/zd/forward/util/Base64DecodedMultipartFile.java

@@ -0,0 +1,93 @@
+package com.zd.forward.util;
+
+import org.springframework.web.multipart.MultipartFile;
+import sun.misc.BASE64Decoder;
+
+import java.io.*;
+
+public class Base64DecodedMultipartFile implements MultipartFile {
+    private final byte[] imgContent;
+    private final String header;
+
+    private Base64DecodedMultipartFile(byte[] imgContent, String header) {
+        this.imgContent = imgContent;
+        this.header = header.split(";")[0];
+    }
+
+    @Override
+    public String getName() {
+        return System.currentTimeMillis() + Math.random() + "." + header.split("/")[1];
+    }
+
+    @Override
+    public String getOriginalFilename() {
+        return header;
+    }
+
+    @Override
+    public String getContentType() {
+        String splitComm[]=header.split(":");
+        if(splitComm.length>1){
+            return header.split(":")[1];
+        }
+        return header.split(":")[0];
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return imgContent == null || imgContent.length == 0;
+    }
+
+    @Override
+    public long getSize() {
+        return imgContent.length;
+    }
+
+    @Override
+    public byte[] getBytes() throws IOException {
+        return imgContent;
+    }
+
+    @Override
+    public InputStream getInputStream() throws IOException {
+        return new ByteArrayInputStream(imgContent);
+    }
+
+    @Override
+    public void transferTo(File dest) throws IOException, IllegalStateException {
+        new FileOutputStream(dest).write(imgContent);
+    }
+
+    /**
+     * base64转MultipartFile文件
+     *
+     * @param base64
+     * @return org.springframework.web.multipart.MultipartFile
+     * @author xianghl
+     * @date 2021/4/25/025 16:33
+     */
+    public static MultipartFile base64ToMultipart(String base64) {
+        try {
+            String[] baseStrs = base64.split(",");
+            BASE64Decoder decoder = new BASE64Decoder();
+            byte[] b;
+            if (baseStrs.length > 1) {
+                b = decoder.decodeBuffer(baseStrs[1]);
+            } else {
+                b = decoder.decodeBuffer(baseStrs[0]);
+            }
+            for (int i = 0; i < b.length; ++i) {
+                if (b[i] < 0) {
+                    b[i] += 256;
+                }
+            }
+            if (baseStrs.length > 1) {
+                return new Base64DecodedMultipartFile(b, "data:image/jpeg;base64");
+            }
+            return new Base64DecodedMultipartFile(b, baseStrs[0]);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+}

+ 76 - 0
zd-modules/zd-forward/src/main/java/com/zd/forward/util/Base64ToMultipartFile.java

@@ -0,0 +1,76 @@
+package com.zd.forward.util;
+
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.util.Base64;
+
+public class Base64ToMultipartFile implements MultipartFile{
+    private final byte[] fileContent;
+
+    private final String extension;
+    private final String contentType;
+
+
+    /**
+     * @param base64
+     * @param dataUri     格式类似于: data:image/png;base64
+     */
+    public Base64ToMultipartFile(String base64, String dataUri) {
+        this.fileContent = Base64.getDecoder().decode(base64.getBytes(StandardCharsets.UTF_8));
+        this.extension = dataUri.split(";")[0].split("/")[1];
+        this.contentType = dataUri.split(";")[0].split(":")[1];
+    }
+
+    public Base64ToMultipartFile(String base64, String extension, String contentType) {
+        this.fileContent = Base64.getDecoder().decode(base64.getBytes(StandardCharsets.UTF_8));
+        this.extension = extension;
+        this.contentType = contentType;
+    }
+
+    @Override
+    public String getName() {
+        return "param_" + System.currentTimeMillis();
+    }
+
+    @Override
+    public String getOriginalFilename() {
+        return "file_" + System.currentTimeMillis() + "." + extension;
+    }
+
+    @Override
+    public String getContentType() {
+        return contentType;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return fileContent == null || fileContent.length == 0;
+    }
+
+    @Override
+    public long getSize() {
+        return fileContent.length;
+    }
+
+    @Override
+    public byte[] getBytes() throws IOException {
+        return fileContent;
+    }
+
+    @Override
+    public ByteArrayInputStream getInputStream() throws IOException {
+        return new ByteArrayInputStream(fileContent);
+    }
+
+    @Override
+    public void transferTo(File file) throws IOException, IllegalStateException {
+        try (FileOutputStream fos = new FileOutputStream(file)) {
+            fos.write(fileContent);
+        }
+    }
+}

+ 201 - 0
zd-modules/zd-forward/src/main/java/com/zd/forward/util/FileUploadUtils.java

@@ -0,0 +1,201 @@
+package com.zd.forward.util;
+
+import com.zd.common.core.exception.ServiceException;
+import com.zd.common.core.exception.file.FileNameLengthLimitExceededException;
+import com.zd.common.core.exception.file.FileSizeLimitExceededException;
+import com.zd.common.core.exception.file.InvalidExtensionException;
+import com.zd.common.core.utils.DateUtils;
+import com.zd.common.core.utils.IdUtils;
+import com.zd.common.core.utils.StringUtils;
+import com.zd.common.core.utils.file.MimeTypeUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * 文件上传工具类
+ *
+ * @author zd
+ */
+public class FileUploadUtils {
+    /**
+     * 默认大小 50M
+     */
+    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
+
+    /**
+     * 默认的文件名最大长度 100
+     */
+    public static final int DEFAULT_FILE_NAME_LENGTH = 100;
+
+    /**
+     * 根据文件路径上传
+     *
+     * @param baseDir 相对应用的基目录
+     * @param file    上传的文件
+     * @return 文件名称
+     * @throws IOException
+     */
+    public static final String upload(String baseDir, MultipartFile file) throws IOException {
+        try {
+            return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
+        } catch (Exception e) {
+            throw new IOException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 文件上传
+     *
+     * @param baseDir          相对应用的基目录
+     * @param file             上传的文件
+     * @param allowedExtension 上传文件类型
+     * @return 返回上传成功的文件名
+     * @throws FileSizeLimitExceededException       如果超出最大大小
+     * @throws FileNameLengthLimitExceededException 文件名太长
+     * @throws IOException                          比如读写文件出错时
+     * @throws InvalidExtensionException            文件校验异常
+     */
+    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
+            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
+            InvalidExtensionException {
+        int fileNamelength = file.getOriginalFilename().length();
+        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
+//            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
+            throw new ServiceException("图片名字太长,请修改名字后,从新上传!");
+        }
+
+        assertAllowed(file, allowedExtension);
+
+        String fileName = extractFilename(file);
+
+        File desc = getAbsoluteFile(baseDir, fileName);
+        file.transferTo(desc);
+        String pathFileName = getPathFileName(fileName);
+        return pathFileName;
+    }
+//
+//    /**
+//     * 文件上传 -不修改文件名
+//     *
+//     * @param baseDir          相对应用的基目录
+//     * @param file             上传的文件
+//     * @param allowedExtension 上传文件类型
+//     * @return 返回上传成功的文件名
+//     * @throws FileSizeLimitExceededException       如果超出最大大小
+//     * @throws FileNameLengthLimitExceededException 文件名太长
+//     * @throws IOException                          比如读写文件出错时
+//     * @throws InvalidExtensionException            文件校验异常
+//     */
+//    public static final String uploadNoUpdateName(String baseDir, MultipartFile file, String[] allowedExtension)
+//            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
+//            InvalidExtensionException {
+//        int fileNamelength = file.getOriginalFilename().length();
+//        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
+//            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
+//        }
+//
+//        assertAllowed(file, allowedExtension);
+//
+////        String fileName = extractFilename(file);
+//
+//        String originalFilename = file.getOriginalFilename();
+//        File desc = getAbsoluteFile(baseDir, originalFilename);
+//        file.transferTo(desc);
+//        String pathFileName = getPathFileName(originalFilename);
+//        return pathFileName;
+//    }
+
+    /**
+     * 编码文件名
+     */
+    public static final String extractFilename(MultipartFile file) {
+        String fileName = file.getOriginalFilename();
+        String extension = getExtension(file);
+        fileName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
+        return fileName;
+    }
+
+    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
+        File desc = new File(uploadDir + File.separator + fileName);
+
+        if (!desc.exists()) {
+            if (!desc.getParentFile().exists()) {
+                desc.getParentFile().mkdirs();
+            }
+        }
+        return desc.isAbsolute() ? desc : desc.getAbsoluteFile();
+    }
+
+    private static final String getPathFileName(String fileName) throws IOException {
+        String pathFileName = "/" + fileName;
+        return pathFileName;
+    }
+
+    /**
+     * 文件大小校验
+     *
+     * @param file 上传的文件
+     * @throws FileSizeLimitExceededException 如果超出最大大小
+     * @throws InvalidExtensionException      文件校验异常
+     */
+    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
+            throws FileSizeLimitExceededException, InvalidExtensionException {
+        long size = file.getSize();
+        if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE) {
+            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
+        }
+
+        String fileName = file.getOriginalFilename();
+        String extension = getExtension(file);
+        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension)) {
+            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION) {
+                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
+                        fileName);
+            } else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION) {
+                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
+                        fileName);
+            } else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION) {
+                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
+                        fileName);
+            } else if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION) {
+                throw new InvalidExtensionException.InvalidVideoExtensionException(allowedExtension, extension,
+                        fileName);
+            } else {
+                throw new InvalidExtensionException(allowedExtension, extension, fileName);
+            }
+        }
+    }
+
+    /**
+     * 判断MIME类型是否是允许的MIME类型
+     *
+     * @param extension        上传文件类型
+     * @param allowedExtension 允许上传文件类型
+     * @return true/false
+     */
+    public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {
+        for (String str : allowedExtension) {
+            if (str.equalsIgnoreCase(extension)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 获取文件名的后缀
+     *
+     * @param file 表单文件
+     * @return 后缀名
+     */
+    public static final String getExtension(MultipartFile file) {
+        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
+        if (StringUtils.isEmpty(extension)) {
+            extension = MimeTypeUtils.getExtension(file.getContentType());
+        }
+        return extension;
+    }
+}

+ 129 - 0
zd-modules/zd-forward/src/main/java/com/zd/forward/util/HttpUtils.java

@@ -0,0 +1,129 @@
+package com.zd.forward.util;
+
+import com.zd.forward.config.AlgorithmYml;
+import com.zd.forward.domain.DataPostAnalysisRespDto;
+import com.zd.forward.domain.ImgPostResponse;
+import com.zd.forward.properties.FireProperties;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.core.ParameterizedTypeReference;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.*;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneOffset;
+
+/**
+ * @author Administrator
+ */
+@Slf4j
+public class HttpUtils {
+
+    private HttpUtils() {
+        throw new IllegalStateException("HttpUtils class");
+    }
+
+    /**
+     * 构造算法文件逆流
+     */
+    public static HttpEntity<MultiValueMap<String, Object>> getHttpEntityMap(MultipartFile file, MultiValueMap<String, Object> params) {
+        try {
+            //设置请求头
+            HttpHeaders headers = new HttpHeaders();
+            headers.setContentType(MediaType.MULTIPART_FORM_DATA);
+            //MultipartFile 转为临时文件
+            File uploadFile = multipartFileToFile(file);
+            //文件转为文件系统资源
+            return getHttpEntity(uploadFile, params, headers);
+        } catch (IOException ex) {
+            ex.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 构造算法文件逆流
+     */
+    public static HttpEntity<MultiValueMap<String, Object>> getHttpEntityMap(File file, MultiValueMap<String, Object> params) {
+        //设置请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.MULTIPART_FORM_DATA);
+        return getHttpEntity(file, params, headers);
+    }
+
+    private static HttpEntity<MultiValueMap<String, Object>> getHttpEntity(File file, MultiValueMap<String, Object> params, HttpHeaders headers) {
+        //文件转为文件系统资源
+        FileSystemResource fileSystemResource = new FileSystemResource(file);
+        //设置请求体,注意是LinkedMultiValueMap
+        MultiValueMap<String, Object> form = getStringObjectMultiValueMap(fileSystemResource);
+        form.addAll(params);
+        //用HttpEntity封装整个请求报文
+        return new HttpEntity<>(form, headers);
+    }
+
+    public static File multipartFileToFile(MultipartFile file) throws IOException {
+        String originalFilename = file.getOriginalFilename() == null ? "" : file.getOriginalFilename();
+        assert originalFilename!=null;
+        String[] filename = originalFilename.split("\\.");
+        File toFile = File.createTempFile(filename[0], "." + filename[1]);
+        file.transferTo(toFile);
+        //toFile.deleteOnExit();//在jvm 退出时删除
+        return toFile;
+    }
+
+    /**
+     * 构建算法图片post请求 参数:只构建文件
+     */
+    public static MultiValueMap<String, Object> getStringObjectMultiValueMap(FileSystemResource fileSystemResource) {
+        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
+        form.add("file", fileSystemResource);
+        return form;
+    }
+
+    private static MultiValueMap<String, Object> getStringObjectMultiValueMap(String extension) {
+        MultiValueMap<String, Object> form = new LinkedMultiValueMap<>();
+        //1-同步(默认),0-异步
+        form.add("sync", 1);
+        form.add("timeStamp", LocalDateTime.now().toInstant(ZoneOffset.of("+8")).toEpochMilli() / 1000);
+        form.add("extension", extension);
+        return form;
+    }
+
+    /**
+     * 构建算法图片post请求 参数
+     */
+    public static MultiValueMap<String, Object> getStringObjectMultiValueMap(AlgorithmYml.CheckValid checkValid, String extension) {
+        MultiValueMap<String, Object> form = getStringObjectMultiValueMap(extension);
+        form.add("algoId", checkValid.getAlgoId());
+        form.add("did", checkValid.getDid());
+        return form;
+    }
+
+    /**
+     * 构建算法图片post请求 参数
+     */
+    public static MultiValueMap<String, Object> getMultiValueMap(FireProperties properties, String extension) {
+        MultiValueMap<String, Object> form = getStringObjectMultiValueMap(extension);
+        form.add("algoId", properties.getAlgoId());
+        form.add("did", properties.getDid());
+        return form;
+    }
+
+    public static ImgPostResponse<DataPostAnalysisRespDto> send(RestTemplate restTemplate, HttpEntity<MultiValueMap<String, Object>> files, AlgorithmYml algorithmYml) {
+        ParameterizedTypeReference<ImgPostResponse<DataPostAnalysisRespDto>> reference = new ParameterizedTypeReference<ImgPostResponse<DataPostAnalysisRespDto>>() {
+        };
+        ResponseEntity<ImgPostResponse<DataPostAnalysisRespDto>> response = restTemplate.exchange(algorithmYml.getImgPostUrl(), HttpMethod.POST, files, reference);
+        if (response.getStatusCode() != HttpStatus.OK) {
+            log.error("算法服务请求异常,请查看算服务器");
+        }
+        if (response.getBody() == null) {
+            log.error("算法服务接口返回异常");
+        }
+        return response.getBody();
+    }
+}