Browse Source

Merge branch 'wanghaicheng' of lift-manager/lift-server into develop

wanghaicheng 5 years ago
parent
commit
89540f9e3e
21 changed files with 1100 additions and 333 deletions
  1. 9 0
      lift-common/src/main/java/cn.com.ty.lift.common/constants/SqlConstants.java
  2. 1 12
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/controller/RegionController.java
  3. 7 0
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/dao/mapper/RegionMapper.java
  4. 2 0
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/service/RegionService.java
  5. 22 0
      lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/service/impl/RegionServiceImpl.java
  6. 9 3
      lift-upload/pom.xml
  7. 302 0
      lift-upload/src/main/java/com/upload/config/AliyunOSS.java
  8. 1 1
      lift-upload/src/main/java/com/upload/controller/CustomCORSConfiguration.java
  9. 31 0
      lift-upload/src/main/java/com/upload/config/GlobalDefaultExceptionHandler.java
  10. 160 0
      lift-upload/src/main/java/com/upload/config/IdWorker.java
  11. 1 1
      lift-upload/src/main/java/com/upload/controller/RestResponse.java
  12. 53 0
      lift-upload/src/main/java/com/upload/config/SystemConfiguration.java
  13. 102 0
      lift-upload/src/main/java/com/upload/config/Validate.java
  14. 122 0
      lift-upload/src/main/java/com/upload/config/ValuePool.java
  15. 0 194
      lift-upload/src/main/java/com/upload/controller/SystemConfiguration.java
  16. 40 71
      lift-upload/src/main/java/com/upload/controller/UploadController.java
  17. 0 49
      lift-upload/src/main/java/com/upload/controller/ValidateMethodInterceptor.java
  18. 28 0
      lift-upload/src/main/java/com/upload/entity/Local.java
  19. 52 0
      lift-upload/src/main/java/com/upload/service/UploadService.java
  20. 156 0
      lift-upload/src/main/java/com/upload/util/WatermarkUtil.java
  21. 2 2
      lift-upload/src/main/resources/application.yml

+ 9 - 0
lift-common/src/main/java/cn.com.ty.lift.common/constants/SqlConstants.java

@@ -167,4 +167,13 @@ public interface SqlConstants {
                     "   from emergency_repair" +
                     "   where (DATE_FORMAT(caller_date, '%Y%m%d') = CURDATE() or DATE_FORMAT(create_date, '%Y%m%d') = CURDATE())" +
                     "  and project_id in (select project_id from project_user where user_id = #{userId})";
+
+    String UPDATE_REGION_DIRECTOR =
+            "<script>"
+                    + "update project_user set user_id=#{userId} where project_id in"
+                    + " <foreach item='item' index='index' collection='projectIds' open='(' separator=',' close=')'>"
+                    + "        #{item}"
+                    + "  </foreach>"
+                    + "and mt_company_id=#{mtCompanyId} and user_role = 'REGION_DIRECTOR'"
+                    + "</script>";
 }

+ 1 - 12
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/controller/RegionController.java

@@ -72,18 +72,7 @@ public class RegionController {
      */
     @PostMapping("/update")
     public RestResponse update(@RequestBody Region region) {
-        Region byId = regionService.getById(region);
-        //如果区域主管更改了,发推送消息
-        if (!byId.getUserId().equals(region.getUserId())) {
-            String oldUser = regionMapper.selectNameByUserId(byId.getUserId());
-            String newUser = regionMapper.selectNameByUserId(region.getUserId());
-            String areaName = byId.getAreaName();
-            regionService.push(areaName, oldUser, newUser, byId, region);
-        }
-        if (regionService.updateById(region)) {
-            return RestResponse.success(null, "成功");
-        }
-        return RestResponse.fail();
+        return regionService.updateByRegionId(region);
     }
 
     @PostMapping("/delete")

+ 7 - 0
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/dao/mapper/RegionMapper.java

@@ -8,6 +8,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper;
 import com.baomidou.mybatisplus.core.metadata.IPage;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Select;
+import org.apache.ibatis.annotations.Update;
 
 import java.util.List;
 import java.util.Map;
@@ -46,6 +47,12 @@ public interface RegionMapper extends BaseMapper<Region> {
     @Select("select id,area_name areaName from region where mt_company_id=#{mtCompanyId} and area_name like #{areaName}")
     List<RegionBO> selectIdAndNameLikeName(Long mtCompanyId, String areaName);
 
+    @Select("select project_id from project_user where user_id = #{userId} and mt_company_id = #{mtCompanyId} and user_role = 'REGION_DIRECTOR'")
+    List<Long> selectProjectIdByRegionDirectorId(Long userId, Long mtCompanyId);
+
+    @Update(SqlConstants.UPDATE_REGION_DIRECTOR)
+    void updateRegionDirector(List<Long> projectIds, Long userId, Long mtCompanyId);
+
     @Select(SqlConstants.QUERY_REGIONS)
     IPage<RegionResponse> regions(IPage<RegionResponse> page, Long mtCompanyId, String name);
 }

+ 2 - 0
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/service/RegionService.java

@@ -29,4 +29,6 @@ public interface RegionService extends IService<Region> {
     List<Map<String, Object>> areas(String cityCode);
 
     void push(String areaName, String oldUser, String newUser, Region byId, Region region);
+
+    RestResponse updateByRegionId(Region region);
 }

+ 22 - 0
lift-enterprise-service/src/main/java/cn/com/ty/lift/enterprise/region/service/impl/RegionServiceImpl.java

@@ -16,6 +16,7 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import lombok.AllArgsConstructor;
 import org.springframework.jms.core.JmsMessagingTemplate;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -170,4 +171,25 @@ public class RegionServiceImpl extends ServiceImpl<RegionMapper, Region> impleme
                 .workReplaceRegionCharger(areaName, oldUser, newUser)
                 .sendTokenOnPlatform(jmsMessagingTemplate, userInfos);
     }
+
+    /**
+     * 修改区域时,检测新老区域主管,有修改时发送推送消息,修改project_user表内的区域主管信息
+     *
+     * @param region 区域信息
+     * @return 操作结果
+     */
+    @Transactional(rollbackFor = Exception.class)
+    public RestResponse<?> updateByRegionId(Region region) {
+        Region byId = this.getById(region);
+        //如果区域主管更改了,发推送消息,修改project_user表内的区域主管信息
+        if (!byId.getUserId().equals(region.getUserId())) {
+            List<Long> projects = baseMapper.selectProjectIdByRegionDirectorId(byId.getUserId(), byId.getMtCompanyId());
+            baseMapper.updateRegionDirector(projects, region.getUserId(), byId.getMtCompanyId());
+            String oldUser = baseMapper.selectNameByUserId(byId.getUserId());
+            String newUser = baseMapper.selectNameByUserId(region.getUserId());
+            String areaName = byId.getAreaName();
+            this.push(areaName, oldUser, newUser, byId, region);
+        }
+        return RestResponse.success(this.updateById(region));
+    }
 }

+ 9 - 3
lift-upload/pom.xml

@@ -17,9 +17,15 @@
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
         <dependency>
-            <groupId>cn.com.ty</groupId>
-            <artifactId>lift-common</artifactId>
-            <version>1.0-SNAPSHOT</version>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.5.0</version>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.8</version>
+            <scope>provided</scope>
         </dependency>
     </dependencies>
     <build>

+ 302 - 0
lift-upload/src/main/java/com/upload/config/AliyunOSS.java

