Aslee před 3 roky
rodič
revize
39f500b24f

+ 317 - 0
pom.xml

@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.3.4.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.caimei365</groupId>
+    <artifactId>caimei-zplm-admin-api</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+
+    <properties>
+        <java.version>1.8</java.version>
+        <!--maven.build.timestamp保存了maven编译时间戳-->
+        <timestamp>${maven.build.timestamp}</timestamp>
+        <!--指定时间格式-->
+        <maven.build.timestamp.format>yyyyMMdd-HHmmss</maven.build.timestamp.format>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+            <exclusions>
+                <exclusion>
+                    <groupId>org.junit.vintage</groupId>
+                    <artifactId>junit-vintage-engine</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <scope>provided</scope>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <scope>runtime</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis.spring.boot</groupId>
+            <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.1.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+            <version>1.2.5</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>mybatis-spring-boot-starter</artifactId>
+                    <groupId>org.mybatis.spring.boot</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>3.8.3</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <!--邮箱发送-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+        <!-- redis依赖包 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>io.lettuce</groupId>
+                    <artifactId>lettuce-core</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>redis.clients</groupId>
+            <artifactId>jedis</artifactId>
+        </dependency>
+        <!--手机短信-->
+        <dependency>
+            <groupId>caimei</groupId>
+            <artifactId>smsClient</artifactId>
+            <version>1.0</version>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.6</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-codec</groupId>
+            <artifactId>commons-codec</artifactId>
+            <version>${commons-codec.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>commons-lang</groupId>
+            <artifactId>commons-lang</artifactId>
+            <version>2.6</version>
+        </dependency>
+        <!--dfs-->
+        <dependency>
+            <groupId>com.github.tobato</groupId>
+            <artifactId>fastdfs-client</artifactId>
+            <version>1.26.1-RELEASE</version>
+        </dependency>
+        <!--引入商品模块-->
+        <dependency>
+            <groupId>com.caimei.module</groupId>
+            <artifactId>product</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+        <dependency>
+            <groupId>org.bouncycastle</groupId>
+            <artifactId>bcprov-jdk16</artifactId>
+            <version>1.46</version>
+        </dependency>
+        <dependency>
+            <groupId>com.caimei.module</groupId>
+            <artifactId>pay</artifactId>
+            <version>0.0.1-SNAPSHOT</version>
+        </dependency>
+        <!-- 对 HTML 富文本文档进行解析和操作 -->
+        <dependency>
+            <groupId>org.jsoup</groupId>
+            <artifactId>jsoup</artifactId>
+            <version>1.9.2</version>
+        </dependency>
+
+        <!--阿里云开放搜索(OpenSearch)sdk -->
+        <dependency>
+            <groupId>com.aliyun.opensearch</groupId>
+            <artifactId>aliyun-sdk-opensearch</artifactId>
+            <version>3.5.1</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>guava</artifactId>
+                    <groupId>com.google.guava</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>commons-lang</artifactId>
+                    <groupId>commons-lang</groupId>
+                </exclusion>
+                <exclusion>
+                    <artifactId>httpclient</artifactId>
+                    <groupId>org.apache.httpcomponents</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-cache</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>io.github.openfeign</groupId>
+            <artifactId>feign-httpclient</artifactId>
+            <version>10.2.0</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>httpclient</artifactId>
+                    <groupId>org.apache.httpcomponents</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+            <version>4.0.6</version> <!-- 注:如提示报错,先升级基础包版,无法解决可联系技术支持 -->
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
+            <version>1.1.0</version>
+        </dependency>
+
+
+        <!--对象存储oss-->
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.10.2</version>
+        </dependency>
+
+        <!--knife4j接口文档-->
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+            <version>3.0.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>io.projectreactor</groupId>
+            <artifactId>reactor-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+            <version>4.4.1</version>
+        </dependency>
+
+
+        <!--消息推送-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.amqp</groupId>
+            <artifactId>spring-amqp</artifactId>
+            <version>1.7.5.RELEASE</version>
+        </dependency>
+        <dependency>
+            <groupId>com.rabbitmq</groupId>
+            <artifactId>amqp-client</artifactId>
+            <version>5.12.0</version>
+        </dependency>
+    </dependencies>
+
+    <profiles>
+        <profile>
+            <id>dev</id>
+            <properties>
+                <!-- 环境标识,需要与配置文件的名称相对应 -->
+                <activatedProperties>dev</activatedProperties>
+            </properties>
+            <activation>
+                <!-- 默认环境 -->
+                <activeByDefault>true</activeByDefault>
+            </activation>
+        </profile>
+        <profile>
+            <id>beta</id>
+            <properties>
+                <activatedProperties>beta</activatedProperties>
+            </properties>
+        </profile>
+        <profile>
+            <id>prod</id>
+            <properties>
+                <activatedProperties>prod</activatedProperties>
+            </properties>
+        </profile>
+    </profiles>
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <resources>
+            <!-- 配置文件路径  -->
+            <resource>
+                <!-- 这里对应项目存放配置文件的目录-->
+                <directory>src/main/resources</directory>
+                <!-- 开启filtering功能  -->
+                <filtering>true</filtering>
+            </resource>
+            <resource>
+                <directory>src/main/resources/config/${activatedProperties}</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <configuration>
+                    <!-- springboot启动类目录 -->
+                    <mainClass>com.caimei.PurchaseApplication</mainClass>
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <!-- 创建一个自动可执行的jar或war文件 -->
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 40 - 0
src/main/java/caimei/PurchaseApplication.java

@@ -0,0 +1,40 @@
+package caimei;
+
+import com.github.tobato.fastdfs.FdfsClientConfig;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.web.servlet.MultipartConfigFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.EnableMBeanExport;
+import org.springframework.context.annotation.Import;
+import org.springframework.jmx.support.RegistrationPolicy;
+
+import javax.servlet.MultipartConfigElement;
+
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/6/4
+ */
+@Import(FdfsClientConfig.class)
+// 解决jmx重复注册bean的问题
+@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
+@SpringBootApplication
+public class PurchaseApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(PurchaseApplication.class, args);
+    }
+
+    /**
+     * 文件上传临时路径
+     */
+    @Bean
+    MultipartConfigElement multipartConfigElement() {
+        MultipartConfigFactory factory = new MultipartConfigFactory();
+        factory.setLocation("/mnt/newdatadrive/data/runtime/jar-instance/purchase/tempImage");
+        return factory.createMultipartConfig();
+    }
+}

+ 294 - 0
src/main/java/caimei/components/RedisService.java

