Przeglądaj źródła

集成minio文件上传

marxjaw 4 miesięcy temu
rodzic
commit
bd02cbae72

+ 1 - 1
yt-agent/agent-service/src/main/java/com/ytpm/config/ResourceServerConfig.java

@@ -64,7 +64,7 @@ public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
     public void configure(HttpSecurity http) throws Exception {
         http.headers().frameOptions().disable()
                 .and()
-                .authorizeRequests().antMatchers("/api/public/**","/doc.html","/api/v2/**","/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security",
+                .authorizeRequests().antMatchers("/attach/**","/api/public/**","/doc.html","/api/v2/**","/v2/api-docs", "/configuration/ui", "/swagger-resources", "/configuration/security",
                         "/swagger-ui.html", "/webjars/**","/swagger-resources/configuration/ui","/swagger-ui.html").permitAll()
                 .anyRequest().authenticated();
     }

+ 44 - 0
yt-agent/agent-service/src/main/java/com/ytpm/controller/AttachController.java

@@ -0,0 +1,44 @@
+package com.ytpm.controller;
+
+import com.ytpm.attach.Attach;
+import com.ytpm.attach.Image;
+import com.ytpm.general.Result;
+import com.ytpm.service.AttachService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+
+@Api(tags = "文件管理")
+@Slf4j(topic = "attach-controller")
+@RequestMapping("/attach")
+@RestController
+public class AttachController {
+    @Resource
+    private AttachService attachService;
+
+    /**
+     * 图片上传
+     */
+    @ApiOperation("图片上传")
+    @PostMapping("/image")
+    public Result<Image> uploadImg(@RequestParam("file") MultipartFile multipartFile) {
+        return Result.resultObjOk(attachService.uploadImage(multipartFile));
+    }
+
+    /**
+     * 上传文件
+     */
+    @ApiOperation("文件上传")
+    @PostMapping( "/file")
+    public Result<Attach> upload(@RequestParam("file") MultipartFile multipartFile) {
+        return Result.resultObjOk(attachService.uploadFile(multipartFile));
+    }
+
+}

+ 23 - 0
yt-agent/agent-service/src/main/java/com/ytpm/oss/OssAttach.java

@@ -0,0 +1,23 @@
+package com.ytpm.oss;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * Oss 文件类
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class OssAttach {
+    /**
+     * 附件名称
+     */
+    private String name;
+
+    /**
+     * 附件路径
+     */
+    private String url;
+}

+ 54 - 0
yt-agent/agent-service/src/main/java/com/ytpm/oss/OssProperties.java

@@ -0,0 +1,54 @@
+package com.ytpm.oss;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+
+/**
+ * oss配置类
+ */
+@Data
+@Component
+public class OssProperties {
+    /**
+     * 存储类的全称
+     */
+    @Value("${oss.name}")
+    private String name;
+
+    /**
+     * 存储的文件路径
+     */
+    @Value("${oss.path}")
+    private String path;
+
+    /**
+     * 存储文件的访问域
+     */
+    @Value("${oss.domain}")
+    private String domain;
+
+    /**
+     * 密钥
+     */
+    @Value("${oss.accessKey}")
+    private String accessKey;
+
+    /**
+     * 访问密钥
+     */
+    @Value("${oss.secretKey}")
+    private String secretKey;
+
+    /**
+     * 端点名
+     */
+    @Value("${oss.endpoint}")
+    private String endpoint;
+
+    /**
+     * 存储桶名
+     */
+    @Value("${oss.bucket}")
+    private String bucket;
+}

+ 76 - 0
yt-agent/agent-service/src/main/java/com/ytpm/oss/OssUtil.java

@@ -0,0 +1,76 @@
+package com.ytpm.oss;
+
+import cn.hutool.core.util.StrUtil;
+import com.ytpm.handle.CustomerException;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.File;
+import java.io.InputStream;
+
+@Slf4j(topic = "oss-util")
+public final class OssUtil {
+    private static StorageTemplate getStorageTemplate(OssProperties ossProperties) {
+        return StorageFactory.createStorageTemplate(ossProperties);
+    }
+
+    /**
+     * 上传文件(本地文件上传)
+     *
+     * @param file          本地文件
+     * @param ossProperties 文件描述信息
+     * @return 生成的文件名
+     */
+    public static String upload(File file, OssProperties ossProperties) {
+        return getStorageTemplate(ossProperties).upload(file);
+    }
+
+    /**
+     * 删除文件
+     *
+     * @param filename
+     */
+    public static boolean deleteFile(String filename, OssProperties ossProperties) {
+        return getStorageTemplate(ossProperties).deleteFile(filename);
+    }
+
+    /**
+     * 转存文件(把原来的文件再重新上传存储一遍)
+     *
+     * @param filename      文件名
+     * @param ossProperties 文件描述
+     * @return 新生成文件名
+     */
+    public static OssAttach restore(String filename, OssProperties ossProperties) {
+        return getStorageTemplate(ossProperties).restore(filename);
+    }
+
+    /**
+     * 获取文件url
+     *
+     * @param ossName       存储的文件名
+     * @param ossProperties 文件描述
+     * @return 文件url
+     */
+    public static String getUrl(String ossName, OssProperties ossProperties) {
+        String url = getStorageTemplate(ossProperties).getUrl(ossName);
+        if (StrUtil.isBlank(url)) {
+            return null;
+        }
+        return url.replace(ossProperties.getEndpoint(), ossProperties.getDomain());
+    }
+
+    /**
+     * 获取文件流
+     *
+     * @param ossName
+     * @param ossProperties
+     * @return
+     */
+    public static InputStream getStream(String ossName, OssProperties ossProperties) {
+        try {
+            return getStorageTemplate(ossProperties).getStream(ossName);
+        } catch (Exception e) {
+            throw new CustomerException(e.getMessage());
+        }
+    }
+}

+ 14 - 0
yt-agent/agent-service/src/main/java/com/ytpm/oss/StorageFactory.java

@@ -0,0 +1,14 @@
+package com.ytpm.oss;
+
+import cn.hutool.core.util.ReflectUtil;
+
+/**
+ * 存储工厂
+ */
+public class StorageFactory {
+    public static StorageTemplate createStorageTemplate(OssProperties ossProperties) {
+        StorageTemplate storageTemplate = ReflectUtil.newInstance(ossProperties.getName());
+        storageTemplate.init(ossProperties);
+        return storageTemplate;
+    }
+}

+ 57 - 0
yt-agent/agent-service/src/main/java/com/ytpm/oss/StorageTemplate.java

@@ -0,0 +1,57 @@
+package com.ytpm.oss;
+
+
+import io.minio.errors.ErrorResponseException;
+import io.minio.errors.InsufficientDataException;
+import io.minio.errors.InternalException;
+import io.minio.errors.InvalidBucketNameException;
+import io.minio.errors.InvalidResponseException;
+import io.minio.errors.XmlParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+
+public interface StorageTemplate {
+    /**
+     * 初始化oss属性
+     *
+     * @param ossProperties oss属性
+     */
+    void init(OssProperties ossProperties);
+
+    /**
+     * 上传文件(本地文件上传)
+     *
+     * @param file 本地文件
+     * @return
+     */
+    String upload(File file);
+
+    /**
+     * 删除文件
+     *
+     * @param filename
+     */
+    boolean deleteFile(String filename);
+
+    /**
+     * 转存文件(把原来的文件再重新上传存储一遍)
+     *
+     * @param filename 文件名
+     * @return
+     */
+    OssAttach restore(String filename);
+
+    /**
+     * 获取文件url
+     *
+     * @param filename
+     * @return
+     */
+    String getUrl(String filename);
+
+    InputStream getStream(String filename) throws IOException, InvalidKeyException, InvalidResponseException, InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException, InvalidBucketNameException;
+}

+ 113 - 0
yt-agent/agent-service/src/main/java/com/ytpm/oss/minio/MinioStorageTemplate.java

@@ -0,0 +1,113 @@
+package com.ytpm.oss.minio;
+
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.file.FileNameUtil;
+import cn.hutool.core.util.IdUtil;
+import com.ytpm.handle.CustomerException;
+import com.ytpm.oss.OssAttach;
+import com.ytpm.oss.OssProperties;
+import com.ytpm.oss.StorageTemplate;
+import io.minio.MinioClient;
+import io.minio.PutObjectOptions;
+import io.minio.errors.ErrorResponseException;
+import io.minio.errors.InsufficientDataException;
+import io.minio.errors.InternalException;
+import io.minio.errors.InvalidBucketNameException;
+import io.minio.errors.InvalidResponseException;
+import io.minio.errors.XmlParserException;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+
+public class MinioStorageTemplate implements StorageTemplate {
+    private String bucket;
+
+    private MinioClient minioClient;
+
+    @Override
+    public void init(OssProperties ossProperties) {
+        try {
+
+            this.minioClient = new MinioClient(ossProperties.getEndpoint(), ossProperties.getAccessKey(), ossProperties.getSecretKey());
+            this.bucket = ossProperties.getBucket();
+            boolean isExists = minioClient.bucketExists(bucket);
+            if (!isExists) {
+                minioClient.makeBucket(bucket);
+                minioClient.setBucketPolicy(bucket,"public");
+            }
+        } catch (Exception e) {
+            throw new CustomerException(e.getMessage());
+        }
+    }
+
+    @Override
+    public String upload(File file) {
+        try {
+            String filename = getFileName(file);
+            PutObjectOptions options = new PutObjectOptions(FileUtil.size(file), PutObjectOptions.MIN_MULTIPART_SIZE);
+            minioClient.putObject(bucket, filename, FileUtil.getInputStream(file), options);
+            return filename;
+        } catch (Exception e) {
+            throw new CustomerException(e.getMessage());
+        }
+    }
+
+
+    @Override
+    public boolean deleteFile(String filename) {
+        try {
+            minioClient.removeObject(bucket, filename);
+        } catch (Exception e) {
+            throw new CustomerException(e.getMessage());
+        }
+        return true;
+    }
+
+    @Override
+    public OssAttach restore(String filename) {
+        String newFileName = getFileName(filename);
+        try {
+            minioClient.copyObject(bucket, newFileName, null, null, bucket, filename, null, null);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return new OssAttach(newFileName, getUrl(newFileName));
+    }
+
+    @Override
+    public String getUrl(String filename) {
+        String url;
+        try {
+            url = this.minioClient.getObjectUrl(bucket, filename);
+        } catch (Exception e) {
+            throw new CustomerException(e.getMessage());
+        }
+        return url;
+    }
+
+    @Override
+    public InputStream getStream(String filename) throws IOException, InvalidKeyException, InvalidResponseException,
+            InsufficientDataException, NoSuchAlgorithmException, InternalException, XmlParserException, InvalidBucketNameException, ErrorResponseException {
+        return minioClient.getObject(bucket, filename);
+    }
+
+    private String getFileName(File file) {
+        String ym = DateUtil.format(new Date(), "YYYYMM");
+        String filename = ym + "/" + ym + IdUtil.fastSimpleUUID() + "." + FileNameUtil.getSuffix(file);
+
+        return filename;
+    }
+
+    private String getFileName(String fileName) {
+        String ym = DateUtil.format(new Date(), "YYYYMM");
+        String filename = ym + "/" + ym + IdUtil.fastSimpleUUID() + "." + FileNameUtil.getSuffix(fileName);
+
+        return filename;
+    }
+}

+ 25 - 0
yt-agent/agent-service/src/main/java/com/ytpm/service/AttachService.java

@@ -0,0 +1,25 @@
+package com.ytpm.service;
+
+import com.ytpm.attach.Attach;
+import com.ytpm.attach.Image;
+import org.springframework.web.multipart.MultipartFile;
+
+public interface AttachService {
+    /**
+     * 上传文件
+     *
+     * @param multipartFile 文件
+    机构id
+     * @return 文件信息
+     */
+    Attach uploadFile(MultipartFile multipartFile);
+
+    /**
+     * 上传图片
+     *
+     * @param multipartFile 文件
+    机构
+     * @return 图片信息
+     */
+    Image uploadImage(MultipartFile multipartFile);
+}

+ 98 - 0
yt-agent/agent-service/src/main/java/com/ytpm/service/impl/AttachServiceImpl.java

@@ -0,0 +1,98 @@
+package com.ytpm.service.impl;
+
+import cn.hutool.core.util.IdUtil;
+import com.ytpm.attach.Attach;
+import com.ytpm.attach.Image;
+import com.ytpm.handle.CustomerException;
+import com.ytpm.oss.OssProperties;
+import com.ytpm.oss.OssUtil;
+import com.ytpm.service.AttachService;
+import lombok.extern.slf4j.Slf4j;
+import net.coobird.thumbnailator.Thumbnails;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+
+@Slf4j(topic = "attach-service")
+@Service
+public class AttachServiceImpl implements AttachService {
+
+    @Autowired
+    OssProperties properties;
+
+    @Override
+    public Attach uploadFile(MultipartFile multipartFile) {
+
+        String originFilename = multipartFile.getOriginalFilename();
+        Attach attach = new Attach();
+        String ossName = upload(multipartFile, properties, false);
+        attach.setName(originFilename);
+        attach.setOssName(ossName);
+        attach.setUrl(OssUtil.getUrl(ossName, properties));
+        attach.setFileSize(multipartFile.getSize());
+        return attach;
+    }
+
+    @Override
+    public Image uploadImage(MultipartFile multipartFile) {
+        String ossName = upload(multipartFile, properties, true);
+
+        Image image = new Image();
+        image.setOssName(ossName);
+        image.setUrl(OssUtil.getUrl(ossName, properties));
+        return image;
+    }
+
+    /**
+     * 文件上传
+     *
+     * @param multipartFile 文件
+     * @param properties    存储配置
+     * @param isImage       是否为图片
+     * @return 文件ossName
+     */
+    private String upload(MultipartFile multipartFile, OssProperties properties, Boolean isImage) {
+        String originFilename = multipartFile.getOriginalFilename();
+        String suffix = originFilename.substring(originFilename.lastIndexOf("."));
+
+        if (isImage) {
+            suffix = suffix.toUpperCase();
+            //图片
+            if (!".JPEG,.JPG,.PNG".contains(suffix)||suffix.equals(".")||suffix.equals(",")) {
+                throw new CustomerException("格式类型错误");
+            }
+        }
+
+        String folder = System.getProperty("java.io.tmpdir");
+        File file = new File(folder + File.separator + IdUtil.fastSimpleUUID() + suffix);
+
+        try {
+            multipartFile.transferTo(file);
+            //压缩图片
+            compressFile(file, suffix);
+        } catch (IOException e) {
+            log.error("文件上传失败:", e);
+            throw new CustomerException(e.getMessage());
+        }
+
+        return OssUtil.upload(file, properties);
+    }
+
+    private void compressFile(File file, String suffix) {
+        //2、大于2M的图片需要压缩大小
+        long fileSize = file.length();
+        if (".JPEG,.JPG,.PNG".contains(suffix) && fileSize > 1024 * 1024 * 2) {
+            try {
+                Thumbnails.of(file)
+                        .scale(0.2)
+//                        .outputQuality(0.2f)
+                        .toFile(file);
+            } catch (IOException e) {
+                log.error("压缩报错了:", e);
+            }
+        }
+    }
+}

+ 5 - 0
yt-common/pom.xml

@@ -19,6 +19,11 @@
     </properties>
 
     <dependencies>
+        <dependency>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+            <version>7.0.2</version>
+        </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>

+ 1 - 0
yt-common/src/main/java/com/ytpm/app/model/YtDyzLoginRecord.java

@@ -21,6 +21,7 @@ public class YtDyzLoginRecord {
     @ApiModelProperty("用户ID")
     private String userId;
     /** 登录时间 */
+    @CustomField
     @ApiModelProperty("登录时间")
     private Date loginTime;
     /** 设备品牌 */

+ 31 - 0
yt-common/src/main/java/com/ytpm/attach/Attach.java

@@ -0,0 +1,31 @@
+package com.ytpm.attach;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Attach {
+    /**
+     * 主键
+     */
+    private String id;
+    /**
+     * 文件名
+     */
+    private String name;
+    /**
+     * 存储的文件名
+     */
+    private String ossName;
+    /**
+     * 文件路径
+     */
+    private String url;
+    /**
+     * 文件大小
+     */
+    private Long fileSize;
+}

+ 34 - 0
yt-common/src/main/java/com/ytpm/attach/Image.java

@@ -0,0 +1,34 @@
+package com.ytpm.attach;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Image {
+    /**
+     * 主键
+     */
+    private String id;
+
+    /**
+     * 存储的文件名
+     */
+    private String ossName;
+    /**
+     * 图片路径
+     */
+    private String url;
+
+    /**
+     * 目标id
+     */
+    private String targetId;
+
+    /**
+     * 业务类型
+     */
+    private String businessType;
+}

+ 148 - 0
yt-common/src/main/java/com/ytpm/attach/WebUtil.java

@@ -0,0 +1,148 @@
+package com.ytpm.attach;
+
+import cn.hutool.core.util.StrUtil;
+import org.springframework.web.util.WebUtils;
+
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.UnsupportedEncodingException;
+import java.net.InetAddress;
+import java.net.URLEncoder;
+import java.net.UnknownHostException;
+import java.util.Enumeration;
+
+public class WebUtil extends WebUtils {
+
+    /**
+     * 获取请求参数值,依次从paramter,header,cookie中查找
+     *
+     * @param request 请求
+     * @param name    参数名
+     * @return
+     */
+    public static String getRequestParamValue(HttpServletRequest request, String name) {
+        String value = findParameterValue(request, name);
+
+        if (StrUtil.isBlank(value)) {
+            value = getHeaderValue(request, name);
+        }
+
+        if (StrUtil.isBlank(value)) {
+            value = getCookieValue(request, name);
+        }
+
+        return value;
+    }
+
+    /**
+     * 获取cookie值
+     *
+     * @param request 请求
+     * @param name    参数名
+     * @return
+     */
+    public static String getCookieValue(HttpServletRequest request, String name) {
+        Cookie cookie = getCookie(request, name);
+        String value = null;
+        if (cookie != null) {
+            value = cookie.getValue();
+        }
+        return value;
+    }
+
+    /**
+     * 获取请求头header值
+     *
+     * @param request 请求
+     * @param name    参数名
+     * @return
+     */
+    public static String getHeaderValue(HttpServletRequest request, String name) {
+        String value = null;
+        Enumeration<String> headerNames = request.getHeaderNames();
+        while (headerNames.hasMoreElements()) {
+            String key = headerNames.nextElement();
+            if (key.equals(name)) {
+                value = request.getHeader(name);
+            }
+        }
+        return value;
+    }
+
+    /**
+     * 响应初始化(下载用)
+     *
+     * @param response 响应
+     * @param fileName 文件名 例exp.xls
+     * @throws UnsupportedEncodingException 转码异常
+     */
+    public static void initDownloadHeader(HttpServletResponse response, String fileName) {
+
+        response.reset();
+        try {
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
+            response.setContentType("application/octet-stream");
+            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
+            response.setCharacterEncoding("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 响应初始化(pdf在线展示用)
+     *
+     * @param response 响应
+     * @param fileName 文件名 例exp.xls
+     * @throws UnsupportedEncodingException 转码异常
+     */
+    public static void initPdfOnlineHeader(HttpServletResponse response, String fileName) {
+
+        response.reset();
+        try {
+            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "UTF-8"));
+            response.setContentType("application/pdf");
+            response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
+            response.setCharacterEncoding("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            throw new RuntimeException(e.getMessage());
+        }
+    }
+
+    /**
+     * 获取用户Ip地址
+     *
+     * @param request
+     * @return
+     */
+    public static String getIpAddress(HttpServletRequest request) {
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_CLIENT_IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddr();
+            if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) {
+                //根据网卡取本机配置的IP
+                InetAddress inet = null;
+                try {
+                    inet = InetAddress.getLocalHost();
+                } catch (UnknownHostException e) {
+                    e.printStackTrace();
+                }
+                ip = inet.getHostAddress();
+            }
+        }
+        return ip;
+    }
+}