@@ -0,0 +1,302 @@
+package com.upload.config;
+
+import cn.hutool.core.util.StrUtil;
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.model.*;
+import lombok.extern.slf4j.Slf4j;
+
+import java.io.*;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+
+/**
+ * <p>
+ * aliyun OSS工具类
+ * </p>
+ */
+@Slf4j
+public class AliyunOSS {
+
+    // Endpoint以杭州为例,其它Region请按实际情况填写。
+    private String endpoint = "http://oss-cn-beijing.aliyuncs.com";
+    // 阿里云主账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM账号进行API访问或日常运维,请登录 https://ram.console.aliyun.com 创建RAM账号。
+    private String accessKeyId = "LTAI4FkSqFZa6LH9HqAsVott";
+    private String accessKeySecret = "w7GXuh5tf1hduQuZ2AzT3a4q14BI1i";
+    //存储空间名
+    private String bucketName = "temp15827479607";
+
+    //OSSClient实例
+    private OSS ossClient;
+
+    public RestResponse<?> putObjects(Map<String, byte[]> fileMap) {
+        //批量上传
+        try {
+            List<String> urls = new LinkedList<>();
+            for (Map.Entry<String, byte[]> entry : fileMap.entrySet()) {
+                ossClient.putObject(bucketName, entry.getKey(), new ByteArrayInputStream(entry.getValue()));
+                String url = getObjectUrl(bucketName, entry.getKey());
+                log.info("upload file complete, file URL: {}", url);
+                Validate.notNull(url, ValuePool.UPLOAD_FAIL);
+                urls.add(url);
+            }
+            return RestResponse.success(urls);
+        } catch (Exception e) {
+            log.error("upload file occur exception", e);
+            return RestResponse.fail(ValuePool.UPLOAD_FAIL);
+        } finally {
+            destroy();
+        }
+    }
+
+    private static class Builder {
+        private static OSSClientBuilder ossClientBuilder = new OSSClientBuilder();
+    }
+
+    /**
+     * 无参构造,初始化oss
+     */
+    private AliyunOSS() {
+        init("Default");
+    }
+
+    /**
+     * 全参构造方法
+     *
+     * @param endpoint
+     * @param accessKeyId
+     * @param accessKeySecret
+     * @param bucketName
+     */
+    private AliyunOSS(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) {
+        this.endpoint = endpoint;
+        this.accessKeyId = accessKeyId;
+        this.accessKeySecret = accessKeySecret;
+        this.bucketName = bucketName;
+        init("Custom");
+    }
+
+    /**
+     * 初始化,创建OSSClient实例
+     */
+    private void init(String type) {
+        log.info("Hint: Using the {} Configuration To Create Aliyun OSS Client.", type);
+        if (Objects.isNull(ossClient)) {
+            ossClient = Builder.ossClientBuilder.build(endpoint, accessKeyId, accessKeySecret);
+        }
+    }
+
+    /**
+     * 关闭OSSClient。
+     */
+    private void destroy() {
+        if (null != ossClient) {
+            ossClient.shutdown();
+        }
+    }
+
+    /**
+     * 设置bucketName
+     *
+     * @param bucketName
+     */
+    public void setBucketName(String bucketName) {
+        this.bucketName = bucketName;
+    }
+
+    /**
+     * static 无参构造方法
+     *
+     * @return
+     */
+    public static AliyunOSS me() {
+        return new AliyunOSS();
+    }
+
+    /**
+     * static 全参构造方法
+     *
+     * @param endpoint
+     * @param accessKeyId
+     * @param accessKeySecret
+     * @param bucketName
+     * @return
+     */
+    public static AliyunOSS me(String endpoint, String accessKeyId, String accessKeySecret, String bucketName) {
+        return new AliyunOSS(endpoint, accessKeyId, accessKeySecret, bucketName);
+    }
+
+    /**
+     * @param
+     * @return
+     * @description 创建存储空间
+     * 存储空间是OSS全局命名空间,相当于数据的容器,可以存储若干文件。 以下代码用于新建一个存储空间
+     * @date 2019/11/29 10:30
+     */
+    public boolean createBucket(String bucketName) {
+        if (StrUtil.isEmpty(bucketName)) {
+            return false;
+        }
+        try {
+            ossClient.createBucket(bucketName);
+            return true;
+        } catch (Exception e) {
+            log.error("创建存储空间异常: {}", e.getMessage());
+            return false;
+        } finally {
+            destroy();
+        }
+    }
+
+    /**
+     * 上传文件,上传文件至OSS
+     *
+     * @param objectName 上传文件到OSS时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
+     * @return
+     */
+    public String putObject(String bucketName, String objectName, byte[] content) {
+        try {
+            // 上传内容到指定的存储空间(bucketName)并保存为指定的文件名称(objectName)。
+            ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(content));
+            String url = getObjectUrl(bucketName, objectName);
+            return url;
+        } catch (Exception e) {
+            log.error("上传文件异常: {}", e);
+            return null;
+        } finally {
+            destroy();
+        }
+    }
+
+    public String putObject(String objectName, byte[] content) {
+        if (StrUtil.isEmpty(objectName)) {
+            return null;
+        }
+        return putObject(bucketName, objectName, content);
+    }
+
+    /**
+     * @param
+     * @return
+     * @description 下载文件,获取文件的文本内容
+     */
+    public boolean getObject(String bucketName, String objectName) throws Exception {
+        try {
+            // 调用ossClient.getObject返回一个OSSObject实例,该实例包含文件内容及文件元信息。
+            OSSObject ossObject = ossClient.getObject(bucketName, objectName);
+            // 调用ossObject.getObjectContent获取文件输入流,可读取此输入流获取其内容。
+            InputStream content = ossObject.getObjectContent();
+            if (content != null) {
+                BufferedReader reader = new BufferedReader(new InputStreamReader(content));
+                while (true) {
+                    String line = reader.readLine();
+                    if (line == null) break;
+                    System.out.println("\n" + line);
+                }
+                // 数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作。
+                content.close();
+            }
+            return true;
+        } catch (Exception e) {
+            log.error("获取文件异常:{}", e.getMessage());
+            return false;
+        } finally {
+            destroy();
+        }
+    }
+
+    /**
+     * @param
+     * @return
+     * @description 列举文件:列举指定存储空间下的文件。默认列举100个文件
+     */
+    public void listObjects(String bucketName) {
+        // ossClient.listObjects返回ObjectListing实例,包含此次listObject请求的返回结果。
+        ObjectListing objectListing = ossClient.listObjects(bucketName);
+        // objectListing.getObjectSummaries获取所有文件的描述信息。
+        for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
+            System.out.println(" - " + objectSummary.getKey() + "  " + "(size = " + objectSummary.getSize() + ")");
+        }
+
+        // 关闭OSSClient。
+        destroy();
+    }
+
+    /**
+     * @param
+     * @return
+     * @description 删除文件
+     * @date 2019/11/29 10:44
+     */
+    public boolean deleteObject(String bucketName, String objectName) {
+        // <yourObjectName>表示删除OSS文件时需要指定包含文件后缀在内的完整路径,例如abc/efg/123.jpg。
+        try {
+            // 删除文件。
+            ossClient.deleteObject(bucketName, objectName);
+            return true;
+        } catch (Exception e) {
+            log.error("删除文件异常: {}", e.getMessage());
+            return false;
+        } finally {
+            destroy();
+        }
+    }
+
+    public boolean deleteObject(String objectName) {
+        if (StrUtil.isEmpty(objectName)) {
+            return false;
+        }
+        return deleteObject(bucketName, objectName);
+    }
+
+    public boolean putFile(String bucketName, String objectName, File file) {
+        try {
+            // 创建PutObjectRequest对象。
+            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, file);
+            // 如果需要上传时设置存储类型与访问权限,请参考以下示例代码。
+            // ObjectMetadata metadata = new ObjectMetadata();
+            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
+            // metadata.setObjectAcl(CannedAccessControlList.Private);
+            // putObjectRequest.setMetadata(metadata);
+
+            // 上传文件。
+            ossClient.putObject(putObjectRequest);
+            return true;
+        } catch (Exception e) {
+            log.error("上传文件异常: {}", e.getMessage());
+            return false;
+        } finally {
+            destroy();
+        }
+    }
+
+    public boolean putFile(String objectName, File file) {
+        if (StrUtil.isEmpty(objectName)) {
+            return false;
+        }
+        return putFile(bucketName, objectName, file);
+    }
+
+
+    public File getFile(String bucketName, String objectName, File file) {
+        try {
+            // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
+            ossClient.getObject(new GetObjectRequest(bucketName, objectName), file);
+            return file;
+        } catch (Exception e) {
+            log.error("获取文件异常: {}", e.getMessage());
+            return null;
+        } finally {
+            destroy();
+        }
+    }
+
+    public String getObjectUrl(String bucketName, String objectName) {
+        if (StrUtil.hasEmpty(endpoint, objectName)) {
+            return null;
+        }
+        return String.format("%s/%s", endpoint.replace("//", "//" + bucketName + "."), objectName);
+    }
+}