@@ -0,0 +1,294 @@
+package caimei.components;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Redis 服务工具类
+ *
+ * @author : Charles
+ * @date : 2021/3/4
+ */
+@Slf4j
+@Service
+public class RedisService {
+
+	@Resource
+	private RedisTemplate<Serializable, Object> redisTemplate;
+
+    /**
+     * 批量删除
+     * @param keys
+     */
+	public void remove(String... keys) {
+		for(String key :keys){
+			remove(key);
+		}
+	}
+
+    /**
+     * 批量删除正则匹配到的
+     * @param pattern
+     */
+	public void removePattern(String pattern) {
+		Set<Serializable> keys = redisTemplate.keys(pattern);
+        assert keys != null;
+        if (keys.size() > 0){
+			redisTemplate.delete(keys);
+		}
+	}
+
+    /**
+     * 删除
+     * @param key
+     */
+	public void remove(String key) {
+		if (exists(key)) {
+			redisTemplate.delete(key);
+		}
+	}
+
+    /**
+     * 判断缓存中是否存在
+     * @param key
+     * @return boolean
+     */
+	public boolean exists(String key) {
+		return StringUtils.isBlank(key) ? false : redisTemplate.hasKey(key);
+	}
+
+    /**
+     * 读取缓存
+     * @param key
+     * @return
+     */
+	public Object get(String key) {
+		Object result = null;
+		ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
+		result = operations.get(key);
+		return result;
+	}
+
+    /**
+     * 写入缓存
+     * @param key
+     * @param value
+     * @return
+     */
+	public boolean set(String key, Object value) {
+		boolean result = false;
+		try {
+			ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
+			operations.set(key, value);
+			result = true;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+
+    /**
+     * 写入缓存并加上过期时间(秒)
+     * @param key
+     * @param value
+     * @param expireTimeSeconds
+     * @return
+     */
+	public boolean set(String key, Object value, Long expireTimeSeconds) {
+		boolean result = false;
+		try {
+			ValueOperations<Serializable, Object> operations = redisTemplate.opsForValue();
+			operations.set(key, value);
+			redisTemplate.expire(key, expireTimeSeconds, TimeUnit.SECONDS);
+			result = true;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+    /**
+     * 写入过期时间(秒)
+     * @param key
+     * @param expireTimeSeconds
+     * @return
+     */
+	public boolean expire(String key, Long expireTimeSeconds) {
+		boolean result = false;
+		try {
+			redisTemplate.expire(key, expireTimeSeconds, TimeUnit.SECONDS);
+			result = true;
+		} catch (Exception e) {
+			e.printStackTrace();
+		}
+		return result;
+	}
+    /* **************************** 针对list操作的方法 **************************** */
+    /**
+     * 在key对应list的尾部添加
+     * @param key
+     * @param value
+     * @return
+     */
+	public long rightPushForList(String key, Object value) {
+		return redisTemplate.opsForList().rightPush(key, value);
+	}
+
+    /**
+     * 在key对应list的头部添加
+     * @param key
+     * @param value
+     * @return
+     */
+	public long leftPushForList(String key, Object value) {
+		return redisTemplate.opsForList().leftPush(key, value);
+	}
+
+    /**
+     * key对应list的长度
+     * @param key
+     * @return
+     */
+	public long listSize(String key) {
+		return redisTemplate.opsForList().size(key);
+	}
+
+    /**
+     * 获取list集合
+     * @param Key
+     * @param begin
+     * @param end
+     * @return
+     */
+	public List<?> getList(String Key, int begin, int end) {
+		return redisTemplate.opsForList().range(Key, begin, end);
+	}
+
+    /**
+     * 在key对应list的尾部移除
+     * @param key
+     * @return
+     */
+	public Object rightPopForList(String key) {
+		return redisTemplate.opsForList().rightPop(key);
+	}
+
+    /**
+     * 在key对应list的头部移除
+     * @param key
+     * @return
+     */
+	public Object leftPopForList(String key) {
+		return redisTemplate.opsForList().leftPop(key);
+	}
+
+    /**
+     * 移除list的index位置上的值
+     * @param Key
+     * @param index
+     * @param value
+     */
+	public void removeList(String Key, long index, Object value) {
+		redisTemplate.opsForList().remove(Key, index, value);
+	}
+
+    /**
+     * 重置list的index位置上的值
+     * @param Key
+     * @param index
+     * @param value
+     */
+	public void setList(String Key, long index, Object value) {
+		redisTemplate.opsForList().set(Key, index, value);
+	}
+
+
+    /**
+     * 写入list
+     * @param key
+     * @param list
+     */
+	public void setList(String key, List list) {
+		if(list!=null&&list.size()>0){
+			for (Object object : list) {
+				rightPushForList(key,object);
+			}
+		}
+	}
+
+    /**
+     * 写入map
+     * @param key
+     * @param map
+     */
+	public void setMap(String key, Map<String, Object> map) {
+		redisTemplate.opsForHash().putAll(key, map);
+	}
+
+    /**
+     * 获取map
+     * @param key
+     * @param mapKey
+     * @return
+     */
+	public Object get(String key, String mapKey) {
+		return redisTemplate.opsForHash().get(key, mapKey);
+	}
+
+    /**
+     * 写入map
+     * @param key
+     * @param hashKey
+     * @param hashValue
+     */
+	public void setMapByKV(String key, Object hashKey, Object hashValue) {
+		redisTemplate.opsForHash().put(key, hashKey,hashValue);
+	}
+
+    /**
+     * 删除map中的某个key-value
+     * @param key
+     * @param hashKey
+     */
+	public void removeHash(String key, String hashKey) {
+		redisTemplate.opsForHash().delete(key, hashKey);
+	}
+
+    /**
+     *
+     * @param key
+     * @return
+     */
+	public Map<Object, Object> getEntries(String key) {
+		return redisTemplate.opsForHash().entries(key);
+	}
+
+    /**
+     *
+     * @param key
+     * @param step
+     * @return
+     */
+	public long increase(String key, long step) {
+		return redisTemplate.opsForValue().increment(key, step);
+	}
+
+    /**
+     * 获取失效时间
+     * @param key
+     * @return
+     */
+	public long getExpireTime(String key) {
+		return redisTemplate.getExpire(key, TimeUnit.SECONDS);
+	}
+
+}

+ 31 - 0
src/main/java/caimei/config/ApiConfig.java

@@ -0,0 +1,31 @@
+package caimei.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import javax.annotation.Resource;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/6/4
+ */
+@Configuration
+public class ApiConfig implements WebMvcConfigurer {
+    @Resource
+    private ApiInterceptor apiInterceptor;
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        //addPathPatterns 用于添加拦截规则
+        //excludePathPatterns 用于排除拦截
+        registry.addInterceptor(apiInterceptor)
+                .addPathPatterns("/auth/**")
+                .addPathPatterns("/shop/**")
+                .addPathPatterns("/upload/**")
+                .addPathPatterns("/user/update/password");
+//                .excludePathPatterns("/order/shareCode");
+    }
+}

+ 44 - 0
src/main/java/caimei/config/ApiInterceptor.java

@@ -0,0 +1,44 @@
+package caimei.config;
+
+import com.caimei.components.RedisService;
+import com.caimei.utils.JwtUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/18
+ */
+@Component
+public class ApiInterceptor implements HandlerInterceptor {
+
+    private RedisService redisService;
+
+    @Autowired
+    public void setRedisService(RedisService redisService) {
+        this.redisService = redisService;
+    }
+
+    @Value("${caimei.zplmapi}")
+    private String zplmapi;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        String token = request.getHeader("X-Token");
+        String cacheToken = null != token ? String.valueOf(redisService.get(token)) : null;
+        if (null == cacheToken || !JwtUtil.isVerify(cacheToken)) {
+            // Token失效
+            response.sendRedirect(zplmapi + "/unauthorized");
+            return false;
+        }
+        return true;
+    }
+
+}

+ 47 - 0
src/main/java/caimei/config/FastDfsClient.java

@@ -0,0 +1,47 @@
+package caimei.config;
+
+import com.github.tobato.fastdfs.domain.StorePath;
+import com.github.tobato.fastdfs.proto.storage.DownloadByteArray;
+import com.github.tobato.fastdfs.service.FastFileStorageClient;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+
+/**
+ * @author Aslee
+ * @date 2021/6/4
+ */
+@Component
+public class FastDfsClient {
+
+    @Autowired
+    private FastFileStorageClient storageClient;
+
+    // 文件上传
+    public String uploadFile(String path) throws FileNotFoundException {
+        File file = new File(path);
+        InputStream input = new FileInputStream(file);
+        long size = FileUtils.sizeOf(file);
+        String name = file.getName();
+        String fileName = name.substring(name.lastIndexOf("/") + 1);
+        StorePath storePath = storageClient.uploadFile(input, size, FilenameUtils.getExtension(fileName), null);
+        return storePath.getFullPath();
+    }
+
+    // 文件下载
+    public boolean downloadFile(String path, String downloadFilePath) throws IOException {
+        File file = new File(downloadFilePath);
+        FileOutputStream outputStream = null;
+        // fastdfs 文件读取
+        String filepath = path.substring(path.lastIndexOf("group1/") + 7);
+        DownloadByteArray callback = new DownloadByteArray();
+        byte[] content = storageClient.downloadFile("group1", filepath, callback);
+        // 数据写入指定文件夹中
+        outputStream = new FileOutputStream(file);
+        outputStream.write(content);
+        return true;
+    }
+}

+ 29 - 0
src/main/java/caimei/config/GlobalCorsConfig.java

@@ -0,0 +1,29 @@
+package caimei.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+
+@Configuration
+public class GlobalCorsConfig {
+
+    @Bean
+    public CorsFilter corsFilter() {
+        CorsConfiguration config = new CorsConfiguration();
+        config.addAllowedOrigin("*");// 1 设置访问源地址
+        config.setAllowCredentials(true);
+        config.addAllowedMethod("*");// 3 设置访问源请求方法
+        config.addAllowedHeader("*");// 2 设置访问源请求头
+        config.addExposedHeader("Content-Type");
+        config.addExposedHeader("X-Requested-With");
+        config.addExposedHeader("accept");
+        config.addExposedHeader("Origin");
+        config.addExposedHeader("Access-Control-Request-Method");
+        config.addExposedHeader("Access-Control-Request-Headers");
+        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
+        configSource.registerCorsConfiguration("/**", config);// 4 对接口配置跨域设置
+        return new CorsFilter(configSource);
+    }
+}

+ 96 - 0
src/main/java/caimei/config/GlobalTokenAspect.java

@@ -0,0 +1,96 @@
+package caimei.config;
+
+import com.caimei.components.RedisService;
+import com.caimei.utils.JwtUtil;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 把切面类加入到IOC容器中
+ * 所有请求都会更新redis存token的时间
+ *
+ * @author : Charles
+ * @date : 2020/3/17
+ */
+@Component
+@Aspect
+public class GlobalTokenAspect {
+
+    @Value("${caimei.oldapi}")
+    private String oldApi;
+
+    private RedisService redisService;
+    @Autowired
+    public void setRedisService(RedisService redisService) {
+        this.redisService = redisService;
+    }
+
+    /**
+     * 定义一个切入点 我这里是从controller切入
+     */
+    @Pointcut("execution(public * com.caimei.controller..*.*(..))")
+    public void pointCut() {
+    }
+
+    /**
+     * 前置通知
+     * 在进入方法前执行 可以对参数进行限制或者拦截
+     * 通常在这边做日志存储存到数据库中
+     * @param joinPoint
+     * @throws Throwable
+     */
+    @Before("pointCut()")
+    public void before(JoinPoint joinPoint) throws Throwable {
+        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
+        HttpServletRequest request = attributes.getRequest();
+        String token = request.getHeader("X-Token");
+        String cacheToken = null!=token ? String.valueOf(redisService.get(token)) : null;
+        // Redis过期后会得到"null"值,所以需判断字符串"null"
+        if (cacheToken != null && cacheToken.length() != 0 && !"null".equals(cacheToken)) {
+            if (JwtUtil.isVerify(cacheToken)) {
+               /* String mobileOrEmail = JwtUtil.parseTokenAud(cacheToken);*/
+                int userId = JwtUtil.parseTokenUid(cacheToken);
+                // 刷新token
+                tokenRefresh(token, userId);
+            }
+        }
+    }
+
+    /**
+     * JWT Token续签:
+     * 业务逻辑:登录成功后,用户在未过期时间内继续操作,续签token。
+     * 登录成功后,空闲超过过期时间,返回token已失效,重新登录。
+     * 实现逻辑:
+     * 1.登录成功后将token存储到redis里面(这时候k、v值一样都为token),并设置过期时间为token过期时间
+     * 2.当用户请求时token值还未过期,则重新设置redis里token的过期时间。
+     * 3.当用户请求时token值已过期,但redis中还在,则JWT重新生成token并覆盖v值(这时候k、v值不一样了),然后设置redis过期时间。
+     * 4.当用户请求时token值已过期,并且redis中也不存在,则用户空闲超时,返回token已失效,重新登录。
+     */
+    public boolean tokenRefresh(String token, Integer userID) {
+        String cacheToken = String.valueOf(redisService.get(token));
+        // 过期后会得到"null"值,所以需判断字符串"null"
+        if (cacheToken != null && cacheToken.length() != 0 && !"null".equals(cacheToken)) {
+            // 校验token有效性
+            if (!JwtUtil.isVerify(cacheToken)) {
+                // 生成token
+                String newToken = JwtUtil.createToken(userID);
+                // 将token存入redis,并设置超时时间
+                redisService.set(token, newToken, JwtUtil.getExpireTime());
+            } else {
+                // 重新设置超时时间
+                redisService.set(token, cacheToken, JwtUtil.getExpireTime());
+            }
+            return true;
+        }
+        return false;
+    }
+}

+ 53 - 0
src/main/java/caimei/config/SwaggerConfig.java

@@ -0,0 +1,53 @@
+package caimei.config;
+
+import com.github.xiaoymin.knife4j.spring.annotations.EnableKnife4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * `@EnableOpenApi`: 用于开启Swagger的自动配置
+ *
+ * @author Aslee
+ * @date 2021/6/4
+ */
+@Configuration
+@EnableSwagger2
+@EnableKnife4j
+public class SwaggerConfig {
+    @Value(value = "${swagger.enabled}")
+    Boolean swaggerEnabled;
+
+    @Bean
+    public Docket createRestApi(){
+        return new Docket(DocumentationType.SWAGGER_2)
+                .apiInfo(apiInfo())
+                // 是否开启swagger
+                .enable(swaggerEnabled)
+                .select()
+                // 扫描api
+                .apis(RequestHandlerSelectors.basePackage("com.caimei.controller"))
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    private ApiInfo apiInfo(){
+        return new ApiInfoBuilder().
+                // 标题
+                title("正品联盟后台API")
+                // 描述
+                .description("正品联盟后台API")
+                // 服务地址
+                .termsOfServiceUrl("/doc.html, /swagger-ui/index.html")
+                // 版本号
+                .version("1.0.0")
+                .build();
+    }
+}

+ 26 - 0
src/main/java/caimei/controller/OrderApi.java

@@ -0,0 +1,26 @@
+package caimei.controller;
+
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Aslee
+ */
+@Slf4j
+@RestController
+@RequestMapping("/order")
+public class OrderApi {
+
+    /**
+     * 下单
+     */
+
+
+    /**
+     * 订单查询
+     */
+
+
+}

+ 18 - 0
src/main/java/caimei/controller/ProductApi.java

@@ -0,0 +1,18 @@
+package caimei.controller;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * @author Aslee
+ */
+@Slf4j
+@RestController
+@RequestMapping("/product")
+public class ProductApi {
+
+    /**
+     * 商品列表
+     */
+}

+ 81 - 0
src/main/java/caimei/model/ResponseJson.java

@@ -0,0 +1,81 @@
+package caimei.model;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 全局API返回值
+ *
+ * @author : Charles
+ * @date : 2021/3/4
+ */
+@Data
+public class ResponseJson<T> implements Serializable {
+    /** 状态码 */
+    private int code;
+    /** 提示信息 */
+    private String msg;
+    /** 返回的数据 */
+    private T data;
+
+    private ResponseJson() {}
+
+    private ResponseJson(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+    private ResponseJson(int code, String msg, T data) {
+        this.code = code;
+        this.msg = msg;
+        this.data = data;
+    }
+
+    public static ResponseJson success() {
+        return new ResponseJson<>(0, "操作成功");
+    }
+
+    public static<T> ResponseJson<T> success(T data) {
+        return new ResponseJson<>(0, "操作成功", data);
+    }
+
+    public static<T> ResponseJson<T> success(String msg, T data) {
+        return new ResponseJson<>(0, msg, data);
+    }
+
+    public static<T> ResponseJson<T> success(int code, String msg, T data) {
+        return new ResponseJson<>(code, msg, data);
+    }
+
+    public static ResponseJson error() {
+        return new ResponseJson<>(-1, "操作失败");
+    }
+
+    public static ResponseJson error(String msg) {
+        return new ResponseJson<>(-1, msg);
+    }
+
+    public static ResponseJson error(int code, String msg) {
+        return new ResponseJson<>(code, msg);
+    }
+
+    public static<T> ResponseJson<T> error(T data) {
+        return new ResponseJson<>(-1, "操作失败", data);
+    }
+
+    public static<T> ResponseJson<T> error(String msg, T data) {
+        return new ResponseJson<>(-1, msg, data);
+    }
+
+    public static<T> ResponseJson<T> error(int code, String msg, T data) {
+        return new ResponseJson<>(code, msg, data);
+    }
+
+    @Override
+    public String toString() {
+        return "JsonModel{" + "code=" + code + ", msg='" + msg + '\'' + ", data=" + data + '}';
+    }
+
+    private static final long serialVersionUID = 1L;
+}

+ 119 - 0
src/main/java/caimei/utils/AliyunSmsUtil.java

@@ -0,0 +1,119 @@
+package caimei.utils;
+
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
+import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.profile.IClientProfile;
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 阿里云短信Sms
+ *
+ * @author : Charles
+ * @date : 2021/3/5
+ */
+@Slf4j
+public class AliyunSmsUtil {
+    /** 短信API产品名称(短信产品名固定,无需修改) */
+    private static final String PRODUCT = "Dysmsapi";
+    /** 短信API产品域名(接口地址固定,无需修改) */
+    private static final String DOMAIN = "dysmsapi.aliyuncs.com";
+    /** 开发者自己的AK(在阿里云访问控制台寻找) */
+    private static final String ACCESS_KEY_ID = "LTAI4GBL3o4YkWnbKYgf2Xia";
+    private static final String ACCESS_KEY_SECRET = "dBjAXqbYiEPP6Ukuk2ZsXQeET7FVkK";
+    /**
+    * 可登录阿里云查看和定义短信模板:https://dysms.console.aliyun.com/dysms.htm#/domestic/text/template
+    */
+    public static boolean sendSms(String mobile, Integer type, String templateParam) {
+        String templateCode = null;
+        String signName = "采美";
+        if (null == type || type<0) {
+            return false;
+        } else if (type == 0) {
+            // 模版内容: 验证码${code},您正在尝试变更重要信息,请妥善保管账户信息。
+            templateCode = "SMS_205240539";
+        } else if (type == 1) {
+            // 模版内容: 验证码${code},您正在尝试修改登录密码,请妥善保管账户信息。
+            templateCode = "SMS_205240540";
+        } else if (type == 2) {
+            // 模版内容: 验证码${code},您正在注册成为新用户,感谢您的支持!
+            templateCode = "SMS_205240541";
+        } else if (type == 3) {
+            // 模版内容: 验证码${code},您正尝试异地登录,若非本人操作,请勿泄露。
+            templateCode = "SMS_205240542";
+        } else if (type == 4) {
+            // 模版内容: 验证码${code},您正在登录,若非本人操作,请勿泄露。
+            templateCode = "SMS_205240543";
+        } else if (type == 5) {
+            // 模版内容: 验证码${code},您正在进行身份验证,打死不要告诉别人哦!
+            templateCode = "SMS_205240544";
+        } else if (type == 6) {
+            // 模版内容: 欢迎成为采美机构用户,您的登录账号为:${name},初始密码为:cm${content},您可使用该账号密码登录采美365网和“采美采购商城”小程序。
+            templateCode = "SMS_215122672";
+        } else if (type == 7) {
+            // 模版内容: 您"呵呵商城"小程序的验证码为:${code},验证码 5 分钟内有效。
+            templateCode = "SMS_215334982";
+            signName = "采美365";
+        } else if (type == 8) {
+            // 模版内容: 欢迎注册采美365网,您的短信验证码为:${code},该验证码 5 分钟内有效,请勿泄漏于他人。
+            templateCode = "SMS_205435882";
+        } else if (type == 9) {
+            // 模版内容: 欢迎注册采美365网供应商账号,您的短信验证码为:${code},该验证码 5 分钟内有效,请勿泄漏于他人。
+            templateCode = "SMS_205445750";
+        } else if (type == 10) {
+            // 模版内容: 注册成功!您可以通过手机号${name}登录。
+            templateCode = "SMS_205445760";
+        } else if (type == 11) {
+            // 模版内容: 欢迎成为${name}的运营人员,您的邀请码为${code}。您可使用以下两种方式激活您的身份:1. 您可在微信搜索“采美采购商城”小程序,使用邀请码登录并绑定微信;2. 进入“采美采购商城”小程序后,使用邀请码登录并绑定微信。绑定微信后,您可通过微信授权直接登录“采美采购商城”小程序或微信扫码直接登录采美365网站。
+            templateCode = "SMS_205445789";
+        } else if (type == 12) {
+            // 模版内容: 欢迎成为机构运营人员,您的验证码为${code}。运营人员可通过微信授权直接登录采美365网。
+            templateCode = "SMS_205435899";
+        } else if (type == 13) {
+            // 模版内容: 您正在更换联系人手机号,您的验证码为:${code}。
+            templateCode = "SMS_205435893";
+        } else if (type == 14) {
+            // 模版内容: 您正品联盟登录密码为:${password}。
+            templateCode = "SMS_217145278";
+        }
+        try {
+            //可自助调整超时时间
+            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
+            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
+
+            //初始化acsClient,暂不支持region化
+            IClientProfile profile = DefaultProfile.getProfile("cn-hangzhou", ACCESS_KEY_ID, ACCESS_KEY_SECRET);
+            DefaultProfile.addEndpoint("cn-hangzhou", "cn-hangzhou", PRODUCT, DOMAIN);
+            IAcsClient acsClient = new DefaultAcsClient(profile);
+
+            //组装请求对象
+            SendSmsRequest request = new SendSmsRequest();
+            //使用post提交
+            request.setMethod(MethodType.POST);
+            //必填:待发送手机号。支持以逗号分隔的形式进行批量调用,批量上限为1000个手机号码,批量调用相对于单条调用及时性稍有延迟,验证码类型的短信推荐使用单条调用的方式;发送国际/港澳台消息时,接收号码格式为国际区号+号码,如“85200000000”
+            request.setPhoneNumbers(mobile);
+            //必填:短信签名-可在短信控制台中找到
+            request.setSignName(signName);
+            //必填:短信模板-可在短信控制台中找到,发送国际/港澳台消息时,请使用国际/港澳台短信模版
+            request.setTemplateCode(templateCode);
+            //可选:模板中的变量替换JSON串,如模板内容为"亲爱的${name},您的验证码为${code}"时,此处的值为{\"name\":\"Tom\", \"code\":\"123\"}";
+            request.setTemplateParam(templateParam);
+            //请求失败这里会抛ClientException异常
+            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
+            log.info(">阿里云短信接口返回的数据: "
+                      +"Code="+ sendSmsResponse.getCode()
+                      +",Message=" + sendSmsResponse.getMessage()
+                      +",RequestId=" + sendSmsResponse.getRequestId()
+                      +",BizId=" + sendSmsResponse.getBizId());
+            //请求成功
+            return sendSmsResponse.getCode() != null && "OK".equals(sendSmsResponse.getCode());
+        } catch (ClientException e) {
+//            log.error(e.getErrCode(), e.getErrMsg(), e.getErrorDescription());
+            return false;
+        }
+    }
+}

+ 80 - 0
src/main/java/caimei/utils/Base64Util.java

@@ -0,0 +1,80 @@
+package caimei.utils;
+
+import org.springframework.web.multipart.MultipartFile;
+import sun.misc.BASE64Decoder;
+
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class Base64Util implements MultipartFile{
+    private final byte[] imgContent;
+    private final String header;
+
+    public Base64Util(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 System.currentTimeMillis() + (int) Math.random() * 10000 + "." + header.split("/")[1];
+    }
+
+    @Override
+    public String getContentType() {
+        return header.split(":")[1];
+    }
+
+    @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 ByteArrayInputStream getInputStream() throws IOException {
+        return new ByteArrayInputStream(imgContent);
+    }
+
+    @Override
+    public void transferTo(File dest) throws IOException, IllegalStateException {
+        new FileOutputStream(dest).write(imgContent);
+    }
+
+    public static MultipartFile base64ToMultipart(String base64) {
+        try {
+            String[] baseStrs = base64.split(",");
+
+            BASE64Decoder decoder = new BASE64Decoder();
+            byte[] b = new byte[0];
+            b = decoder.decodeBuffer(baseStrs[1]);
+
+            for (int i = 0; i < b.length; ++i) {
+                if (b[i] < 0) {
+                    b[i] += 256;
+                }
+            }
+            return new Base64Util(b, baseStrs[0]);
+        } catch (IOException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+}

+ 84 - 0
src/main/java/caimei/utils/CodeUtil.java

@@ -0,0 +1,84 @@
+package caimei.utils;
+
+import java.util.Random;
+
+public class CodeUtil {
+
+    private static char codeSequence[] = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
+            'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+            'W', 'X', 'Y', 'Z', '2', '3', '4', '5', '6', '7',
+            '8', '9'
+    };
+
+    private static char intSequence[] = {
+            '2', '3', '4', '5', '6', '7',
+            '8', '9'
+    };
+
+    private static char stringSequence[] = {
+            'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
+            'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
+            'W', 'X', 'Y', 'Z'
+    };
+
+    private static char newStringSequence[] = {
+            'A', 'a', 'B', 'b', 'D', 'd', 'E', 'e', 'F', 'f', 'G', 'g', 'H', 'h',
+            'L', 'N', 'n', 'Q', 'q', 'R', 'r', 'T', 't', 'Y', 'y'
+    };
+
+    public static String generateCode(int length) {
+        StringBuffer sb = new StringBuffer();
+        Random random = new Random();
+        for (int i = 0; i < codeSequence.length && i < length; ++i) {
+            sb.append(codeSequence[random.nextInt(codeSequence.length)]);
+        }
+        return sb.toString();
+    }
+
+    public static String generateCodeInt(int length) {
+        StringBuffer sb = new StringBuffer();
+        Random random = new Random();
+        for (int i = 0; i < intSequence.length && i < length; ++i) {
+            sb.append(intSequence[random.nextInt(intSequence.length)]);
+        }
+        return sb.toString();
+    }
+
+    public static String generateCodeString(int length) {
+        StringBuffer sb = new StringBuffer();
+        Random random = new Random();
+        for (int i = 0; i < stringSequence.length && i < length; ++i) {
+            sb.append(stringSequence[random.nextInt(stringSequence.length)]);
+        }
+        return sb.toString();
+    }
+
+
+    public static String getRandomCharAndNumr(int length) {
+        String val = "";
+        Random random = new Random();
+        for (int i = 0; i < length; i++) {
+            // 输出字母还是数字
+            String charOrNum = random.nextInt(2) % 2 == 0 ? "char" : "num";
+            // 字符串
+            if ("char".equalsIgnoreCase(charOrNum)) {
+                // 取得大写字母还是小写字母
+                int choice = random.nextInt(2) % 2 == 0 ? 65 : 97;
+                val += (char) (choice + random.nextInt(26));
+            } else if ("num".equalsIgnoreCase(charOrNum)) {
+                val += String.valueOf(random.nextInt(10));
+            }
+        }
+        return val;
+    }
+
+    public static String generateAccount(int length) {
+        StringBuffer sb = new StringBuffer();
+        Random random = new Random();
+        for (int i = 0; i < newStringSequence.length && i < length; ++i) {
+            sb.append(newStringSequence[random.nextInt(newStringSequence.length)]);
+        }
+        return sb.toString();
+    }
+}

+ 196 - 0
src/main/java/caimei/utils/ImageUtils.java

@@ -0,0 +1,196 @@
+package caimei.utils;
+
+import org.springframework.util.StringUtils;
+import sun.misc.BASE64Encoder;
+
+import javax.imageio.ImageIO;
+import javax.swing.*;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayOutputStream;
+import java.net.URL;
+
+/**
+ * Description
+ *
+ * @author : Charles
+ * @date : 2020/3/16
+ */
+public class ImageUtils {
+
+	public static String getImageURL(String dirName, String src, String domain) {
+		return getImageURL(dirName, src, 0,domain);
+	}
+
+	/***
+	 * 获取图片地址
+	 *
+	 * @param src
+	 *            保存在数据库中的图片文件名
+	 * @param type
+	 *            图片的前缀 (如 type = 200 那么则获取的图片是 200_XXX的图片)
+	 * @param dirName
+	 *            图片保存的文件夹名 如 (league)
+	 * @param domain
+	 * 			   加上域名拼成完整路径
+	 * @return
+	 */
+	public static String getImageURL(String dirName, String src, int type, String domain) {
+
+
+		//正式环境 域名 http --- https处理
+		if (domain != null && !"".equals(domain) && domain.startsWith("http:") && domain.toLowerCase().lastIndexOf("config/beta")== -1 && domain.toLowerCase().lastIndexOf("localhost")== -1) {
+			domain = domain.replace("http:", "https:");
+		}
+
+		//正式环境 图片地址 http --- https处理
+		if(src != null && src.startsWith("https:")){
+			//非正式环境 使用http
+			if (domain !=null && !"".equals(domain) && domain.toLowerCase().lastIndexOf("config/beta")>-1 || domain.toLowerCase().lastIndexOf("localhost")>-1){
+				src = src.replace("https:","http:");
+			}
+			return src;
+		}
+
+		//正式环境 图片地址  http --- https处理
+		if(src != null && src.startsWith("http:")){
+			//非正式环境 使用http
+			if (domain !=null && !"".equals(domain) && domain.toLowerCase().lastIndexOf("config/beta")==-1 && domain.toLowerCase().lastIndexOf("localhost")==-1){
+				src = src.replace("http:","https:");
+			}
+			return src;
+		}
+		type = 0 ;
+		dirName = dirName.trim();
+		if (dirName == null) {dirName = "";}
+		if(src == null || src.equalsIgnoreCase("null")) {src = "";}
+		if (src.indexOf(",") > 0) {
+			String tmp = src;
+			src = tmp.substring(0, tmp.indexOf(","));
+		}
+		String image = "/img/default/none.jpg";
+		if (dirName.equals("user")) {
+			image = "/img/default/HeaderImg.png";
+		} else if (dirName.equals("club")) {
+			image = "/img/default/default_club.jpg";
+		} else if (dirName.equals("shopLogo")) {
+			image = "/img/default/suppliver.jpg";
+		}else if (dirName.equals("caiMeiImage")) {
+			image = "/img/default/caiMeiImage.jpg";
+		}else {
+			image = "/img/default/none.jpg";
+		}
+		if (src != null && !src.equals("")) {
+			if (type != 0 || dirName.equals("product")) {
+				src = src.replace("\\", "/");
+				String srcActual = src;
+				String subDirName = "";
+				int index = src.lastIndexOf("/");
+
+				if (index != -1) {
+					subDirName = src.substring(0, index + 1);
+					srcActual = src.substring(index + 1);
+				}
+				boolean b = src.startsWith("/uploadFile");
+				if(b){
+					image = src;
+				}else{
+					image = "/uploadFile/" + dirName + "/" + subDirName
+							+ (type == 0 ? "" : type + "_") + srcActual;
+				}
+			} else {
+				boolean b = src.startsWith("/uploadFile");
+				if(b){
+					image = src;
+				}else{
+					image = "/uploadFile/" + dirName + "/" + src;
+				}
+			}
+		}else {
+			if(StringUtils.isEmpty(image)) {
+				image = "/img/default/none.jpg";
+			}
+		}
+		return domain + image;
+	}
+
+	public static String getProductImageURL(String image, int type, String domain) {
+		if (image == null) {
+			return getImageURL("product", "", type, domain);
+		}
+		return getImageURL("product", image, type, domain);
+	}
+
+	/**
+	 * 添加水印图片
+	 * @param waterMarkImg	水印图片
+	 * @param srcImgURL		原图片路径
+	 * @param degree		旋转角度
+	 * @return
+	 */
+	public static String markImageByIcon(Image waterMarkImg, String srcImgURL, Integer degree) {
+		//io流
+		ByteArrayOutputStream baos = new ByteArrayOutputStream();
+		try {
+			//原图片
+			ImageIcon imageIcon = new ImageIcon(new URL(srcImgURL));
+			Image srcImg = imageIcon.getImage();
+			BufferedImage buffImg = ImageIO.read(new URL(srcImgURL));
+
+			// 1、得到画笔对象
+			Graphics2D g = buffImg.createGraphics();
+
+			// 2、设置对线段的锯齿状边缘处理
+			g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+					RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+
+			g.drawImage(
+					srcImg.getScaledInstance(srcImg.getWidth(null),
+							srcImg.getHeight(null), Image.SCALE_SMOOTH), 0, 0,
+					null);
+			// 3、设置水印旋转
+			if (null != degree) {
+				g.rotate(Math.toRadians(degree),
+						(double) buffImg.getWidth() / 2,
+						(double) buffImg.getHeight() / 2);
+			}
+
+
+			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP,
+					1f));
+
+			// 6、水印图片的位置
+			int srcWidth = srcImg.getWidth(null);
+			int srcHeight = srcImg.getHeight(null);
+			int waterMarkWidth = waterMarkImg.getWidth(null);
+			int waterMarkHeight = waterMarkImg.getHeight(null);
+			g.drawImage(waterMarkImg, (srcWidth - waterMarkWidth) / 2, srcHeight - waterMarkHeight, null);
+			g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER));
+			// 7、释放资源
+			g.dispose();
+
+			//将图片写入流中
+			ImageIO.write(buffImg, "png", baos);
+			//转换成字节
+			byte[] bytes = baos.toByteArray();
+			BASE64Encoder encoder = new BASE64Encoder();
+			//转换成base64串
+			String addImage = encoder.encodeBuffer(bytes).trim();
+			//删除 \r\n
+			addImage = addImage.replaceAll("\n", "").replaceAll("\r", "");
+			return "data:image/jpg;base64," + addImage;
+
+		} catch (Exception e) {
+			e.printStackTrace();
+		} finally {
+			try {
+				if (null != baos) {
+					baos.close();
+				}
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+		}
+		return null;
+	}
+}

+ 113 - 0
src/main/java/caimei/utils/JwtUtil.java

@@ -0,0 +1,113 @@
+package caimei.utils;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import com.auth0.jwt.interfaces.JWTVerifier;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * JWT工具类
+ *
+ * 标准中注册的声明
+ * iss: jwt签发者
+ * sub: jwt所面向的用户
+ * aud: 接收jwt的一方
+ * exp: jwt的过期时间,这个过期时间必须要大于签发时间
+ * nbf: 定义在什么时间之前,该jwt都是不可用的.
+ * iat: jwt的签发时间
+ * jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
+ *
+ *
+ * @author : Charles
+ * @date : 2021/3/8
+ */
+public class JwtUtil {
+    /**
+     * 设置过期时间: 2*60分钟
+     */
+    private static final long EXPIRE_TIME = 2 * 60 * 60 * 1000;
+    /**
+     * 服务端的私钥secret,在任何场景都不应该流露出去
+     */
+    private static final String TOKEN_SECRET = "zhengchao";
+
+    /**
+     * 生成签名,6EXPIRE_TIME过期
+     */
+    public static String createToken(Integer userId) {
+        try {
+            // 设置过期时间
+            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
+            // 私钥和加密算法
+            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
+            // 设置头部信息
+            Map<String, Object> header = new HashMap<>(2);
+            header.put("typ", "JWT");
+            header.put("alg", "HS256");
+            // 返回token字符串
+            return JWT.create()
+                    .withHeader(header)
+                    .withClaim("uid", userId)
+                    /*.withClaim("aud", mobile)*/
+                    .withExpiresAt(date)
+                    .sign(algorithm);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 检验token是否正确
+     */
+    public static boolean isVerify(String token) {
+        try {
+            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
+            JWTVerifier verifier = JWT.require(algorithm).build();
+            verifier.verify(token);
+            return true;
+        } catch (Exception e) {
+            return false;
+        }
+    }
+
+    /**
+     * 从token解析出uid信息,用户ID
+     */
+    public static int parseTokenUid(String token) {
+        DecodedJWT jwt = JWT.decode(token);
+        return jwt.getClaim("uid").asInt();
+    }
+
+    /**
+     * 从token解析出过期日期时间
+     */
+    public static Date paraseExpiresAt(String token) {
+        DecodedJWT jwt = JWT.decode(token);
+        return jwt.getExpiresAt();
+    }
+
+    /**
+     * 返回设置的过期秒数
+     *
+     * @return long 秒数
+     */
+    public static long getExpireTime() {
+        return EXPIRE_TIME / 1000;
+    }
+
+    /**
+     * 从token解析出aud信息,用户名
+     *
+     * @param token
+     * @return
+     */
+    /*public static String parseTokenAud(String token) {
+        DecodedJWT jwt = JWT.decode(token);
+        return jwt.getClaim("aud").asString();
+    }*/
+}

+ 62 - 0
src/main/java/caimei/utils/Md5Util.java

@@ -0,0 +1,62 @@
+package caimei.utils;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import java.util.UUID;
+
+/**
+ * md5加密工具类
+ *
+ * @author : Charles
+ * @date : 2021/3/3
+ */
+public class Md5Util {
+
+    private static final String HEX_DIGITS = "0123456789ABCDEF";
+
+    /**
+	 * md5加密
+	 * @param s:待加密字符串
+	 * @return 加密后16进制字符串
+	 */
+	public static String md5(String s) {
+	    try {
+	    	//实例化MessageDigest的MD5算法对象
+	        MessageDigest md = MessageDigest.getInstance("MD5");
+	        //通过digest方法返回哈希计算后的字节数组
+	        byte[] bytes = md.digest(s.getBytes(StandardCharsets.UTF_8));
+	        //将字节数组转换为16进制字符串并返回
+	        return toHex(bytes);
+	    }
+	    catch (Exception e) {
+	        throw new RuntimeException(e);
+	    }
+	}
+
+	/**
+	 * 获取随即盐
+	 * @return salt
+	 */
+	public static String salt(){
+		//利用UUID生成随机盐
+		UUID uuid = UUID.randomUUID();
+		//返回a2c64597-232f-4782-ab2d-9dfeb9d76932
+		String[] arr = uuid.toString().split("-");
+		return arr[0];
+	}
+
+	/**
+	 * 字节数组转换为16进制字符串
+	 * @param bytes byte数组
+	 * @return 16进制字符串
+	 */
+	private static String toHex(byte[] bytes) {
+	    final char[] hexDigits = HEX_DIGITS.toCharArray();
+	    StringBuilder ret = new StringBuilder(bytes.length * 2);
+        for (byte aByte : bytes) {
+            ret.append(hexDigits[(aByte >> 4) & 0x0f]);
+            ret.append(hexDigits[aByte & 0x0f]);
+        }
+	    return ret.toString();
+	}
+}

+ 201 - 0
src/main/java/caimei/utils/OSSUtils.java

@@ -0,0 +1,201 @@
+package caimei.utils;
+
+import com.aliyun.oss.OSS;
+import com.aliyun.oss.OSSClientBuilder;
+import com.aliyun.oss.model.GetObjectRequest;
+import com.aliyun.oss.model.ObjectMetadata;
+import com.aliyun.oss.model.UploadFileRequest;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.UUID;
+
+@Component
+public class OSSUtils {
+    private static String endpoint;
+
+    @Value("${aliyunConfig.endpoint}")
+    public void setEndpoint(String endpoints) {
+        endpoint = endpoints;
+    }
+
+    private static String accessKeyId;
+
+    @Value("${aliyunConfig.accessKeyId}")
+    public void setAccessKeyId(String accessKeyIds) {
+        accessKeyId = accessKeyIds;
+    }
+
+    private static String accessKeySecret;
+
+    @Value("${aliyunConfig.accessKeySecret}")
+    public void setAccessKeySecret(String accessKeySecrets) {
+        accessKeySecret = accessKeySecrets;
+    }
+
+    private static String privateBucket;
+
+    @Value("${aliyunConfig.bucketName}")
+    public void setPrivateBucket(String bucketName) {
+        privateBucket = bucketName;
+    }
+
+    private static String active;
+
+    @Value("${spring.profiles.active}")
+    public void setActive(String actives) {
+        active = actives;
+    }
+
+    public static String ossUpload(String fileName, File file, String contentType) {
+        String url = null;
+        try {
+            OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+            ObjectMetadata meta = new ObjectMetadata();
+            meta.setContentType(contentType);
+            fileName = active + "/authFile/" + fileName;
+            UploadFileRequest uploadFileRequest = new UploadFileRequest(privateBucket, fileName);
+            // 指定上传的本地文件。
+            uploadFileRequest.setUploadFile(file.toString());
+            // 指定上传并发线程数,默认为1。
+            uploadFileRequest.setTaskNum(10);
+            // 指定上传的分片大小,范围为100KB~5GB,默认为文件大小/10000。
+            uploadFileRequest.setPartSize(1024 * 1024);
+            // 开启断点续传,默认关闭。
+            uploadFileRequest.setEnableCheckpoint(true);
+            uploadFileRequest.setCheckpointFile(file.getAbsolutePath() + "uploadFile.ucp");
+            // 文件的元数据。
+            uploadFileRequest.setObjectMetadata(meta);
+            // 设置上传成功回调,参数为Callback类型。
+            //uploadFileRequest.setCallback("<yourCallbackEvent>");
+            // 断点续传上传。
+            ossClient.uploadFile(uploadFileRequest);
+            Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000);
+            url = ossClient.generatePresignedUrl(privateBucket, fileName, expiration).toString();
+            // 关闭OSSClient。
+            ossClient.shutdown();
+        } catch (Throwable e) {
+            e.printStackTrace();
+        }
+        return url;
+    }
+
+
+    /**
+     * 通过文件名判断并获取OSS服务文件上传时文件的contentType
+     */
+    public static String getContentType(String fileName) {
+        String fileExtension = fileName.substring(fileName.lastIndexOf("."));
+        if (".bmp".equalsIgnoreCase(fileExtension)) {
+            return "image/bmp";
+        }
+        if (".gif".equalsIgnoreCase(fileExtension)) {
+            return "image/gif";
+        }
+        if (".jpeg".equalsIgnoreCase(fileExtension)) {
+            return "image/jpeg";
+        }
+        if (".jpg".equalsIgnoreCase(fileExtension)) {
+            return "image/jpg";
+        }
+        if (".png".equalsIgnoreCase(fileExtension)) {
+            return "image/png";
+        }
+        if (".html".equalsIgnoreCase(fileExtension)) {
+            return "text/html";
+        }
+        if (".txt".equalsIgnoreCase(fileExtension)) {
+            return "text/plain";
+        }
+        if (".vsd".equalsIgnoreCase(fileExtension)) {
+            return "application/vnd.visio";
+        }
+        if (".ppt".equalsIgnoreCase(fileExtension) || "pptx".equalsIgnoreCase(fileExtension)) {
+            return "application/vnd.ms-powerpoint";
+        }
+        if (".doc".equalsIgnoreCase(fileExtension) || "docx".equalsIgnoreCase(fileExtension)) {
+            return "application/msword";
+        }
+        if (".xml".equalsIgnoreCase(fileExtension)) {
+            return "text/xml";
+        }
+        if (".mp4".equalsIgnoreCase(fileExtension)) {
+            return "video/mp4";
+        }
+        if (".mp3".equalsIgnoreCase(fileExtension)) {
+            return "audio/mp3";
+        }
+        if (".pdf".equalsIgnoreCase(fileExtension)) {
+            return "application/pdf";
+        }
+        return "text/html";
+    }
+
+    public static void deleteFile(File... files) {
+        for (File file : files) {
+            //logger.info("File:[{}]",file.getAbsolutePath());
+            if (file.exists()) {
+                file.delete();
+            }
+        }
+    }
+
+    public static File ossUpload(MultipartFile file) throws IOException {
+        // 获取文件名
+        String fileName = file.getOriginalFilename();
+        // 获取文件后缀
+        String prefix = fileName.substring(fileName.lastIndexOf("."));
+        // 用uuid作为文件名,防止生成的临时文件重复
+        File excelFile = File.createTempFile(UUID.randomUUID().toString(), prefix);
+        // MultipartFile to File
+        file.transferTo(excelFile);
+        //程序结束时,删除临时文件
+        return excelFile;
+    }
+
+    /**
+     * 授权生成签名URL临时访问
+     *
+     * @param fileName 文件名称
+     */
+    public static String getOssUrl(String fileName) {
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        // 设置URL过期时间为1个小时
+        Date expiration = new Date(System.currentTimeMillis() + 3600L * 1000);
+        String url = ossClient.generatePresignedUrl(privateBucket, fileName, expiration).toString();
+        // 关闭OSSClient。
+        ossClient.shutdown();
+        return url;
+    }
+
+    /**
+     * oss单个文件删除
+     *
+     * @param fileName 文件名称或文件夹名称
+     */
+    public static void deleteSingleFile(String fileName) {
+        // 创建OSSClient实例。
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        // 删除文件。如需删除文件夹,请将ObjectName设置为对应的文件夹名称。
+        // 如果文件夹非空,则需要将文件夹下的所有object删除后才能删除该文件夹。
+        ossClient.deleteObject(privateBucket, active + "/authFile/" + fileName);
+        // 关闭OSSClient。
+        ossClient.shutdown();
+    }
+
+    /**
+     * oss单个文件下载
+     */
+    public static void downFile(String ossName, String fileName) {
+        // 创建OSSClient实例。
+        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
+        // 下载OSS文件到本地文件。如果指定的本地文件存在会覆盖,不存在则新建。
+        ossClient.getObject(new GetObjectRequest(privateBucket, ossName), new File("./" + fileName));
+        // 关闭OSSClient。
+        ossClient.shutdown();
+    }
+}

+ 26 - 0
src/main/resources/application.yml

@@ -0,0 +1,26 @@
+server:
+  port: 8012
+spring:
+  application:
+    # 指定服务名
+    name: caimei-zplm-admin
+  profiles:
+    active: @activatedProperties@
+
+#整合mybatis
+mybatis:
+  #加载Mybatis映射文件
+  mapper-locations:
+    - classpath:mapper/*.xml
+
+#阿里云配置
+aliyunConfig:
+  endpoint: https://oss-cn-shenzhen.aliyuncs.com
+  accessKeyId: LTAI4GBL3o4YkWnbKYgf2Xia
+  accessKeySecret: dBjAXqbYiEPP6Ukuk2ZsXQeET7FVkK
+  bucketName: caimei-oss
+
+
+
+
+

+ 14 - 0
src/main/resources/backup.sql

@@ -0,0 +1,14 @@
+CREATE TABLE `cm_api_organize` (
+                                        `id` INT NOT NULL,
+                                        `userId` INT NULL COMMENT '用户id',
+                                        `cmAccount` VARCHAR(45) NULL COMMENT '采美标识,(\'caimei\'+userId)的md5加密',
+                                        `privateKey` TEXT NULL COMMENT '组织私钥',
+                                        `publicKey` TEXT NULL COMMENT '公钥',
+                                        `notifyUrl` TEXT NULL COMMENT '支付完成回调接口',
+                                        PRIMARY KEY (`id`))
+    ENGINE = InnoDB
+    DEFAULT CHARACTER SET = utf8
+    COLLATE = utf8_bin
+    COMMENT = '采美接口对接组织表';
+
+

+ 74 - 0
src/main/resources/config/beta/application-beta.yml

@@ -0,0 +1,74 @@
+spring:
+  #数据源连接--start
+  datasource:
+    url: jdbc:mysql://172.31.165.28:3306/caimei?characterEncoding=UTF8&serverTimezone=Asia/Shanghai
+    username: developer
+    password: J5p3tgOVazNl4ydf
+    # Hikari will use the above plus the following to setup connection pooling
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 5
+      maximum-pool-size: 15
+      auto-commit: true
+      idle-timeout: 30000
+      pool-name: DatebookHikariCP
+      max-lifetime: 1800000
+      connection-timeout: 30000
+      connection-test-query: SELECT 1
+  #数据源连接--end
+
+  redis:
+    host: 47.119.112.46
+    port: 6379
+    password: 6#xsI%b4o@5c3RoE
+#    host: 47.119.112.46
+#    port: 6379
+#    password: 6#xsI%b4o@5c3RoE
+    #Redis数据库索引(默认为0)
+    database: 0
+    #连接池最大连接数(使用负值表示没有限制)
+    jedis:
+      pool:
+        max-active: 50
+        #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: 3000
+        #连接池中的最大空闲连接
+        max-idle: 20
+        #连接池中的最小空闲连接
+        min-idle: 2
+    #连接超时时间(毫秒)
+    timeout: 5000
+
+#上传文件大小
+  servlet:
+    multipart:
+      max-file-size: 10MB
+      max-request-size: 100MB
+
+#日志配置
+logging:
+  file:
+    path: /mnt/newdatadrive/data/runtime/jar-instance/zplma/logs
+  level:
+    root: info
+
+# swagger文档显示配置
+swagger:
+  enabled: false
+
+# 新旧www服务域名
+caimei:
+  oldapi: https://www-b.caimei365.com
+  zplmapi: https://zplma-b.caimei365.com
+  #图片服务器
+  imageDomain: https://img-b.caimei365.com
+
+#DFS配置
+fdfs:
+  so-timeout: 5000 #上传的超时时间
+  connect-timeout: 2000 #连接超时时间
+  thumb-image:             #缩略图生成参数
+    width: 150
+    height: 150
+  tracker-list:            #TrackerList参数,支持多个
+    - 172.31.165.28:22122

+ 81 - 0
src/main/resources/config/dev/application-dev.yml

@@ -0,0 +1,81 @@
+spring:
+  #数据源连接--start
+  datasource:
+    #driverClassName: com.mysql.jdbc.Driver
+    url: jdbc:mysql://192.168.2.100:3306/caimei?characterEncoding=UTF8&serverTimezone=Asia/Shanghai
+    username: developer
+    password: 05bZ/OxTB:X+yd%1
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 5
+      maximum-pool-size: 15
+      auto-commit: true
+      idle-timeout: 30000
+      pool-name: DatebookHikariCP
+      max-lifetime: 1800000
+      connection-timeout: 30000
+      connection-test-query: SELECT 1
+  #数据源连接--end
+
+  redis:
+    host: 119.29.0.46
+    port: 6380
+    password: 6#xsI%b4o@5c3RoE
+    #Redis数据库索引(默认为0)
+    database: 0
+    #连接池最大连接数(使用负值表示没有限制)
+    jedis:
+      pool:
+        max-active: 50
+        #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: -1
+        #连接池中的最大空闲连接
+        max-idle: 20
+        #连接池中的最小空闲连接
+        min-idle: 2
+    #连接超时时间(毫秒)
+    timeout: 5000
+
+  #上传文件大小
+  servlet:
+    multipart:
+      max-file-size: 10MB
+      max-request-size: 100MB
+
+#日志配置
+logging:
+  level:
+    root: info
+    com.caimei.mapper: debug
+    com.caimei.module.product.dao: debug
+
+# swagger文档显示配置
+swagger:
+  enabled: true
+
+# 新旧www服务域名
+caimei:
+  oldapi: http://localhost:8100
+  zplmapi: http://localhost:8012
+  #图片服务器
+  imageDomain: https://img-b.caimei365.com
+
+#DFS配置
+fdfs:
+  so-timeout: 5000 #上传的超时时间
+  connect-timeout: 2000 #连接超时时间
+  thumb-image:             #缩略图生成参数
+    width: 150
+    height: 150
+  tracker-list:            #TrackerList参数,支持多个
+    - 192.168.2.100:22122
+
+#消息队列
+rabbitmq:
+  host: 192.168.2.100
+  port: 5672
+  username: cmuser
+  password: 6#xsI%b4o@5c3RoE
+  virtual-host: /
+  connection-timeout: 3000
+

+ 71 - 0
src/main/resources/config/prod/application-prod.yml

@@ -0,0 +1,71 @@
+spring:
+  #数据源连接--start
+  datasource:
+    url: jdbc:mysql://rm-wz928s8btl7kxil44.mysql.rds.aliyuncs.com:3306/caimei?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true
+    username: coder
+    password: diKtPYZ%wToI&9#L
+    # Hikari will use the above plus the following to setup connection pooling
+    type: com.zaxxer.hikari.HikariDataSource
+    hikari:
+      minimum-idle: 5
+      maximum-pool-size: 15
+      auto-commit: true
+      idle-timeout: 30000
+      pool-name: DatebookHikariCP
+      max-lifetime: 1800000
+      connection-timeout: 30000
+      connection-test-query: SELECT 1
+  #数据源连接--end
+
+  redis:
+    host: 172.31.165.23
+    port: 6379
+    #password: 6#xsI%b4o@5c3RoE
+    #Redis数据库索引(默认为0)
+    database: 0
+    #连接池最大连接数(使用负值表示没有限制)
+    jedis:
+      pool:
+        max-active: 50
+        #连接池最大阻塞等待时间(使用负值表示没有限制)
+        max-wait: 3000
+        #连接池中的最大空闲连接
+        max-idle: 20
+        #连接池中的最小空闲连接
+        min-idle: 2
+    #连接超时时间(毫秒)
+    timeout: 5000
+
+  #上传文件大小
+  servlet:
+    multipart:
+      max-file-size: 10MB
+      max-request-size: 100MB
+
+#日志配置
+logging:
+  file:
+    path: /mnt/newdatadrive/data/runtime/jar-instance/zplma/logs
+  level:
+    root: info
+
+# swagger文档显示配置
+swagger:
+  enabled: false
+
+# 新旧www服务域名
+caimei:
+  oldapi: https://www.caimei365.com
+  zplmapi: https://zplma.caimei365.com
+  #图片服务器
+  imageDomain: https://img.caimei365.com
+
+#DFS配置
+fdfs:
+  so-timeout: 5000 #上传的超时时间
+  connect-timeout: 2000 #连接超时时间
+  thumb-image:             #缩略图生成参数
+    width: 150
+    height: 150
+  tracker-list:            #TrackerList参数,支持多个
+    - 172.31.165.24:22122

+ 29 - 0
src/test/java/caimei/PurchaseApplicationTests.java

@@ -0,0 +1,29 @@
+package com.caimei;
+
+
+import com.aliyun.oss.internal.OSSUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.junit.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.UUID;
+
+@SpringBootTest
+public class PurchaseApplicationTests {
+
+
+    @Test
+    public void JWTToken(){
+    }
+
+
+}