+ 1 - 1
lift-upload/src/main/java/com/upload/controller/CustomCORSConfiguration.java

@@ -1,4 +1,4 @@
-package com.upload.controller;
+package com.upload.config;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;

+ 31 - 0
lift-upload/src/main/java/com/upload/config/GlobalDefaultExceptionHandler.java

@@ -0,0 +1,31 @@
+package com.upload.config;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * <p>
+ * 全局异常捕获处理
+ * </p>
+ */
+@Slf4j
+@RestControllerAdvice
+public class GlobalDefaultExceptionHandler {
+
+    @ExceptionHandler(value = Exception.class)
+    public RestResponse<?> exception(final HttpServletRequest request, final HttpServletResponse response, final Exception error) {
+        log.error(ValuePool.LOG_GLOBAL_EXCEPTION_LINE);
+        log.error("{}{} {}", ValuePool.LOG_URL, request.getMethod(), request.getRequestURI());
+        log.error(ValuePool.LOG_STATUS + response.getStatus());
+        log.error(ValuePool.LOG_EXCEPTION, error);
+
+        if (error instanceof IllegalArgumentException) {
+            return RestResponse.failParam();
+        }
+        return RestResponse.exception();
+    }
+}

+ 160 - 0
lift-upload/src/main/java/com/upload/config/IdWorker.java

@@ -0,0 +1,160 @@
+package com.upload.config;
+
+import java.lang.management.ManagementFactory;
+import java.net.InetAddress;
+import java.net.NetworkInterface;
+
+/**
+ * <p>名称:IdWorker.java</p>
+ * <p>描述:分布式自增长ID</p>
+ * <pre>
+ *     Twitter的 Snowflake JAVA实现方案
+ * </pre>
+ * 核心代码为其IdWorker这个类实现,其原理结构如下,我分别用一个0表示一位,用—分割开部分的作用:
+ * 1||0---0000000000 0000000000 0000000000 0000000000 0 --- 00000 ---00000 ---000000000000
+ * 在上面的字符串中,第一位为未使用(实际上也可作为long的符号位),接下来的41位为毫秒级时间,
+ * 然后5位dataCenter标识位,5位机器ID(并不算标识符,实际是为线程标识),
+ * 然后12位该毫秒内的当前毫秒内的计数,加起来刚好64位,为一个Long型。
+ * 这样的好处是,整体上按照时间自增排序,并且整个分布式系统内不会产生ID碰撞(由dataCenter和机器ID作区分),
+ * 并且效率较高,经测试,snowflake每秒能够产生26万ID左右,完全满足需要。
+ * <p>
+ * 64位ID (42(毫秒)+5(机器ID)+5(业务编码)+12(重复累加))
+ *
+ * @author Polim
+ */
+public class IdWorker {
+    // 时间起始标记点,作为基准,一般取系统的最近时间(一旦确定不能变动)
+    private final static long twepoch = 1288834974657L;
+    // 机器标识位数
+    private final static long workerIdBits = 5L;
+    // 数据中心标识位数
+    private final static long datacenterIdBits = 5L;
+    // 机器ID最大值
+    private final static long maxWorkerId = ~(-1L << workerIdBits);
+    // 数据中心ID最大值
+    private final static long maxDatacenterId = ~(-1L << datacenterIdBits);
+    // 毫秒内自增位
+    private final static long sequenceBits = 12L;
+    // 机器ID偏左移12位
+    private final static long workerIdShift = sequenceBits;
+    // 数据中心ID左移17位
+    private final static long datacenterIdShift = sequenceBits + workerIdBits;
+    // 时间毫秒左移22位
+    private final static long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits;
+
+    private final static long sequenceMask = ~(-1L << sequenceBits);
+    /* 上次生产id时间戳 */
+    private static long lastTimestamp = -1L;
+    // 0,并发控制
+    private long sequence = 0L;
+
+    private final long workerId;
+    // 数据标识id部分
+    private final long dataCenterId;
+
+    public IdWorker() {
+        this.dataCenterId = getDataCenterId(maxDatacenterId);
+        this.workerId = getMaxWorkerId(dataCenterId, maxWorkerId);
+    }
+
+    /**
+     * @param workerId     工作机器ID
+     * @param dataCenterId 序列号
+     */
+    public IdWorker(long workerId, long dataCenterId) {
+        if (workerId > maxWorkerId || workerId < 0) {
+            throw new IllegalArgumentException(String.format("worker Id can't be greater than %d or less than 0", maxWorkerId));
+        }
+        if (dataCenterId > maxDatacenterId || dataCenterId < 0) {
+            throw new IllegalArgumentException(String.format("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));
+        }
+        this.workerId = workerId;
+        this.dataCenterId = dataCenterId;
+    }
+
+    /**
+     * 获取下一个ID
+     *
+     * @return
+     */
+    public synchronized long nextId() {
+        long timestamp = timeGen();
+        if (timestamp < lastTimestamp) {
+            throw new RuntimeException(String.format("Clock moved backwards.  Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));
+        }
+        if (lastTimestamp == timestamp) {
+            // 当前毫秒内,则+1
+            sequence = (sequence + 1) & sequenceMask;
+            if (sequence == 0) {
+                // 当前毫秒内计数满了,则等待下一秒
+                timestamp = tilNextMillis(lastTimestamp);
+            }
+        } else {
+            sequence = 0L;
+        }
+        lastTimestamp = timestamp;
+        // ID偏移组合生成最终的ID,并返回ID
+        long nextId = ((timestamp - twepoch) << timestampLeftShift)
+                | (dataCenterId << datacenterIdShift)
+                | (workerId << workerIdShift) | sequence;
+
+        return nextId;
+    }
+
+    private long tilNextMillis(final long lastTimestamp) {
+        long timestamp = this.timeGen();
+        while (timestamp <= lastTimestamp) {
+            timestamp = this.timeGen();
+        }
+        return timestamp;
+    }
+
+    private long timeGen() {
+        return System.currentTimeMillis();
+    }
+
+    /**
+     * <p>
+     * 获取 maxWorkerId
+     * </p>
+     */
+    protected static long getMaxWorkerId(long dataCenterId, long maxWorkerId) {
+        StringBuffer mpid = new StringBuffer();
+        mpid.append(dataCenterId);
+        String name = ManagementFactory.getRuntimeMXBean().getName();
+        if (!name.isEmpty()) {
+            /*
+             * GET jvmPid
+             */
+            mpid.append(name.split("@")[0]);
+        }
+        /*
+         * MAC + PID 的 hashcode 获取16个低位
+         */
+        return (mpid.toString().hashCode() & 0xffff) % (maxWorkerId + 1);
+    }
+
+    /**
+     * <p>
+     * 数据标识id部分
+     * </p>
+     */
+    protected static long getDataCenterId(long maxDataCenterId) {
+        long id = 0L;
+        try {
+            InetAddress ip = InetAddress.getLocalHost();
+            NetworkInterface network = NetworkInterface.getByInetAddress(ip);
+            if (network == null) {
+                id = 1L;
+            } else {
+                byte[] mac = network.getHardwareAddress();
+                id = ((0x000000FF & (long) mac[mac.length - 1])
+                        | (0x0000FF00 & (((long) mac[mac.length - 2]) << 8))) >> 6;
+                id = id % (maxDataCenterId + 1);
+            }
+        } catch (Exception e) {
+            System.out.println(" getDataCenterId: " + e.getMessage());
+        }
+        return id;
+    }
+}

+ 1 - 1
lift-upload/src/main/java/com/upload/controller/RestResponse.java

@@ -1,4 +1,4 @@
-package com.upload.controller;
+package com.upload.config;
 
 import java.io.Serializable;
 

+ 53 - 0
lift-upload/src/main/java/com/upload/config/SystemConfiguration.java

@@ -0,0 +1,53 @@
+package com.upload.config;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.PostConstruct;
+
+/**
+ * <p>
+ * 配置bean注入
+ * </p>
+ *
+ * @author wcz
+ * @since 2019/12/3
+ */
+@Slf4j
+@Data
+@Configuration
+@ConfigurationProperties(prefix = "aliyun.oss")
+public class SystemConfiguration {
+
+    private String endpoint;
+
+    private String bucketName;
+
+    private String accessKeySecret;
+
+    private String accessKeyId;
+
+    @PostConstruct
+    private void print() {
+        log.info("Hint: the Configuration for Aliyun OSS Client.");
+        log.info("============================================================");
+        log.info("###| endpoint       : {}", endpoint);
+        log.info("###| accessKeyId    : {}", accessKeyId);
+        log.info("###| accessKeySecret: {}", accessKeySecret);
+        log.info("###| bucketName     : {}", bucketName);
+        log.info("============================================================");
+    }
+
+    /**
+     * 创建aliyun OSS bean,每次使用完连接释放
+     */
+    public AliyunOSS build() {
+        if (StrUtil.hasEmpty(endpoint, accessKeyId, accessKeySecret, bucketName)) {
+            return AliyunOSS.me();
+        }
+        return AliyunOSS.me(endpoint, accessKeyId, accessKeySecret, bucketName);
+    }
+}

+ 102 - 0
lift-upload/src/main/java/com/upload/config/Validate.java

@@ -0,0 +1,102 @@
+package com.upload.config;
+
+import cn.hutool.core.exceptions.ValidateException;
+import cn.hutool.core.util.ObjectUtil;
+
+import java.util.Objects;
+
+/**
+ * <p>
+ * 条件判断,如果不符合条件,抛出异常
+ * </p>
+ */
+public interface Validate {
+
+    static ValidateException validateException(String message) {
+        return new ValidateException(message);
+    }
+
+    /**
+     * 判断表达式是否为真,如果为假,直接抛出异常,返回message
+     *
+     * @param expression 需要判断的布尔表达式
+     * @param message    抛出异常的消息
+     */
+    static void isTrue(boolean expression, String message) {
+        if (!expression) {
+            throw validateException(message);
+        }
+    }
+
+    /**
+     * 判断表达式是否为真,如果为真,直接抛出异常,返回message
+     *
+     * @param expression 需要判断的布尔表达式
+     * @param message    抛出异常的消息
+     */
+    static void notTrue(boolean expression, String message) {
+        if (expression) {
+            throw validateException(message);
+        }
+    }
+
+    /**
+     * 判断对象object是否为空,如果不为空,直接抛出异常,返回message
+     *
+     * @param object  参数值
+     * @param message 抛出异常的消息
+     */
+    static void isNull(Object object, String message) {
+        isTrue(Objects.isNull(object), message);
+    }
+
+    /**
+     * 判断对象object是否为空,如果为真,直接抛出异常,返回message
+     *
+     * @param object  参数值
+     * @param message 抛出异常的消息
+     */
+    static void notNull(Object object, String message) {
+        isTrue(Objects.nonNull(object), message);
+    }
+
+    static void between(int value, int min, int max, String message) {
+        isTrue(value >= min && value <= max, message);
+    }
+
+    static void notBetween(int value, int min, int max, String message) {
+        isTrue(value < min || value > max, message);
+    }
+
+    static void equals(int one, int other, String message) {
+        isTrue(one == other, message);
+    }
+
+    static void notEquals(int one, int other, String message) {
+        isTrue(one != other, message);
+    }
+
+    static void greater(int value, int bounds, String message) {
+        isTrue(value > bounds, message);
+    }
+
+    static void less(int value, int bounds, String message) {
+        isTrue(value < bounds, message);
+    }
+
+    static void notEmpty(Object object, String message) {
+        isTrue(ObjectUtil.isNotEmpty(object), message);
+    }
+
+    static void isEmpty(Object object, String message) {
+        isTrue(ObjectUtil.isEmpty(object), message);
+    }
+
+    static void isBlank(CharSequence cs, String message) {
+        isTrue(Objects.isNull(cs) || cs.toString().trim().isEmpty(), message);
+    }
+
+    static void notBlank(CharSequence cs, String message) {
+        isTrue(Objects.nonNull(cs) && cs.toString().trim().length() > 0, message);
+    }
+}

+ 122 - 0
lift-upload/src/main/java/com/upload/config/ValuePool.java

@@ -0,0 +1,122 @@
+package com.upload.config;
+
+/**
+ * 系统常量池
+ * Copy to jodd.util
+ */
+public interface ValuePool {
+
+    String AMPERSAND = "&";
+    String AND = "and";
+    String AT = "@";
+    String ASTERISK = "*";
+    String STAR = ASTERISK;
+    String BACK_SLASH = "\\";
+    String COLON = ":";
+    String COMMA = ",";
+    String DASH = "-";
+    String DOLLAR = "$";
+    String DOT = ".";
+    String DOTDOT = "..";
+    String DOT_CLASS = ".class";
+    String DOT_JAVA = ".java";
+    String EMPTY = "";
+    String EQUALS = "=";
+    String FALSE = "false";
+    String SLASH = "/";
+    String HASH = "#";
+    String HAT = "^";
+    String LEFT_BRACE = "{";
+    String LEFT_BRACKET = "(";
+    String LEFT_CHEV = "<";
+    String NEWLINE = "\n";
+    String N = "n";
+    String NO = "no";
+    String NULL = "null";
+    String OFF = "off";
+    String ON = "on";
+    String PERCENT = "%";
+    String PIPE = "|";
+    String PLUS = "+";
+    String QUESTION_MARK = "?";
+    String EXCLAMATION_MARK = "!";
+    String QUOTE = "\"";
+    String RETURN = "\r";
+    String TAB = "\t";
+    String RIGHT_BRACE = "}";
+    String RIGHT_BRACKET = ")";
+    String RIGHT_CHEV = ">";
+    String SEMICOLON = ";";
+    String SINGLE_QUOTE = "'";
+    String SPACE = " ";
+    String LEFT_SQ_BRACKET = "[";
+    String RIGHT_SQ_BRACKET = "]";
+    String TRUE = "true";
+    String UNDERSCORE = "_";
+    String UTF_8 = "UTF-8";
+    String ISO_8859_1 = "ISO-8859-1";
+    String Y = "y";
+    String YES = "yes";
+    String ONE = "1";
+    String ZERO = "0";
+    String DOLLAR_LEFT_BRACE = "${";
+    String HASH_LEFT_BRACE = "#{";
+    String CRLF = "\r\n";
+    //HTML
+    String HTML_NBSP = "&nbsp;";
+    String HTML_AMP = "&amp";
+    String HTML_QUOTE = "&quot;";
+    String HTML_LT = "&lt;";
+    String HTML_GT = "&gt;";
+    // ----------------------------------------------------------------log
+    String LOG_PREFIX = "###| ";
+    String LOG_LINE = "============================================================";
+    String LOG_GLOBAL_EXCEPTION_LINE = "====================== GlobalDefaultException ======================";
+    String LOG_URL = LOG_PREFIX + "URL          : ";
+    String LOG_IP = LOG_PREFIX + "IP           : ";
+    String LOG_CLASS_METHOD = LOG_PREFIX + "CLASS_METHOD : ";
+    String LOG_ARGS = LOG_PREFIX + "ARGS         : ";
+    String LOG_RESPONSE = LOG_PREFIX + "RESPONSE     : ";
+    String LOG_STATUS = LOG_PREFIX + "STATUS       : ";
+    String LOG_EXCEPTION = LOG_PREFIX + "EXCEPTION    : ";
+
+    //===================上传相关状态值和判断方法======================================
+    /**
+     * 图片上传最大大小10M * 1024 * 1024
+     */
+    long UPLOAD_MAX_SIZE_PIC = 10 << 20;
+    String UPLOAD_MAX_SIZE_PIC_DESC = "图片文件大小不超过10M";
+    /**
+     * 文件上传最大大小50M * 1024 * 1024
+     */
+    long UPLOAD_MAX_SIZE_FILE = 50 << 20;
+    String UPLOAD_MAX_SIZE_FILE_DESC = "常用文件大小不超过50M";
+    /**
+     * 视频上传最大大小100M * 1024 * 1024
+     */
+    long UPLOAD_MAX_SIZE_VIDEO = 100 << 20;
+    String UPLOAD_MAX_SIZE_VIDEO_DESC = "视频文件大小不超过100M";
+    /**
+     * 上传图片文件类型
+     */
+    String[] UPLOAD_TYPE_PICS = {".jpg", ".jpeg", ".png", ".bmp", ".gif"};
+    /**
+     * 上传其他文件类型
+     */
+    String[] UPLOAD_TYPE_FILES = {".pdf", ".txt", ".rar", ".zip", ".7z", ".xls", ".xlsx", ".doc", ".docx", ".ppt", ".pptx"};
+    /**
+     * 上传视频文件类型
+     */
+    String[] UPLOAD_TYPE_VIDEOS = {".mov", ".mp4", ".avi", ".mpg", ".mpeg", ".rm", ".rmvb", ".wmv"};
+    String UPLOAD_DATA_MISSING = "没有接收到文件数据";
+    String UPLOAD_FAIL = "上传文件失败";
+    String UPLOAD_FORMAT_NOT_SUPPORT = "文件格式暂时不支持";
+    String UPLOAD_FORMAT_MISSING = "原文件名解析不到文件格式";
+    String UPLOAD_FORMAT_ILLEGAL = "原文件名不合法";
+    String UPLOAD_ORIGINAL_NAME_MISSING = "未解析到原文件名";
+
+    /**
+     * 水印图片地址
+     */
+    String MARK_IMAGE_PATH="c:/watermark.png";
+}

+ 0 - 194
lift-upload/src/main/java/com/upload/controller/SystemConfiguration.java

@@ -1,194 +0,0 @@
-package com.upload.controller;
-
-import cn.com.ty.lift.common.aliservice.aliyunoss.AliyunOSS;
-import cn.com.ty.lift.common.sql.SqlAnalysisInterceptor;
-import cn.com.ty.lift.common.sql.SqlIllegalInterceptor;
-import cn.com.ty.lift.common.verify.Validation;
-import cn.hutool.core.date.DatePattern;
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.parser.ISqlParser;
-import com.baomidou.mybatisplus.core.parser.SqlParserHelper;
-import com.baomidou.mybatisplus.extension.plugins.PaginationInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.PerformanceInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.SqlExplainInterceptor;
-import com.baomidou.mybatisplus.extension.plugins.tenant.TenantHandler;
-import com.baomidou.mybatisplus.extension.plugins.tenant.TenantSqlParser;
-import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
-import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
-import lombok.Data;
-import lombok.extern.slf4j.Slf4j;
-import net.sf.jsqlparser.expression.Expression;
-import net.sf.jsqlparser.expression.LongValue;
-import org.apache.ibatis.mapping.MappedStatement;
-import org.springframework.aop.support.DefaultPointcutAdvisor;
-import org.springframework.aop.support.annotation.AnnotationMatchingPointcut;
-import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
-import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.bind.annotation.RestController;
-
-import javax.annotation.PostConstruct;
-import java.time.format.DateTimeFormatter;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * <p>
- * 配置bean注入
- * </p>
- *
- * @author wcz
- * @since 2019/12/3
- */
-@Slf4j
-@Data
-@Configuration
-@ConfigurationProperties(prefix = "aliyun.oss")
-public class SystemConfiguration {
-
-    private String endpoint;
-
-    private String bucketName;
-
-    private String accessKeySecret;
-
-    private String accessKeyId;
-
-    @PostConstruct
-    private void print() {
-        log.info("Hint: the Configuration for Aliyun OSS Client.");
-        log.info("============================================================");
-        log.info("###| endpoint       : {}", endpoint);
-        log.info("###| accessKeyId    : {}", accessKeyId);
-        log.info("###| accessKeySecret: {}", accessKeySecret);
-        log.info("###| bucketName     : {}", bucketName);
-        log.info("============================================================");
-    }
-
-    /**
-     * 创建aliyun OSS bean,每次使用完连接释放
-     */
-    public AliyunOSS build() {
-        if (StrUtil.hasEmpty(endpoint, accessKeyId, accessKeySecret, bucketName)) {
-            return AliyunOSS.me();
-        }
-        return AliyunOSS.me(endpoint, accessKeyId, accessKeySecret, bucketName);
-    }
-
-    /**
-     * 全局格式化日期
-     */
-    @Bean
-    public Jackson2ObjectMapperBuilderCustomizer jsonCustomizer() {
-        return builder -> {
-            builder.serializers(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
-            builder.serializers(new LocalDateSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
-            builder.serializers(new LocalTimeSerializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
-
-            builder.deserializers(new LocalDateDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATE_PATTERN)));
-            builder.deserializers(new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_DATETIME_PATTERN)));
-            builder.deserializers(new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DatePattern.NORM_TIME_PATTERN)));
-
-            builder.serializerByType(Long.class, ToStringSerializer.instance);
-        };
-    }
-
-    /**
-     * mybatis-plus 执行sql性能监测
-     */
-    @Bean
-    @ConditionalOnMissingBean(PerformanceInterceptor.class)
-    public SqlAnalysisInterceptor sqlAnalysisInterceptor() {
-        SqlAnalysisInterceptor sqlAnalysisInterceptor = new SqlAnalysisInterceptor();
-        //格式化执行的sql
-        sqlAnalysisInterceptor.setFormat(true);
-        //sql写入日志文件
-        sqlAnalysisInterceptor.setLogWrite(true);
-        return sqlAnalysisInterceptor;
-    }
-
-    /**
-     * SQL是影响系统性能最重要的因素,所以拦截提示不合理的SQL语句
-     */
-//    @Bean
-    @ConditionalOnMissingBean
-    public SqlIllegalInterceptor sqlIllegalInterceptor() {
-        SqlIllegalInterceptor sqlIllegalInterceptor = new SqlIllegalInterceptor();
-        return sqlIllegalInterceptor;
-    }
-
-    /**
-     * 防止全表更新与删除
-     */
-//    @Bean
-//    @ConditionalOnMissingBean
-    public SqlExplainInterceptor sqlExplainInterceptor() {
-        SqlExplainInterceptor sqlExplainInterceptor = new SqlExplainInterceptor();
-        return sqlExplainInterceptor;
-    }
-
-    /**
-     * 方法参数校验拦截器,标注了@Verifier的方法,会检查参数,如果参数不满足条件,直接抛出异常
-     */
-    @Bean
-    public DefaultPointcutAdvisor defaultPointcutAdvisor() {
-        DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
-        advisor.setPointcut(new AnnotationMatchingPointcut(RestController.class, Validation.class));
-        advisor.setAdvice(new ValidateMethodInterceptor());
-        advisor.setOrder(2);
-        return advisor;
-    }
-
-    /**
-     * 多租户 SQL 解析器
-     */
-//    @Bean
-    @ConditionalOnMissingBean
-    public PaginationInterceptor paginationInterceptor() {
-        PaginationInterceptor paginationInterceptor = new PaginationInterceptor();
-        /*
-         * 多租户SQL 解析处理拦截器<br>
-         * 动态获取当前登录用户所在的mt_company_id( 注意观察 SQL )<br>
-         */
-        List<ISqlParser> sqlParserList = new ArrayList<>();
-        TenantSqlParser tenantSqlParser = new TenantSqlParser();
-        tenantSqlParser.setTenantHandler(new TenantHandler() {
-            @Override
-            public Expression getTenantId() {
-                // 该 where 条件 3.2.0 版本开始添加的,用于分区是否为在 where 条件中使用
-                // 如果是in/between之类的多个tenantId的情况,参考下方示例
-                return new LongValue(1L);
-            }
-
-            @Override
-            public String getTenantIdColumn() {
-                return "mt_company_id";
-            }
-
-            @Override
-            public boolean doTableFilter(String tableName) {
-                // 这里可以判断是否过滤表
-            /*
-            if ("user".equals(tableName)) {
-                return true;
-            }*/
-                return false;
-            }
-        });
-        sqlParserList.add(tenantSqlParser);
-        paginationInterceptor.setSqlParserList(sqlParserList);
-        paginationInterceptor.setSqlParserFilter((metaObject) -> {
-            MappedStatement ms = SqlParserHelper.getMappedStatement(metaObject);
-            // 过滤自定义查询此时无租户信息约束
-            return "com.baomidou.springboot.mapper.UserMapper.selectListBySQL".equals(ms.getId());
-        });
-        return paginationInterceptor;
-    }
-}

+ 40 - 71
lift-upload/src/main/java/com/upload/controller/UploadController.java

@@ -1,21 +1,21 @@
 package com.upload.controller;
 
-import cn.com.ty.lift.common.utils.ValuePool;
-import cn.com.ty.lift.common.verify.Validate;
 import cn.hutool.core.util.ArrayUtil;
-import cn.hutool.core.util.StrUtil;
-import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.upload.service.UploadService;
+import com.upload.config.*;
+import com.upload.util.WatermarkUtil;
 import lombok.AllArgsConstructor;
 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 java.time.LocalDate;
-import java.time.format.DateTimeFormatter;
-import java.util.*;
+import java.io.IOException;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.FutureTask;
 
 /**
  * 图片上传接口
@@ -23,56 +23,58 @@ import java.util.*;
 @Slf4j
 @AllArgsConstructor
 @RestController
-@RequestMapping("common")
 public class UploadController {
-
-    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd");
-
-    private SystemConfiguration systemConfiguration;
+    UploadService uploadService;
+    SystemConfiguration systemConfiguration;
 
     /**
      * 批量上传多个文件
      *
-     * @param files 文件列表
+     * @param multipartFiles 文件列表
      * @return RestResponse
      */
     @PostMapping("uploads")
-    public RestResponse uploads(@RequestParam("files") MultipartFile[] files) {
-        Validate.notTrue(ArrayUtil.isEmpty(files), ValuePool.UPLOAD_DATA_MISSING);
-        Map<String, MultipartFile> fileMap = new LinkedHashMap<>();
+    public RestResponse<?> uploads(@RequestParam("files") MultipartFile[] multipartFiles, @RequestParam(required = false) String workerName, @RequestParam(required = false) String registrationCode) throws IOException {
+        Validate.notTrue(ArrayUtil.isEmpty(multipartFiles), ValuePool.UPLOAD_DATA_MISSING);
+        Map<String, byte[]> fileMap = new LinkedHashMap<>();
         //1 先解析文件格式
-        for (MultipartFile file : files) {
-            String fileName = handleFile(file);
-            fileMap.put(fileName, file);
-        }
-        //2 批量上传
-        try {
-            List<String> urls = new LinkedList<>();
-            for (Map.Entry<String, MultipartFile> entry : fileMap.entrySet()) {
-                String url = systemConfiguration.build().putObject(entry.getKey(), entry.getValue().getBytes());
-                log.info("upload file complete, file URL: {}", url);
-                Validate.notNull(url, ValuePool.UPLOAD_FAIL);
-                urls.add(url);
+        for (MultipartFile multipartFile : multipartFiles) {
+            String fileName = uploadService.handleFile(multipartFile);
+            byte[] fileByte;
+            if (registrationCode == null || workerName == null) {
+                fileByte = multipartFile.getBytes();
+            } else {
+                fileByte = WatermarkUtil.pressImageAndWorld(multipartFile, ValuePool.MARK_IMAGE_PATH, workerName, registrationCode);
             }
-            return RestResponse.success(urls);
-        } catch (Exception e) {
-            log.error("upload file occur exception", e);
-            return RestResponse.fail(ValuePool.UPLOAD_FAIL);
+            fileMap.put(fileName, fileByte);
         }
+        //2 批量上传
+        return AliyunOSS.me().putObjects(fileMap);
     }
 
     /**
      * 上传单个文件
      *
-     * @param file 上传的文件
+     * @param multipartFile 上传的文件
      * @return RestResponse
      */
     @PostMapping("upload")
-    public RestResponse upload(@RequestParam("file") MultipartFile file) {
-        Validate.notTrue(Objects.isNull(file) || file.isEmpty(), ValuePool.UPLOAD_DATA_MISSING);
-        String fileName = handleFile(file);
+    public RestResponse<?> upload(@RequestParam("file") MultipartFile multipartFile, @RequestParam(required = false) String workerName, @RequestParam(required = false) String registrationCode) throws IOException {
+        Validate.notTrue(Objects.isNull(multipartFile) || multipartFile.isEmpty(), ValuePool.UPLOAD_DATA_MISSING);
+        String fileName = uploadService.handleFile(multipartFile);
+        byte[] fileByte;
+        if (registrationCode == null || workerName == null) {
+            fileByte = multipartFile.getBytes();
+        } else {
+            fileByte = WatermarkUtil.pressImageAndWorld(multipartFile, ValuePool.MARK_IMAGE_PATH, workerName, registrationCode);
+        }
         try {
-            String url = systemConfiguration.build().putObject(fileName, file.getBytes());
+            FutureTask<String> futureTask = new FutureTask<>(() ->
+                    systemConfiguration.build().putObject(fileName, fileByte));
+            new Thread(futureTask).start();
+            if (!futureTask.isDone())
+                log.info("task has not finished!");
+            String url = futureTask.get();
             log.info("upload file complete, file URL: {}", url);
             return RestResponse.success(url);
         } catch (Exception e) {
@@ -80,37 +82,4 @@ public class UploadController {
             return RestResponse.fail(ValuePool.UPLOAD_FAIL);
         }
     }
-
-    /**
-     * 校验文件大小,文件格式,生成新文件名
-     *
-     * @param file the {@link MultipartFile} to upload
-     * @return the name string of the file.
-     */
-    private String handleFile(MultipartFile file) {
-        Validate.notTrue(Objects.isNull(file) || file.isEmpty(), ValuePool.UPLOAD_DATA_MISSING);
-        // 获取文件名,带后缀
-        String originalFilename = file.getOriginalFilename();
-        log.info("the original file name:{}", originalFilename);
-        // 获取文件的后缀格式
-        Validate.notNull(originalFilename, ValuePool.UPLOAD_ORIGINAL_NAME_MISSING);
-        int lastDotIndex = originalFilename.lastIndexOf(ValuePool.DOT);
-        Validate.notTrue(-1 == lastDotIndex, ValuePool.UPLOAD_FORMAT_MISSING);
-        String fileSuffix = originalFilename.substring(lastDotIndex).toLowerCase();
-        Validate.notNull(fileSuffix, ValuePool.UPLOAD_FORMAT_ILLEGAL);
-        long fileSize = file.getSize();
-        log.info("the size of file: {}", fileSize);
-        if (StrUtil.equalsAny(fileSuffix, ValuePool.UPLOAD_TYPE_PICS)) {
-            Validate.notTrue(fileSize > ValuePool.UPLOAD_MAX_SIZE_PIC, ValuePool.UPLOAD_MAX_SIZE_PIC_DESC);
-        } else if (StrUtil.equalsAny(fileSuffix, ValuePool.UPLOAD_TYPE_FILES)) {
-            Validate.notTrue(fileSize > ValuePool.UPLOAD_MAX_SIZE_FILE, ValuePool.UPLOAD_MAX_SIZE_FILE_DESC);
-        } else if (StrUtil.equalsAny(fileSuffix, ValuePool.UPLOAD_TYPE_VIDEOS)) {
-            Validate.notTrue(fileSize > ValuePool.UPLOAD_MAX_SIZE_VIDEO, ValuePool.UPLOAD_MAX_SIZE_VIDEO_DESC);
-        } else {
-            throw Validate.validateException(ValuePool.UPLOAD_FORMAT_NOT_SUPPORT);
-        }
-        String fileName = StrUtil.format("{}/{}{}", DATE_TIME_FORMATTER.format(LocalDate.now()), IdWorker.getIdStr(), fileSuffix);
-        log.info("the new file name:{}", fileName);
-        return fileName;
-    }
 }

+ 0 - 49
lift-upload/src/main/java/com/upload/controller/ValidateMethodInterceptor.java

@@ -1,49 +0,0 @@
-package com.upload.controller;
-
-import cn.com.ty.lift.common.verify.Val;
-import cn.com.ty.lift.common.verify.Validation;
-import cn.com.ty.lift.common.verify.Validator;
-import org.aopalliance.intercept.MethodInterceptor;
-import org.aopalliance.intercept.MethodInvocation;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Parameter;
-import java.util.Objects;
-
-/**
- * the {@link MethodInterceptor} for verify parameter.
- *
- * @author wcz
- * @since 2020/3/15
- */
-public class ValidateMethodInterceptor implements MethodInterceptor {
-    @Override
-    public Object invoke(MethodInvocation invocation) throws Throwable {
-        //check whether the method is present with validation annotation.
-        Method method = invocation.getMethod();
-        boolean annotationPresent = method.isAnnotationPresent(Validation.class);
-        if(!annotationPresent){
-            return invocation.proceed();
-        }
-        //check the list of parameters.
-        Parameter[] parameters = method.getParameters();
-        if(Objects.isNull(parameters) || parameters.length == 0){
-            return invocation.proceed();
-        }
-        //if the parameter is present with Val. return the index.
-        Object object = null;
-        Object[] arguments = invocation.getArguments();
-        for (int i = 0; i < parameters.length; i++) {
-            if(parameters[i].isAnnotationPresent(Val.class)){
-                object = arguments[i];
-                break;
-            }
-        }
-        if(Objects.isNull(object)){
-            return invocation.proceed();
-        }
-        Validation validation = method.getDeclaredAnnotation(Validation.class);
-        Validator.valid(object, validation.fields());
-        return invocation.proceed();
-    }
-}

+ 28 - 0
lift-upload/src/main/java/com/upload/entity/Local.java

@@ -0,0 +1,28 @@
+package com.upload.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.awt.*;
+
+@Data
+@AllArgsConstructor
+public class Local {
+    private String workerName;
+    private int workerNameX;
+    private int workerNameY;
+    private String dateTime;
+    private int dateTimeX;
+    private int dateTimeY;
+    private String registrationCode;
+    private int registrationCodeX;
+    private int registrationCodeY;
+    private int markWidth;
+    private int markHeight;
+    private int markX;
+    private int markY;
+    private MultipartFile multipartFile;
+    private Font font;
+    private Color color;
+}

+ 52 - 0
lift-upload/src/main/java/com/upload/service/UploadService.java

@@ -0,0 +1,52 @@
+package com.upload.service;
+
+import cn.hutool.core.util.StrUtil;
+import com.upload.config.IdWorker;
+import com.upload.config.Validate;
+import com.upload.config.ValuePool;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.Objects;
+
+@Service
+@Slf4j
+public class UploadService {
+    private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy/MM/dd");
+
+    /**
+     * 校验文件大小,文件格式,生成新文件名
+     *
+     * @param file the {@link MultipartFile} to upload
+     * @return the name string of the file.
+     */
+    public String handleFile(MultipartFile file) {
+        Validate.notTrue(Objects.isNull(file) || file.isEmpty(), ValuePool.UPLOAD_DATA_MISSING);
+        // 获取文件名,带后缀
+        String originalFilename = file.getOriginalFilename();
+        log.info("the original file name:{}", originalFilename);
+        // 获取文件的后缀格式
+        Validate.notNull(originalFilename, ValuePool.UPLOAD_ORIGINAL_NAME_MISSING);
+        int lastDotIndex = originalFilename.lastIndexOf(ValuePool.DOT);
+        Validate.notTrue(-1 == lastDotIndex, ValuePool.UPLOAD_FORMAT_MISSING);
+        String fileSuffix = originalFilename.substring(lastDotIndex).toLowerCase();
+        Validate.notNull(fileSuffix, ValuePool.UPLOAD_FORMAT_ILLEGAL);
+        long fileSize = file.getSize();
+        log.info("the size of file: {}", fileSize);
+        if (StrUtil.equalsAny(fileSuffix, ValuePool.UPLOAD_TYPE_PICS)) {
+            Validate.notTrue(fileSize > ValuePool.UPLOAD_MAX_SIZE_PIC, ValuePool.UPLOAD_MAX_SIZE_PIC_DESC);
+        } else if (StrUtil.equalsAny(fileSuffix, ValuePool.UPLOAD_TYPE_FILES)) {
+            Validate.notTrue(fileSize > ValuePool.UPLOAD_MAX_SIZE_FILE, ValuePool.UPLOAD_MAX_SIZE_FILE_DESC);
+        } else if (StrUtil.equalsAny(fileSuffix, ValuePool.UPLOAD_TYPE_VIDEOS)) {
+            Validate.notTrue(fileSize > ValuePool.UPLOAD_MAX_SIZE_VIDEO, ValuePool.UPLOAD_MAX_SIZE_VIDEO_DESC);
+        } else {
+            throw Validate.validateException(ValuePool.UPLOAD_FORMAT_NOT_SUPPORT);
+        }
+        String fileName = StrUtil.format("{}/{}{}", DATE_TIME_FORMATTER.format(LocalDate.now()), new IdWorker().nextId(), fileSuffix);
+        log.info("the new file name:{}", fileName);
+        return fileName;
+    }
+}

+ 156 - 0
lift-upload/src/main/java/com/upload/util/WatermarkUtil.java

@@ -0,0 +1,156 @@
+package com.upload.util;
+
+import com.upload.entity.Local;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import javax.imageio.stream.ImageOutputStream;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.ArrayList;
+
+public class WatermarkUtil {
+
+    /**
+     * 加图片水印
+     *
+     * @param bufImg  --BufferedImage  用来画图的宽高跟需要加水印的图片一样的空白图
+     * @param img     --需要加水印的图片
+     * @param markImg --水印图片
+     * @param width   --水印图片宽
+     * @param height  --水印图片高
+     * @param x       --水印相对于底片的x轴坐标(PS:左上角为(0,0))
+     * @param y       --水印相对于底片的y轴坐标(PS:左上角为(0,0))
+     */
+    public static void markPic(BufferedImage bufImg, Image img, Image markImg, int width, int height, int x, int y) {
+        //取到画笔
+        Graphics2D g = bufImg.createGraphics();
+        //画底片
+        g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
+        //画水印位置
+        g.drawImage(markImg, x, y, width, height, null);
+        g.dispose();
+    }
+
+
+    /**
+     * 加文字水印
+     *
+     * @param bufImg --BufferedImage  用来画图的宽高跟需要加水印的图片一样的空白图
+     * @param img    --需要加水印的图片
+     * @param text   --水印文字
+     * @param font   --字体
+     * @param color  --颜色
+     * @param x      --水印相对于底片的x轴坐标(PS:左上角为(0,0))
+     * @param y      --水印相对于底片的y轴坐标(PS:左上角为(0,0))
+     */
+    public static void markWord(BufferedImage bufImg, Image img, String text, Font font, Color color, int x, int y) {
+        //取到画笔
+        Graphics2D g = bufImg.createGraphics();
+        //画底片
+        g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
+        g.setColor(color);
+        g.setFont(font);
+        //位置
+        g.drawString(text, x, y);
+        g.dispose();
+    }
+
+    public static void markPicAndWord(BufferedImage bufImg, Image img, Image markImg, Local local) {
+        //取到画笔
+        Graphics2D g = bufImg.createGraphics();
+        //画底片
+        g.drawImage(img, 0, 0, bufImg.getWidth(), bufImg.getHeight(), null);
+        //画水印图片
+        g.drawImage(markImg, local.getMarkX(), local.getMarkY(), local.getMarkWidth(), local.getMarkHeight(), null);
+        //画水印文字
+        g.setColor(local.getColor());
+        g.setFont(local.getFont());
+        g.drawString(local.getRegistrationCode(), local.getRegistrationCodeX(), local.getRegistrationCodeY());
+        g.drawString(local.getDateTime(), local.getDateTimeX(), local.getDateTimeY());
+        g.drawString(local.getWorkerName(), local.getWorkerNameX(), local.getWorkerNameY());
+
+        g.dispose();
+    }
+
+    /**
+     * 单文件返回水印图片byte[]数组
+     *
+     * @param multipartFile    待加水印的文件
+     * @param watermarkImage   水印图片本地图片地址
+     * @param workerName       水印文字
+     * @param registrationCode 水印文字
+     * @return 操作结果
+     * @throws IOException
+     */
+    public static byte[] pressImageAndWorld(MultipartFile multipartFile, String watermarkImage, String workerName, String registrationCode) throws IOException {
+        String originFileName = multipartFile.getOriginalFilename();
+        int lastSplit = originFileName.lastIndexOf(".");
+        String suffix = originFileName.substring(lastSplit + 1);
+        return press(watermarkImage, workerName, registrationCode, multipartFile, suffix);
+    }
+
+    /**
+     * 多文件返回图片 ArrayList<byte[]> 数组
+     *
+     * @param multipartFiles   待加水印的文件
+     * @param watermarkImage   水印图片本地图片地址
+     * @param workerName       水印文字
+     * @param registrationCode 水印文字
+     * @return 操作结果
+     * @throws IOException
+     */
+    public static ArrayList<byte[]> pressImageAndWorld(MultipartFile[] multipartFiles, String watermarkImage, String workerName, String registrationCode) throws IOException {
+        ArrayList<byte[]> bytes = new ArrayList<>();
+        for (MultipartFile multipartFile : multipartFiles) {
+            String originFileName = multipartFile.getOriginalFilename();
+            int lastSplit = originFileName.lastIndexOf(".");
+            String suffix = originFileName.substring(lastSplit + 1);
+            bytes.add(press(watermarkImage, workerName, registrationCode, multipartFile, suffix));
+        }
+        return bytes;
+    }
+
+    private static byte[] press(String watermarkImage, String workerName, String registrationCode, MultipartFile multipartFile, String suffix) throws IOException {
+        // 获取待加水印图片
+        InputStream inputImg = multipartFile.getInputStream();
+        Image img = ImageIO.read(inputImg);
+        // 获取水印图片
+        Image mark = ImageIO.read(new FileInputStream(new File(watermarkImage)));
+        //获取待加水印图片大小
+        int imgWidth = img.getWidth(null);
+        int imgHeight = img.getHeight(null);
+        //把待加水印的图片读入缓存
+        BufferedImage bufImg = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_RGB);
+        //设置字体
+        int fontSize = imgWidth / 30;
+        Font font = new Font("宋体", Font.BOLD, fontSize);
+        //创建输出流
+        ByteArrayOutputStream bs = new ByteArrayOutputStream();
+        ImageOutputStream imageOutputStream = ImageIO.createImageOutputStream(bs);
+        //设置图片和文字位置,水印图片大小
+        int markWidth = imgWidth / 4;
+        int markHeight = (imgWidth * mark.getHeight(null)) / (4 * mark.getWidth(null));
+        //组装要画的数据
+        String now = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-mm-dd hh:mm:ss"));
+        Local local = new Local(
+                workerName, 0, imgHeight - fontSize * 2,
+                now, 0, imgHeight,
+                registrationCode, imgWidth - registrationCode.length() * fontSize / 10 * 6, imgHeight - markHeight - fontSize,
+                markWidth, markHeight, imgWidth - markWidth, imgHeight - markHeight,
+                multipartFile, font, new Color(42, 148, 188));
+        //调用画图片和文字的方法
+        markPicAndWord(bufImg, img, mark, local);
+        ImageIO.write(bufImg, suffix, imageOutputStream);
+
+        //bs.writeTo(fileOutputStream);
+        byte[] bytes = bs.toByteArray();
+        bs.close();
+        inputImg.close();
+        imageOutputStream.close();
+        return bytes;
+    }
+}

+ 2 - 2
lift-upload/src/main/resources/application.yml

@@ -8,5 +8,5 @@ spring:
     active: prod
   servlet:
     multipart:
-      max-file-size: 512MB  # Max file size,默认1M
-      max-request-size: 512MB  # Max request size,默认10M
+      max-file-size: 3MB  # Max file size,默认1M
+      max-request-size: 5MB  # Max request size,默认10M