Aslee пре 4 година
родитељ
комит
595c0c85df
43 измењених фајлова са 3273 додато и 4 уклоњено
  1. 56 4
      pom.xml
  2. 40 0
      src/main/java/com/caimei/AdminApplication.java
  3. 294 0
      src/main/java/com/caimei/components/RedisService.java
  4. 48 0
      src/main/java/com/caimei/config/FastDfsClient.java
  5. 29 0
      src/main/java/com/caimei/config/GlobalCorsConfig.java
  6. 53 0
      src/main/java/com/caimei/config/SwaggerConfig.java
  7. 88 0
      src/main/java/com/caimei/controller/AuthApi.java
  8. 148 0
      src/main/java/com/caimei/controller/ShopApi.java
  9. 70 0
      src/main/java/com/caimei/controller/UploadApi.java
  10. 57 0
      src/main/java/com/caimei/controller/UserApi.java
  11. 28 0
      src/main/java/com/caimei/mapper/AuthMapper.java
  12. 48 0
      src/main/java/com/caimei/mapper/ShopMapper.java
  13. 23 0
      src/main/java/com/caimei/mapper/UserMapper.java
  14. 81 0
      src/main/java/com/caimei/model/ResponseJson.java
  15. 34 0
      src/main/java/com/caimei/model/dto/PasswordDto.java
  16. 122 0
      src/main/java/com/caimei/model/dto/ShopSaveDto.java
  17. 40 0
      src/main/java/com/caimei/model/po/CmBrandAuthFilePo.java
  18. 40 0
      src/main/java/com/caimei/model/po/CmBrandAuthPo.java
  19. 54 0
      src/main/java/com/caimei/model/po/ShopInfoPo.java
  20. 54 0
      src/main/java/com/caimei/model/po/UserPo.java
  21. 47 0
      src/main/java/com/caimei/model/vo/AuthVo.java
  22. 73 0
      src/main/java/com/caimei/model/vo/ShopVo.java
  23. 50 0
      src/main/java/com/caimei/model/vo/UserLoginVo.java
  24. 51 0
      src/main/java/com/caimei/service/AuthService.java
  25. 76 0
      src/main/java/com/caimei/service/ShopService.java
  26. 35 0
      src/main/java/com/caimei/service/UserService.java
  27. 109 0
      src/main/java/com/caimei/service/impl/AuthServiceImpl.java
  28. 239 0
      src/main/java/com/caimei/service/impl/ShopServiceImpl.java
  29. 138 0
      src/main/java/com/caimei/service/impl/UserServiceImpl.java
  30. 116 0
      src/main/java/com/caimei/utils/AliyunSmsUtil.java
  31. 84 0
      src/main/java/com/caimei/utils/CodeUtil.java
  32. 113 0
      src/main/java/com/caimei/utils/JwtUtil.java
  33. 62 0
      src/main/java/com/caimei/utils/Md5Util.java
  34. 172 0
      src/main/java/com/caimei/utils/OSSUtils.java
  35. 19 0
      src/main/resources/application.yml
  36. 44 0
      src/main/resources/backup.sql
  37. 74 0
      src/main/resources/config/beta/application-beta.yml
  38. 79 0
      src/main/resources/config/dev/application-dev.yml
  39. 72 0
      src/main/resources/config/prod/application-prod.yml
  40. 28 0
      src/main/resources/mapper/AuthMapper.xml
  41. 142 0
      src/main/resources/mapper/ShopMapper.xml
  42. 27 0
      src/main/resources/mapper/UserMapper.xml
  43. 16 0
      src/test/java/com/caimei/AdminApplicationTests.java

+ 56 - 4
pom.xml

@@ -24,14 +24,22 @@
 
 
     <dependencies>
+        <!--
+        添加此依赖会导致跨域问题,用org.apache.tomcat.embed代替
+        -->
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-thymeleaf</artifactId>
+            <artifactId>spring-boot-starter-web</artifactId>
         </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-webflux</artifactId>
+            <artifactId>spring-boot-starter-thymeleaf</artifactId>
         </dependency>
+        <!--<dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-webflux</artifactId>
+        </dependency>-->
         <dependency>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
@@ -42,6 +50,11 @@
             <artifactId>mybatis-spring-boot-starter</artifactId>
             <version>2.1.1</version>
         </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-starter-cache</artifactId>
@@ -64,7 +77,7 @@
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-devtools</artifactId>
-            <scope>runtime</scope>
+            <scope>provided</scope>
             <optional>true</optional>
         </dependency>
         <dependency>
@@ -98,7 +111,13 @@
         <dependency>
             <groupId>com.github.pagehelper</groupId>
             <artifactId>pagehelper-spring-boot-starter</artifactId>
-            <version>1.2.13</version>
+            <version>1.2.5</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>mybatis-spring-boot-starter</artifactId>
+                    <groupId>org.mybatis.spring.boot</groupId>
+                </exclusion>
+            </exclusions>
         </dependency>
 
         <dependency>
@@ -126,6 +145,39 @@
             <artifactId>httpclient</artifactId>
             <version>4.5.7</version>
         </dependency>
+
+        <!-- jwt -->
+        <dependency>
+            <groupId>com.auth0</groupId>
+            <artifactId>java-jwt</artifactId>
+            <version>3.14.0</version>
+        </dependency>
+
+        <!-- 阿里云短信sdk -->
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+            <version>4.5.18</version>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-dysmsapi</artifactId>
+            <version>2.1.0</version>
+        </dependency>
+
+        <!--对象存储oss-->
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>3.10.2</version>
+        </dependency>
+
+        <!--dfs-->
+        <dependency>
+            <groupId>com.github.tobato</groupId>
+            <artifactId>fastdfs-client</artifactId>
+            <version>1.26.1-RELEASE</version>
+        </dependency>
     </dependencies>
 
     <profiles>

+ 40 - 0
src/main/java/com/caimei/AdminApplication.java

@@ -0,0 +1,40 @@
+package com.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/5/11
+ */
+@Import(FdfsClientConfig.class)
+// 解决jmx重复注册bean的问题
+@EnableMBeanExport(registration = RegistrationPolicy.IGNORE_EXISTING)
+@SpringBootApplication
+public class AdminApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(AdminApplication.class, args);
+    }
+
+    /**
+     * 文件上传临时路径
+     */
+    @Bean
+    MultipartConfigElement multipartConfigElement() {
+        MultipartConfigFactory factory = new MultipartConfigFactory();
+        factory.setLocation("/mnt/newdatadrive/data/runtime/jar-instance/mall-admin/tempImage");
+        return factory.createMultipartConfig();
+    }
+}

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

@@ -0,0 +1,294 @@
+package com.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);
+	}
+
+}

+ 48 - 0
src/main/java/com/caimei/config/FastDfsClient.java

@@ -0,0 +1,48 @@
+package com.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 lombok.RequiredArgsConstructor;
+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/5/14
+ */
+@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/com/caimei/config/GlobalCorsConfig.java

@@ -0,0 +1,29 @@
+package com.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);
+    }
+}

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

@@ -0,0 +1,53 @@
+package com.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/3/10
+ */
+@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();
+    }
+}

+ 88 - 0
src/main/java/com/caimei/controller/AuthApi.java

@@ -0,0 +1,88 @@
+package com.caimei.controller;
+
+import com.alibaba.fastjson.JSONObject;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.AuthVo;
+import com.caimei.service.AuthService;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+/**
+ * 供应商API
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Api(tags = "品牌授权API")
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/auth")
+public class AuthApi {
+
+    private final AuthService authService;
+
+    /**
+     * 授权列表
+     */
+    @ApiOperation("授权列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "authUserId", required = false, value = "供应商用户id"),
+            @ApiImplicitParam(name = "authParty", required = false, value = "授权机构"),
+            @ApiImplicitParam(name = "pageNum", required = false, value = "第几页"),
+            @ApiImplicitParam(name = "pageSize", required = false, value = "一页多少条")
+    })
+    @GetMapping("/list")
+    public ResponseJson<PageInfo<AuthVo>> getAuthList(Integer authUserId, String authParty,
+                                                      @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+                                                      @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
+        return authService.getAuthList(authUserId, authParty, pageNum, pageSize);
+    }
+
+    /**
+     * 更新授权状态
+     */
+    @ApiOperation("更新授权状态")
+    @ApiImplicitParam(name = "params", value = "authId:授权id;status:授权状态:0停用 1启用", required = true)
+    @PostMapping("/update/status")
+    public ResponseJson updateAuthStatus(@RequestBody Map<String,Integer> params) {
+        Integer authId = params.get("authId");
+        Integer status = params.get("status");
+        return authService.updateAuthStatus(authId, status);
+    }
+
+    /**
+     * 删除授权
+     */
+    @ApiOperation("删除授权")
+    @ApiImplicitParam(name = "params", value = "authId:授权id", required = true)
+    @PostMapping("/delete")
+    public ResponseJson deleteAuth(@RequestBody Map<String,Integer> params) {
+        Integer authId = params.get("authId");
+        return authService.deleteAuth(authId);
+    }
+
+    /**
+     * 添加/编辑授权
+     */
+    @ApiOperation("添加/编辑授权")
+    @ApiImplicitParam(name = "params", value = "authId:授权id;authUserId:供应商用户id;authParty:授权机构;status:授权状态:0下架,1上架;createBy:创建人id", required = true)
+    @PostMapping("/save")
+    public ResponseJson saveAuth(@RequestBody String params) {
+        JSONObject paramsMap = JSONObject.parseObject(params);
+        Integer authId = paramsMap.getInteger("authId");
+        Integer authUserId = paramsMap.getInteger("authUserId");
+        String authParty = paramsMap.getString("authParty");
+        Integer status = paramsMap.getInteger("status");
+        Integer createBy = paramsMap.getInteger("createBy");
+        return authService.saveAuth(authId, authUserId, authParty, status, createBy);
+    }
+}

+ 148 - 0
src/main/java/com/caimei/controller/ShopApi.java

@@ -0,0 +1,148 @@
+package com.caimei.controller;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.dto.ShopSaveDto;
+import com.caimei.model.vo.ShopVo;
+import com.caimei.service.ShopService;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.Map;
+
+/**
+ * 供应商API
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Api(tags = "供应商API")
+@Slf4j
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/shop")
+public class ShopApi {
+
+    private final ShopService shopService;
+
+    /**
+     * 供应商列表
+     */
+    @ApiOperation("供应商列表")
+    @ApiImplicitParams({
+            @ApiImplicitParam(name = "shopName", required = false, value = "供应商名称"),
+            @ApiImplicitParam(name = "shopType", required = false, value = "供应商类型:1品牌方,2代理商"),
+            @ApiImplicitParam(name = "brandId", required = false, value = "所属品牌id"),
+            @ApiImplicitParam(name = "mobile", required = false, value = "手机号"),
+            @ApiImplicitParam(name = "linkMan", required = false, value = "联系人"),
+            @ApiImplicitParam(name = "pageNum", required = false, value = "第几页"),
+            @ApiImplicitParam(name = "pageSize", required = false, value = "一页多少条")
+    })
+    @GetMapping("/list")
+    public ResponseJson<PageInfo<ShopVo>> getShopList(String shopName, Integer shopType, Integer brandId, String mobile, String linkMan,
+                                                      @RequestParam(value = "pageNum", defaultValue = "1") Integer pageNum,
+                                                      @RequestParam(value = "pageSize", defaultValue = "10") Integer pageSize) {
+
+        return shopService.getShopList(shopName, shopType, brandId, mobile, linkMan, pageNum, pageSize);
+    }
+
+    /**
+     * 获取供应商表单数据
+     * @param authUserId    供应商用户id
+     * @return  ShopVo
+     */
+    @GetMapping("/form/data")
+    public ResponseJson<ShopVo> getShopFormData(Integer authUserId) {
+        return shopService.getShopFormData(authUserId);
+    }
+
+    /**
+     * 添加供应商
+     * @param shopSaveDto {
+     *                   shopType           供应商类型:1代理商,2品牌方
+     *                   brandId            品牌id
+     *                   shopName           供应商名称
+     *                   mobile             手机号
+     *                   linkMan            联系人
+     *                   countryId          产地国家id
+     *                   brandAuthLogo      品牌授权logo
+     *                   shopStatus         供应商状态:0停用 1启用
+     *                   securityLink       官网认证链接
+     *                   statementType      代理声明类型:1弹窗 2链接 3图片 4文件(.doc .ppt .pdf)
+     *                   statementContent   声明弹窗内容
+     *                   statementLink      声明链接
+     *                   statementImage     声明图片
+     *                   statementFileId    声明文件id
+     *                   createBy           创建人用户id
+     * }
+     */
+    @ApiOperation("添加/编辑供应商")
+    @PostMapping("/save")
+    public ResponseJson saveShop(@RequestBody ShopSaveDto shopSaveDto) {
+        return shopService.saveShop(shopSaveDto);
+    }
+
+    /**
+     * 更新供应商状态
+     */
+    @ApiOperation("更新供应商状态")
+    @ApiImplicitParam(name = "params", value = "authUserId:供应商用户id;status:供应商状态:0停用 1启用", required = true)
+    @PostMapping("/update/status")
+    public ResponseJson updateShopStatus(@RequestBody Map<String,Integer> params) {
+        Integer authUserId = params.get("authUserId");
+        Integer status = params.get("status");
+        return shopService.updateShopStatus(authUserId, status);
+    }
+
+    /**
+     * 重置密码
+     */
+    @ApiOperation("重置密码")
+    @ApiImplicitParam(name = "params", value = "authUserId:供应商用户id", required = true)
+    @PostMapping("/reset/password")
+    public ResponseJson resetShopPassword(@RequestBody Map<String,Integer> params) {
+        Integer authUserId = params.get("authUserId");
+        return shopService.resetShopPassword(authUserId);
+    }
+
+
+    /**
+     * 代理声明文件上传
+     *
+     * @param params authUserId:供应商用户id,file:上传的文件,fileName:文件名称
+     * @return
+     */
+    @ApiOperation("代理声明文件上传")
+    @ApiImplicitParam(name = "params", value = "authUserId:供应商用户id,file:上传文件", required = true)
+    @PostMapping("/upload/file")
+    public ResponseJson<Integer> uploadFile(@RequestBody String params) {
+        if (StringUtils.isBlank(params)) {
+            return ResponseJson.error("数据异常", null);
+        }
+        Integer authUserId = null;
+        MultipartFile file = null;
+        try {
+            JSONObject paramsMap = JSON.parseObject(params);
+            if (null == paramsMap) {
+                return ResponseJson.error("数据异常,参数不能为空", null);
+            }
+            authUserId = paramsMap.getInteger("authUserId");
+            file = (MultipartFile) paramsMap.get("file");
+            if (null == file) {
+                return ResponseJson.error("数据异常,上传文件不能为空", null);
+            }
+        } catch (Exception e) {
+            log.error("<<<<< 系统异常 >>>>>");
+        }
+        return shopService.uploadFile(authUserId, file);
+    }
+}

+ 70 - 0
src/main/java/com/caimei/controller/UploadApi.java

@@ -0,0 +1,70 @@
+package com.caimei.controller;
+
+import com.caimei.config.FastDfsClient;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+@Api(tags = "上传API")
+@Slf4j
+@RestController
+@RequestMapping("/upload")
+public class UploadApi {
+    protected static final Logger logger = LoggerFactory.getLogger(UploadApi.class);
+    @Autowired
+    private FastDfsClient client;
+    @Value("${caimei.imageDomain}")
+    private String imageDomain;
+
+    /**
+     * 上传图片
+     */
+    @ApiOperation("上传图片")
+    @ApiImplicitParam(name = "file", value = "图片", required = true)
+    @PostMapping("/image")
+    public Map<String, Object> uploadImage(MultipartFile file) throws IOException {
+        Map<String, Object> map = new HashMap<>(2);
+        String saveFile = null;
+        if (file != null ) {
+            // 保存文件
+            saveFile = saveFile(file);
+            saveFile = imageDomain + "/" + saveFile;
+            map.put("data", saveFile);
+            map.put("msg", "上传成功");
+            logger.info(">>>>>>>>>>>>>>>>图片上传成功:" + saveFile);
+        } else {
+            map.put("msg", "上传失败");
+            logger.info(">>>>>>>>>>>>>>>>图片上传失败:");
+        }
+        return map;
+    }
+
+    private String saveFile( MultipartFile file) throws IOException {
+        String originalFilename = file.getOriginalFilename();
+        String name = file.getName();
+        String randomUUID = UUID.randomUUID().toString();
+        int index = originalFilename.lastIndexOf(".");
+        String exet = originalFilename.substring(index);
+        String filePath = "/mnt/newdatadrive/data/runtime/jar-instance/zplm-admin/tempImage/";
+        filePath += "\\" + randomUUID + exet;
+        file.transferTo(new File(filePath));
+        logger.info(">>>>>>>>>>>>>>>>图片上传路径:" + filePath);
+        String file1 = client.uploadFile(filePath);
+        return file1;
+    }
+
+}

+ 57 - 0
src/main/java/com/caimei/controller/UserApi.java

@@ -0,0 +1,57 @@
+package com.caimei.controller;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.dto.PasswordDto;
+import com.caimei.model.vo.UserLoginVo;
+import com.caimei.service.UserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiOperation;
+import lombok.RequiredArgsConstructor;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Map;
+
+
+/**
+ * 用户公共API
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Api(tags = "用户公共API")
+@RestController
+@RequiredArgsConstructor
+@RequestMapping("/user")
+public class UserApi {
+
+    private final UserService userService;
+
+    /**
+     * 登录(用户名/手机号,密码)
+     */
+    @ApiOperation("登录(用户名/手机号,密码)")
+    @ApiImplicitParam(name = "params", value = "mobileOrName:手机号或用户名;password:密码", required = true)
+    @PostMapping("/login/password")
+    public ResponseJson<UserLoginVo> passwordLogin(@RequestBody Map<String,String> params) {
+        String mobileOrName = params.get("mobileOrName");
+        String password = params.get("password");
+        return userService.passwordLogin(mobileOrName,password);
+    }
+
+    /**
+     * 修改密码
+     * @param passwordDto {
+     *                           authUserId         用户id
+     *                           oldPassword        旧密码
+     *                           newPassword        新密码
+     *                           confirmPwd         确认密码
+     * }
+     */
+    @ApiOperation("修改密码")
+    @PostMapping("/update/password")
+    public ResponseJson updatePassword(@RequestBody PasswordDto passwordDto) {
+        return userService.updatePassword(passwordDto);
+    }
+}

+ 28 - 0
src/main/java/com/caimei/mapper/AuthMapper.java

@@ -0,0 +1,28 @@
+package com.caimei.mapper;
+
+import com.caimei.model.po.CmBrandAuthPo;
+import com.caimei.model.vo.AuthVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Mapper
+public interface AuthMapper {
+
+    List<AuthVo> getAuthList(@Param("authUserId") Integer authUserId, @Param("authParty") String authParty);
+
+    void updateAuthStatusByAuthId(@Param("authId") Integer authId, @Param("status") Integer status);
+
+    void deleteAuthByAuthId(Integer authId);
+
+    void insertAuth(CmBrandAuthPo auth);
+
+    void updateAuthByAuthId(CmBrandAuthPo auth);
+}

+ 48 - 0
src/main/java/com/caimei/mapper/ShopMapper.java

@@ -0,0 +1,48 @@
+package com.caimei.mapper;
+
+import com.caimei.model.po.CmBrandAuthFilePo;
+import com.caimei.model.po.ShopInfoPo;
+import com.caimei.model.po.UserPo;
+import com.caimei.model.vo.ShopVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Mapper
+public interface ShopMapper {
+
+    List<ShopVo> getShopList(@Param("shopName") String shopName, @Param("shopType") Integer shopType, @Param("brandId") Integer brandId, @Param("mobile") String mobile, @Param("linkMan") String linkMan);
+
+    void updateShopStatusByUserId(@Param("authUserId") Integer authUserId, @Param("status") Integer status);
+
+    String getShopMobileByUserId(Integer authUserId);
+
+    CmBrandAuthFilePo getStatementFile(CmBrandAuthFilePo searchFile);
+
+    void insertStatementFile(CmBrandAuthFilePo cmBrandAuthFile);
+
+    Integer getFileNumByMd5Hex(String md5Hex);
+
+    void deleteStatementFile(Integer id);
+
+    void insertShop(UserPo shop);
+
+    void updateBrandAuthLogo(Integer brandId);
+
+    void updateFileUserId(@Param("statementFileId") Integer statementFileId,@Param("authUserId") Integer authUserId);
+
+    void insertShopInfo(ShopInfoPo shopInfo);
+
+    void updateShopByUserId(UserPo shop);
+
+    void updateShopInfoByUserId(ShopInfoPo shopInfo);
+
+    ShopVo getShopByAuthUserId(Integer authUserId);
+}

+ 23 - 0
src/main/java/com/caimei/mapper/UserMapper.java

@@ -0,0 +1,23 @@
+package com.caimei.mapper;
+
+import com.caimei.model.vo.UserLoginVo;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Mapper
+public interface UserMapper {
+
+    UserLoginVo getAdminUserByName(String name);
+
+    UserLoginVo getShopUserByMobile(String mobile);
+
+    String getPasswordByUserId(Integer authUserId);
+
+    void updatePasswordByUserId(@Param("authUserId") Integer authUserId, @Param("newPassword") String newPassword);
+}

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

@@ -0,0 +1,81 @@
+package com.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;
+}

+ 34 - 0
src/main/java/com/caimei/model/dto/PasswordDto.java

@@ -0,0 +1,34 @@
+package com.caimei.model.dto;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/12
+ */
+@ApiModel("修改密码")
+@Data
+public class PasswordDto {
+
+    @NotNull
+    @ApiModelProperty("用户id")
+    Integer authUserId;
+
+    @NotNull
+    @ApiModelProperty("旧密码")
+    String oldPassword;
+
+    @NotNull
+    @ApiModelProperty("新密码")
+    String newPassword;
+
+    @NotNull
+    @ApiModelProperty("确认密码")
+    String confirmPwd;
+}

+ 122 - 0
src/main/java/com/caimei/model/dto/ShopSaveDto.java

@@ -0,0 +1,122 @@
+package com.caimei.model.dto;
+
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.validation.constraints.NotNull;
+
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Data
+public class ShopSaveDto {
+    /**
+     * 供应商id
+     */
+    @ApiModelProperty("供应商id")
+    private Integer authUserId;
+
+    /**
+     * 供应商类型:1代理商,2品牌方
+     */
+    @NotNull(message = "供应商类型不能为空")
+    @ApiModelProperty("供应商类型:1代理商,2品牌方")
+    private Integer shopType;
+
+    /**
+     * 品牌id
+     */
+    @NotNull(message = "品牌id不能为空")
+    @ApiModelProperty("品牌id")
+    private Integer brandId;
+
+    /**
+     * 供应商名称
+     */
+    @NotNull(message = "供应商名称不能为空")
+    @ApiModelProperty("供应商名称")
+    private String shopName;
+
+    /**
+     * 手机号
+     */
+    @NotNull(message = "手机号不能为空")
+    @ApiModelProperty("手机号")
+    private String mobile;
+
+    /**
+     * 联系人
+     */
+    @NotNull(message = "联系人不能为空")
+    @ApiModelProperty("联系人")
+    private String linkMan;
+
+    /**
+     * 产地国家id
+     */
+    @NotNull(message = "产地不能为空")
+    @ApiModelProperty("产地国家id")
+    private Integer countryId;
+
+    /**
+     * 品牌授权logo
+     */
+    @NotNull(message = "品牌logo不能为空")
+    @ApiModelProperty("品牌授权logo")
+    private String brandAuthLogo;
+
+    /**
+     * 供应商状态:0停用 1启用
+     */
+    @NotNull(message = "供应商状态不能为空")
+    @ApiModelProperty("供应商状态:0停用 1启用")
+    private Integer shopStatus;
+
+    /**
+     * 官网认证链接
+     */
+    @ApiModelProperty("官网认证链接")
+    private String securityLink;
+
+    /**
+     * 代理声明类型:1弹窗 2链接 3图片 4文件(.doc .ppt .pdf)
+     */
+    @ApiModelProperty("代理声明类型:1弹窗 2链接 3图片 4文件(.doc .ppt .pdf)")
+    private Integer statementType;
+
+    /**
+     * 声明弹窗内容
+     */
+    @ApiModelProperty("声明弹窗内容")
+    private String statementContent;
+
+    /**
+     * 声明链接
+     */
+    @ApiModelProperty("声明链接")
+    private String statementLink;
+
+    /**
+     * 声明图片
+     */
+    @ApiModelProperty("声明图片")
+    private String statementImage;
+
+    /**
+     * 声明文件id
+     */
+    @ApiModelProperty("声明文件id")
+    private Integer statementFileId;
+
+    /**
+     * 创建人用户id
+     */
+    @ApiModelProperty("创建人用户id")
+    private Integer createBy;
+}

+ 40 - 0
src/main/java/com/caimei/model/po/CmBrandAuthFilePo.java

@@ -0,0 +1,40 @@
+package com.caimei.model.po;
+
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/05/13
+ */
+@Data
+public class CmBrandAuthFilePo {
+    private Integer id;
+    /**
+     * 对应cm_brand_auth_user表authUserId
+     */
+    private Integer authUserId;
+
+    /**
+     * 声明文件名称
+     */
+    private String name;
+
+    /**
+     * oss存储名
+     */
+    private String ossName;
+
+    /**
+     * 文件唯一标识
+     */
+    private String md5Hex;
+
+    /**
+     * 上传时间
+     */
+    private Date uploadTime;
+}

+ 40 - 0
src/main/java/com/caimei/model/po/CmBrandAuthPo.java

@@ -0,0 +1,40 @@
+package com.caimei.model.po;
+
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * cm_brand_auth
+ * @author 
+ */
+@Data
+public class CmBrandAuthPo {
+    private Integer id;
+
+    /**
+     * 供应商用户id
+     */
+    private Integer authUserId;
+
+    /**
+     * 被授权方名称
+     */
+    private String authParty;
+
+    /**
+     * 上架状态:0已下架,1已上架
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 创建人Id
+     */
+    private Integer createBy;
+
+}

+ 54 - 0
src/main/java/com/caimei/model/po/ShopInfoPo.java

@@ -0,0 +1,54 @@
+package com.caimei.model.po;
+
+import java.io.Serializable;
+import lombok.Data;
+
+/**
+ * cm_brand_auth_shop_info
+ * @author 
+ */
+@Data
+public class ShopInfoPo{
+    private Integer id;
+
+    /**
+     * 用户Id
+     */
+    private Integer authUserId;
+
+    /**
+     * 供应商类型:1品牌方,2代理商
+     */
+    private Integer type;
+
+    /**
+     * 所属品牌Id
+     */
+    private Integer brandId;
+
+    /**
+     * 产地国家id
+     */
+    private Integer countryId;
+
+    /**
+     * 代理声明类型:1弹窗,2链接,3图片,4文件
+     */
+    private Integer statementType;
+
+    /**
+     * 声明弹窗内容
+     */
+    private String statementContent;
+
+    /**
+     * 声明链接
+     */
+    private String statementlink;
+
+    /**
+     * 声明图片
+     */
+    private String statementImage;
+
+}

+ 54 - 0
src/main/java/com/caimei/model/po/UserPo.java

@@ -0,0 +1,54 @@
+package com.caimei.model.po;
+
+import java.io.Serializable;
+import java.util.Date;
+import lombok.Data;
+
+/**
+ * cm_brand_auth_user
+ * @author 
+ */
+@Data
+public class UserPo {
+    private Integer authUserId;
+
+    /**
+     * 账号名
+     */
+    private String name;
+
+    /**
+     * 手机号
+     */
+    private String mobile;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 联系人
+     */
+    private String linkMan;
+
+    /**
+     * 用户身份:1管理员,2供应商
+     */
+    private Integer userIdentity;
+
+    /**
+     * 创建时间
+     */
+    private Date createTime;
+
+    /**
+     * 创建人用户Id
+     */
+    private Integer createBy;
+
+    /**
+     * 状态:0停用,1启用
+     */
+    private Integer status;
+}

+ 47 - 0
src/main/java/com/caimei/model/vo/AuthVo.java

@@ -0,0 +1,47 @@
+package com.caimei.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.util.Date;
+
+/**
+ * cm_brand_auth
+ * @author 
+ */
+@Data
+public class AuthVo {
+    @ApiModelProperty("授权id")
+    private Integer id;
+
+    /**
+     * 供应商用户id
+     */
+    @ApiModelProperty("供应商用户id")
+    private Integer authUserId;
+
+    /**
+     * 授权机构
+     */
+    @ApiModelProperty("授权机构")
+    private String authParty;
+
+    /**
+     * 上架状态:0已下架,1已上架
+     */
+    @ApiModelProperty("上架状态:0已下架,1已上架")
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+
+    /**
+     * 创建人Id
+     */
+    @ApiModelProperty("创建人")
+    private String createBy;
+
+}

+ 73 - 0
src/main/java/com/caimei/model/vo/ShopVo.java

@@ -0,0 +1,73 @@
+package com.caimei.model.vo;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Data
+public class ShopVo implements Serializable {
+    /**
+     * 供应商用户id
+     */
+    @ApiModelProperty("供应商用户id")
+    private Integer authUserId;
+
+    /**
+     * 供应商名称
+     */
+    @ApiModelProperty("供应商名称")
+    private String name;
+
+    /**
+     * 供应商类型:1代理商 2品牌方
+     */
+    @ApiModelProperty("供应商类型")
+    private Integer type;
+
+    /**
+     * 所属品牌
+     */
+    @ApiModelProperty("所属品牌")
+    private Integer brandName;
+
+    /**
+     * 手机号
+     */
+    @ApiModelProperty("手机号")
+    private String mobile;
+
+    /**
+     * 联系人
+     */
+    @ApiModelProperty("联系人")
+    private String linkMan;
+
+    /**
+     * 供应商状态:0停用 1启用
+     */
+    @ApiModelProperty("供应商状态:0停用 1启用")
+    private Integer shopStatus;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    private Date createTime;
+
+    /**
+     * 创建人
+     */
+    @ApiModelProperty("创建人")
+    private String createBy;
+
+}

+ 50 - 0
src/main/java/com/caimei/model/vo/UserLoginVo.java

@@ -0,0 +1,50 @@
+package com.caimei.model.vo;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 登录成功返回用户数据
+ *
+ * @author : Charles
+ * @date : 2021/3/10
+ */
+@Data
+public class UserLoginVo implements Serializable {
+    /**
+     * 用户Id
+     */
+    @ApiModelProperty("用户Id")
+    private Integer authUserId;
+    /**
+     * 用户名
+     */
+    @ApiModelProperty("用户名")
+    private String name;
+    /**
+     * 密码
+     */
+    @ApiModelProperty("密码")
+    private String password;
+    /**
+     * 供应商状态:0已停用 1已启用
+     */
+    @ApiModelProperty("供应商状态:0已停用 1已启用")
+    private Integer shopStatus;
+    /**
+     * 用户身份: 1管理员 2供应商
+     */
+    @ApiModelProperty("用户身份: 1管理员 2供应商")
+    private Integer userIdentity;
+    /**
+     * token
+     */
+    @ApiModelProperty("token")
+    private String token;
+}

+ 51 - 0
src/main/java/com/caimei/service/AuthService.java

@@ -0,0 +1,51 @@
+package com.caimei.service;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.vo.AuthVo;
+import com.github.pagehelper.PageInfo;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+public interface AuthService {
+
+    /**
+     * 授权列表
+     * @param authUserId    供应商用户id
+     * @param authParty     授权机构
+     * @param pageNum       第几页
+     * @param pageSize      一页多少条
+     * @return  AuthVo
+     */
+    ResponseJson<PageInfo<AuthVo>> getAuthList(Integer authUserId, String authParty, Integer pageNum, Integer pageSize);
+
+    /**
+     * 更新授权状态
+     * @param authId    授权id
+     * @param status    授权状态:0停用 1启用
+     * @return  ResponseJson
+     */
+    ResponseJson updateAuthStatus(Integer authId, Integer status);
+
+    /**
+     * 删除授权
+     * @param authId    授权id
+     * @return  ResponseJson
+     */
+    ResponseJson deleteAuth(Integer authId);
+
+    /**
+     * 添加/编辑授权
+     *
+     * @param authId            授权id
+     * @param authUserId        供应商用户id
+     * @param authParty         授权机构
+     * @param status            授权状态:0已下架 1已上架
+     * @param createBy          创建人id
+     * @return  ResponseJson
+     */
+    ResponseJson saveAuth(Integer authId, Integer authUserId, String authParty, Integer status, Integer createBy);
+}

+ 76 - 0
src/main/java/com/caimei/service/ShopService.java

@@ -0,0 +1,76 @@
+package com.caimei.service;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.dto.ShopSaveDto;
+import com.caimei.model.vo.ShopVo;
+import com.github.pagehelper.PageInfo;
+import org.springframework.web.multipart.MultipartFile;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+public interface ShopService {
+    /**
+     * 供应商列表数据
+     *
+     * @param shopName  供应商名称
+     * @param shopType  供应商类型:1品牌方,2代理商
+     * @param brandId   所属品牌Id
+     * @param mobile    手机号
+     * @param linkMan   联系人
+     * @param pageNum   第几页
+     * @param pageSize  一页多少条
+     * @return PageInfo<ShopVo>
+     */
+    ResponseJson<PageInfo<ShopVo>> getShopList(String shopName, Integer shopType, Integer brandId, String mobile, String linkMan, Integer pageNum, Integer pageSize);
+
+    /**
+     * 更新供应商状态
+     * @param authUserId    供应商用户id
+     * @param status    供应商状态
+     * @return ResponseJson
+     */
+    ResponseJson updateShopStatus(Integer authUserId, Integer status);
+
+    /**
+     * 重置供应商密码
+     * @param authUserId    供应商用户id
+     * @return ResponseJson
+     */
+    ResponseJson resetShopPassword(Integer authUserId);
+
+    /**
+     * 上传文件
+     * @param authUserId    供应商用户id
+     * @param file      上传文件
+     * @return
+     */
+    ResponseJson<Integer> uploadFile(Integer authUserId, MultipartFile file);
+
+    /**
+     * 添加供应商
+     * @param shopSaveDto {
+     *                   shopType           供应商类型:1代理商,2品牌方
+     *                   brandId            品牌id
+     *                   shopName           供应商名称
+     *                   mobile             手机号
+     *                   linkMan            联系人
+     *                   countryId          产地国家id
+     *                   brandAuthLogo      品牌授权logo
+     *                   shopStatus         供应商状态:0停用 1启用
+     *                   securityLink       官网认证链接
+     *                   statementType      代理声明类型:1弹窗 2链接 3图片 4文件(.doc .ppt .pdf)
+     *                   statementContent   声明弹窗内容
+     *                   statementLink      声明链接
+     *                   statementImage     声明图片
+     *                   statementFileId    声明文件id
+     *                   createBy           创建人用户id
+     * }
+     */
+    ResponseJson saveShop(ShopSaveDto shopSaveDto);
+
+    ResponseJson<ShopVo> getShopFormData(Integer authUserId);
+}

+ 35 - 0
src/main/java/com/caimei/service/UserService.java

@@ -0,0 +1,35 @@
+package com.caimei.service;
+
+import com.caimei.model.ResponseJson;
+import com.caimei.model.dto.PasswordDto;
+import com.caimei.model.vo.ShopVo;
+import com.caimei.model.vo.UserLoginVo;
+import com.github.pagehelper.PageInfo;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+public interface UserService {
+    /**
+     * 登录(用户名/手机号,密码)
+     * @param mobileOrName 手机号或用户名
+     * @param password 密码
+     * @return UserLoginVo
+     */
+    ResponseJson<UserLoginVo> passwordLogin(String mobileOrName, String password);
+
+    /**
+     * 修改密码
+     * @param passwordDto {
+     *                           authUserId         用户id
+     *                           oldPassword        旧密码
+     *                           newPassword        新密码
+     *                           confirmPwd         确认密码
+     * }
+     * @return ResponseJson
+     */
+    ResponseJson updatePassword(PasswordDto passwordDto);
+}

+ 109 - 0
src/main/java/com/caimei/service/impl/AuthServiceImpl.java

@@ -0,0 +1,109 @@
+package com.caimei.service.impl;
+
+import com.caimei.mapper.AuthMapper;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.po.CmBrandAuthPo;
+import com.caimei.model.vo.AuthVo;
+import com.caimei.service.AuthService;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Slf4j
+@Service
+public class AuthServiceImpl implements AuthService {
+
+    @Resource
+    private AuthMapper authMapper;
+
+    @Override
+    public ResponseJson<PageInfo<AuthVo>> getAuthList(Integer authUserId, String authParty, Integer pageNum, Integer pageSize) {
+        if (null == authUserId) {
+            return ResponseJson.error("参数异常,请输入供应商用户id", null);
+        }
+        PageHelper.startPage(pageNum, pageSize);
+        List<AuthVo> authList = authMapper.getAuthList(authUserId, authParty);
+        PageInfo<AuthVo> pageData = new PageInfo<>(authList);
+        return ResponseJson.success(pageData);
+    }
+
+    @Override
+    public ResponseJson updateAuthStatus(Integer authId, Integer status) {
+        if (authId == null) {
+            return ResponseJson.error("请输入用户id");
+        }
+        if (status == null) {
+            return ResponseJson.error("请输入要更新的状态值");
+        } else if (status != 0 && status != 1) {
+            return ResponseJson.error("状态值只能为0或1");
+        }
+        authMapper.updateAuthStatusByAuthId(authId, status);
+        if (status == 0) {
+            return ResponseJson.success("停用品牌授权成功");
+        } else {
+            return ResponseJson.success("启用品牌授权成功");
+        }
+    }
+
+    @Override
+    public ResponseJson deleteAuth(Integer authId) {
+        if (null == authId) {
+            return ResponseJson.error("参数异常,请输入授权id");
+        }
+        authMapper.deleteAuthByAuthId(authId);
+        return ResponseJson.success("删除品牌授权成功");
+    }
+
+    @Override
+    public ResponseJson saveAuth(Integer authId, Integer authUserId, String authParty, Integer status, Integer createBy) {
+        if (null == authUserId) {
+            return ResponseJson.error("参数异常,请输入供应商用户id");
+        }
+        if (StringUtils.isEmpty(authParty)) {
+            return ResponseJson.error("参数异常,请输入授权机构名称");
+        }
+        if (null == authUserId) {
+            return ResponseJson.error("参数异常,请输入授权状态值");
+        } else {
+            if (status != 0 && status != 1) {
+                return ResponseJson.error("参数异常,授权状态值只能为0或1");
+            }
+        }
+        if (null == createBy) {
+            return ResponseJson.error("参数异常,请输入创建人id");
+        }
+        /*
+            组装授权数据
+         */
+        CmBrandAuthPo auth = new CmBrandAuthPo();
+        auth.setAuthUserId(authUserId);
+        auth.setAuthParty(authParty);
+        auth.setStatus(status);
+        if (null == authId) {
+            auth.setCreateBy(createBy);
+            auth.setCreateTime(new Date());
+        } else
+            auth.setId(authId);
+        /*
+            保存授权
+         */
+            if (null == authId) {
+                authMapper.insertAuth(auth);
+            } else {
+                authMapper.updateAuthByAuthId(auth);
+            }
+        return ResponseJson.success("保存品牌授权成功");
+    }
+}

+ 239 - 0
src/main/java/com/caimei/service/impl/ShopServiceImpl.java

@@ -0,0 +1,239 @@
+package com.caimei.service.impl;
+
+import com.caimei.mapper.ShopMapper;
+import com.caimei.mapper.UserMapper;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.dto.ShopSaveDto;
+import com.caimei.model.po.CmBrandAuthFilePo;
+import com.caimei.model.po.ShopInfoPo;
+import com.caimei.model.po.UserPo;
+import com.caimei.model.vo.ShopVo;
+import com.caimei.service.ShopService;
+import com.caimei.utils.AliyunSmsUtil;
+import com.caimei.utils.CodeUtil;
+import com.caimei.utils.Md5Util;
+import com.caimei.utils.OSSUtils;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileInputStream;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Slf4j
+@Service
+public class ShopServiceImpl implements ShopService {
+
+    @Resource
+    private ShopMapper shopMapper;
+    @Resource
+    private UserMapper userMapper;
+
+    @Override
+    public ResponseJson<PageInfo<ShopVo>> getShopList(String shopName, Integer shopType, Integer brandId, String mobile, String linkMan, Integer pageNum, Integer pageSize) {
+        PageHelper.startPage(pageNum, pageSize);
+        List<ShopVo> shopList = shopMapper.getShopList(shopName, shopType, brandId, mobile, linkMan);
+        PageInfo<ShopVo> pageData = new PageInfo<>(shopList);
+        return ResponseJson.success(pageData);
+    }
+
+    @Override
+    public ResponseJson updateShopStatus(Integer authUserId, Integer status) {
+        if (authUserId == null) {
+            return ResponseJson.error("请输入用户id");
+        }
+        if (status == null) {
+            return ResponseJson.error("请输入要更新的状态值");
+        } else if (status != 0 && status != 1) {
+            return ResponseJson.error("状态值只能为0或1");
+        }
+        shopMapper.updateShopStatusByUserId(authUserId, status);
+        if (status == 0) {
+            return ResponseJson.success("停用供应商成功");
+        } else {
+            return ResponseJson.success("启用供应商成功");
+        }
+    }
+
+    @Override
+    public ResponseJson resetShopPassword(Integer authUserId) {
+        if (authUserId == null) {
+            return ResponseJson.error("请输入用户id");
+        }
+        String newPassword = CodeUtil.generateCode(8);
+        String md5Password = Md5Util.md5(newPassword);
+        userMapper.updatePasswordByUserId(authUserId, md5Password);
+        String mobile = shopMapper.getShopMobileByUserId(authUserId);
+        boolean smsFlag = AliyunSmsUtil.sendSms(mobile, 7, "{code:" + newPassword + "}");
+        if (!smsFlag) {
+            // 短信发送失败重试一次
+            AliyunSmsUtil.sendSms(mobile, 7, "{code:" + newPassword + "}");
+        }
+        log.info("正品联盟后台供应商重置密码,用户id:" + authUserId + ",新密码:" + newPassword);
+        return ResponseJson.success("密码重置成功");
+    }
+
+    @Override
+    public ResponseJson<Integer> uploadFile(Integer authUserId, MultipartFile file) {
+        String fileAllName = file.getOriginalFilename();
+        String fileType = fileAllName.substring(fileAllName.lastIndexOf(".") + 1);
+        String fffff = file.getName();
+        String fileName = file.getResource().getFilename();
+        String uuid = UUID.randomUUID().toString().replaceAll("-", "");
+        String filePath = uuid + "." + fileType;
+        String contentType = OSSUtils.getContentType(fileAllName);
+        try {
+            //保存本地
+            File uploadFile = OSSUtils.ossUpload(file);
+            //判断文件的唯一性,转换成16进制md5值
+            String md5Hex = DigestUtils.md5Hex(new FileInputStream(uploadFile));
+            CmBrandAuthFilePo searchFile = new CmBrandAuthFilePo();
+            searchFile.setAuthUserId(authUserId);
+            searchFile.setMd5Hex(md5Hex);
+            // 查找该供应商下是否已存在相同文件
+            CmBrandAuthFilePo cmBrandAuthFile = shopMapper.getStatementFile(searchFile);
+            if (cmBrandAuthFile == null) {
+                log.info("默认路径>>>" + uploadFile.getAbsolutePath());
+                // 修改情况下,如果原来已经选择了文件代理声明,并且旧文件与新文件不同,需要将旧文件删除
+                deleteFileByUserId(authUserId);
+                //将新文件上传oss
+                OSSUtils.ossUpload(filePath, uploadFile, contentType);
+                //删除本地文件
+                OSSUtils.deleteFile(uploadFile);
+                //保存关联关系
+                cmBrandAuthFile = new CmBrandAuthFilePo();
+                cmBrandAuthFile.setAuthUserId(authUserId);
+                cmBrandAuthFile.setName(fileName);
+                cmBrandAuthFile.setOssName(filePath);
+                cmBrandAuthFile.setMd5Hex(md5Hex);
+                cmBrandAuthFile.setUploadTime(new Date());
+                shopMapper.insertStatementFile(cmBrandAuthFile);
+            } else {
+                //删除本地文件
+                OSSUtils.deleteFile(uploadFile);
+            }
+            return ResponseJson.success("文件上传成功", cmBrandAuthFile.getId());
+        } catch (Exception e) {
+            log.error("<<<<< 文件上传异常 >>>>>");
+            return ResponseJson.error("文件上传失败", null);
+        }
+    }
+
+    private void deleteFileByUserId(Integer authUserId) {
+        CmBrandAuthFilePo searchFile = new CmBrandAuthFilePo();
+        searchFile.setAuthUserId(authUserId);
+        CmBrandAuthFilePo oldFile = shopMapper.getStatementFile(searchFile);
+        if (oldFile != null) {
+            Integer num = shopMapper.getFileNumByMd5Hex(oldFile.getMd5Hex());
+            if (num == 1) {
+                // 如果这个文件只有这个供应商在使用,删除oss服务器上的文件
+                OSSUtils.deleteSingleFile(oldFile.getOssName());
+            }
+            shopMapper.deleteStatementFile(oldFile.getId());
+        }
+    }
+
+    @Override
+    public ResponseJson saveShop(ShopSaveDto shopSaveDto) {
+        Integer shopType = shopSaveDto.getShopType();
+        if (shopType == null) {
+            return ResponseJson.error("请选择供应商类型", null);
+        }
+        // 更新品牌授权logo
+        shopMapper.updateBrandAuthLogo(shopSaveDto.getBrandId());
+        /*
+            组装供应商用户数据
+         */
+        UserPo shop = new UserPo();
+        // 供应商名称
+        shop.setName(shopSaveDto.getShopName());
+        // 手机号
+        shop.setMobile(shopSaveDto.getMobile());
+        // 联系人
+        shop.setLinkMan(shopSaveDto.getLinkMan());
+        // 供应商状态
+        shop.setStatus(shopSaveDto.getShopStatus());
+        if (null == shopSaveDto.getAuthUserId()) {
+            // 用户身份:1管理员,2供应商
+            shop.setUserIdentity(2);
+            // 创建管理员id
+            shop.setCreateBy(shopSaveDto.getCreateBy());
+            // 创建时间
+            shop.setCreateTime(new Date());
+            // 设置随机8位密码
+            shop.setPassword(CodeUtil.generateCode(8));
+        } else {
+            shop.setAuthUserId(shopSaveDto.getAuthUserId());
+        }
+        /*
+            保存供应商用户
+         */
+        if (null == shopSaveDto.getAuthUserId()) {
+            shopMapper.insertShop(shop);
+        } else {
+            shopMapper.updateShopByUserId(shop);
+        }
+        /*
+            组装供应商信息数据
+         */
+        ShopInfoPo shopInfo = new ShopInfoPo();
+        // 供应商用户id
+        shopInfo.setAuthUserId(shop.getAuthUserId());
+        // 供应商类型:1品牌方,2代理商
+        shopInfo.setType(shopSaveDto.getShopType());
+        // 品牌id
+        shopInfo.setBrandId(shopSaveDto.getBrandId());
+        // 国家id
+        shopInfo.setCountryId(shopSaveDto.getCountryId());
+        if (null != shopSaveDto.getStatementType()) {
+            shopInfo.setStatementType(shopSaveDto.getStatementType());
+            if (1 == shopSaveDto.getStatementType()) {
+                // 声明弹窗
+                shopInfo.setStatementContent(shopSaveDto.getStatementContent());
+            } else if (2 == shopSaveDto.getStatementType()) {
+                // 声明链接
+                shopInfo.setStatementlink(shopSaveDto.getStatementLink());
+            } else if (3 == shopSaveDto.getStatementType()) {
+                // 声明图片
+                shopInfo.setStatementImage(shopSaveDto.getStatementImage());
+            }
+            if (4 == shopSaveDto.getStatementType()) {
+                // 更新代理声明文件
+                Integer statementFileId = shopSaveDto.getStatementFileId();
+                shopMapper.updateFileUserId(statementFileId, shop.getAuthUserId());
+            } else {
+                // 没有选择文件代理声明的情况下,若存在原来的文件,删除代理声明文件
+                deleteFileByUserId(shop.getAuthUserId());
+            }
+        }
+        if (null == shopSaveDto.getAuthUserId()) {
+            shopMapper.insertShopInfo(shopInfo);
+        } else {
+            shopMapper.updateShopInfoByUserId(shopInfo);
+        }
+        return ResponseJson.success("保存供应商成功", null);
+    }
+
+
+    @Override
+    public ResponseJson<ShopVo> getShopFormData(Integer authUserId) {
+        if (null == authUserId) {
+            return ResponseJson.error("参数异常,请输入供应商用户id", null);
+        }
+        shopMapper.getShopByAuthUserId(authUserId);
+        return null;
+    }
+}

+ 138 - 0
src/main/java/com/caimei/service/impl/UserServiceImpl.java

@@ -0,0 +1,138 @@
+package com.caimei.service.impl;
+
+import com.caimei.components.RedisService;
+import com.caimei.mapper.UserMapper;
+import com.caimei.model.ResponseJson;
+import com.caimei.model.dto.PasswordDto;
+import com.caimei.model.vo.UserLoginVo;
+import com.caimei.service.UserService;
+import com.caimei.utils.JwtUtil;
+import com.caimei.utils.Md5Util;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+
+/**
+ * Description
+ *
+ * @author : Aslee
+ * @date : 2021/5/11
+ */
+@Slf4j
+@Service
+public class UserServiceImpl implements UserService {
+
+    @Resource
+    private RedisService redisService;
+    @Resource
+    private UserMapper userMapper;
+
+    /**
+     * 登录(用户名/手机号,密码)
+     * @param mobileOrName 手机号或用户名
+     * @param password 密码
+     * @return UserLoginVo
+     */
+    @Override
+    public ResponseJson<UserLoginVo> passwordLogin(String mobileOrName, String password) {
+        if (StringUtils.isEmpty(mobileOrName)) {
+            return ResponseJson.error("请填写账户名", null);
+        }
+        if (StringUtils.isEmpty(password)) {
+            return ResponseJson.error("请填写密码", null);
+        }
+        // 根据账户名和手机号获取管理员账号和供应商账号
+        UserLoginVo adminUser = userMapper.getAdminUserByName(mobileOrName);
+        UserLoginVo shopUser = userMapper.getShopUserByMobile(mobileOrName);
+        // 密码校验
+        Boolean passwordVerify;
+        if (adminUser != null) {
+            // 管理员登录
+            // 比对密码
+            passwordVerify = passwordVerify(password, adminUser.getPassword());
+            if (passwordVerify) {
+                return logonVerify(adminUser);
+            } else if (shopUser != null) {
+                // 管理员登录失败,尝试供应商登录
+                passwordVerify = passwordVerify(password, shopUser.getPassword());
+                if (passwordVerify) {
+                    return logonVerify(shopUser);
+                }
+            }
+        } else if (shopUser != null) {
+            // 供应商登录
+            passwordVerify = passwordVerify(password, shopUser.getPassword());
+            if (passwordVerify) {
+                return logonVerify(shopUser);
+            }
+        }
+        return ResponseJson.error("输入的密码和账户名不匹配", null);
+    }
+
+    @Override
+    public ResponseJson updatePassword(PasswordDto passwordDto) {
+        Integer authUserId = passwordDto.getAuthUserId();
+        String oldPassword = passwordDto.getOldPassword();
+        String newPassword = passwordDto.getNewPassword();
+        String confirmPwd = passwordDto.getConfirmPwd();
+        // 参数校验
+        if (authUserId == null) {
+            return ResponseJson.error("用户id不能为空");
+        }
+        if (StringUtils.isEmpty(oldPassword)) {
+            return ResponseJson.error("请输入旧密码");
+        }
+        if (StringUtils.isEmpty(newPassword)) {
+            return ResponseJson.error("请输入新密码");
+        }
+        if (StringUtils.isEmpty(confirmPwd)) {
+            return ResponseJson.error("请确认密码");
+        }
+        if (!newPassword.equals(confirmPwd)) {
+            return ResponseJson.error("新密码与确认密码不一致");
+        }
+        // 验证输入的旧密码与数据库中的密码是否相同
+        String dbPassword = userMapper.getPasswordByUserId(authUserId);
+        Boolean passwordVerify = passwordVerify(oldPassword, dbPassword);
+        if (!passwordVerify) {
+            return ResponseJson.error("旧密码输入不正确");
+        }
+        // 更新密码
+        newPassword = Md5Util.md5(newPassword);
+        userMapper.updatePasswordByUserId(authUserId, newPassword);
+        return ResponseJson.success("密码修改成功");
+    }
+
+    /**
+     * 登录校验
+     *
+     * @param loginUser 用户信息
+     * @return UserLoginVo
+     */
+    private ResponseJson<UserLoginVo> logonVerify(UserLoginVo loginUser) {
+        // 生成token给用户
+        String token = JwtUtil.createToken(loginUser.getAuthUserId());
+        // 为了过期续签,将token存入redis,并设置超时时间
+        redisService.set(token, token, JwtUtil.getExpireTime());
+        loginUser.setToken(token);
+        // 供应商
+        if (null != loginUser.getShopStatus() && null != loginUser.getUserIdentity() && 2 == loginUser.getUserIdentity()) {
+            if (0 == loginUser.getShopStatus()) {
+                return ResponseJson.error(-2, "您的企业账号已被冻结,请联系客服处理", null);
+            }
+        }
+        // 清除密码
+        loginUser.setPassword(null);
+        return ResponseJson.success("登录成功", loginUser);
+    }
+
+    /**
+     * 密码校验
+     */
+    private Boolean passwordVerify(String password, String dbPassword) {
+        String md5Password = Md5Util.md5(password);
+        return md5Password.equals(dbPassword);
+    }
+}

+ 116 - 0
src/main/java/com/caimei/utils/AliyunSmsUtil.java

@@ -0,0 +1,116 @@
+package com.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";
+        }
+        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;
+        }
+    }
+}

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

@@ -0,0 +1,84 @@
+package com.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();
+    }
+}

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

@@ -0,0 +1,113 @@
+package com.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/com/caimei/utils/Md5Util.java

@@ -0,0 +1,62 @@
+package com.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();
+	}
+}

+ 172 - 0
src/main/java/com/caimei/utils/OSSUtils.java

@@ -0,0 +1,172 @@
+package com.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.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Date;
+import java.util.UUID;
+
+public class OSSUtils {
+    @Value("${aliyun.endpoint}")
+    private static String endpoint;
+    @Value("${aliyun.accessKeyId}")
+    private static String accessKeyId;
+    @Value("${aliyun.accessKeySecret}")
+    private static String accessKeySecret;
+    @Value("${aliyun.bucketName}")
+    private static String privateBucket;
+
+    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);
+            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, 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();
+    }
+}

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

@@ -0,0 +1,19 @@
+server:
+  port: 8012
+spring:
+  application:
+    # 指定服务名
+    name: caimei-zplm-admin
+  profiles:
+    active: @activatedProperties@
+
+#整合mybatis
+mybatis:
+  #加载Mybatis映射文件
+  mapper-locations:
+    - classpath:mapper/*.xml
+
+
+
+
+

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

@@ -0,0 +1,44 @@
+CREATE TABLE `cm_brand_auth_user` (
+                                                `authUserId` INT NOT NULL AUTO_INCREMENT,
+                                                `name` VARCHAR(100) NULL COMMENT '账号名',
+                                                `mobile` VARCHAR(20) NULL COMMENT '手机号',
+                                                `password` VARCHAR(100) NULL COMMENT '密码',
+                                                `linkMan` VARCHAR(30) NULL COMMENT '联系人',
+                                                `userIdentity` INT NULL COMMENT '用户身份:1管理员,2供应商',
+                                                `createTime` DATETIME NULL COMMENT '创建时间',
+                                                `createBy` INT NULL COMMENT '创建人Id',
+                                                `status` INT NULL COMMENT '状态:0停用,1启用',
+                                                PRIMARY KEY (`authUserId`))
+    ENGINE = InnoDB
+    DEFAULT CHARACTER SET = utf8
+    COMMENT = '正品联盟后台管理员';
+CREATE TABLE `cm_brand_auth_shop_info` (
+                                                   `id` INT NOT NULL AUTO_INCREMENT,
+                                                   `authUserId` INT NULL COMMENT '用户Id',
+                                                   `type` INT NULL COMMENT '供应商类型:1品牌方,2代理商',
+                                                   `brandId` INT NULL COMMENT '所属品牌Id',
+                                                   `countryId` INT NULL COMMENT '产地国家id',
+                                                   `statementType` INT NULL COMMENT '代理声明类型:1弹窗,2链接,3图片,4文件',
+                                                   `statementContent` TEXT NULL COMMENT '声明弹窗内容',
+                                                   `statementLink` VARCHAR(255) NULL COMMENT '声明链接',
+                                                   `statementImage` TEXT NULL COMMENT '声明图片',
+                                                   PRIMARY KEY (`id`))
+    ENGINE = InnoDB
+    DEFAULT CHARACTER SET = utf8
+    COMMENT = '正品联盟供应商信息';
+INSERT INTO `cm_brand_auth_user` (`authUserId`, `name`, `password`, `userIdentity`, `status`) VALUES ('1', 'admin', '21D34CF4A2F21FDD791C4C1B67C3F954', '1', '1');
+ALTER TABLE `cm_brand_auth_file`
+    CHANGE COLUMN `brandAuthId` `authUserId` INT NULL DEFAULT NULL COMMENT '授权用户id' ;
+
+ALTER TABLE `cm_brand_auth`
+    DROP COLUMN `statementImage`,
+    DROP COLUMN `statementLink`,
+    DROP COLUMN `statementContent`,
+    DROP COLUMN `statementType`,
+    DROP COLUMN `agentName`,
+    DROP COLUMN `agentFlag`,
+    DROP COLUMN `securityLink`,
+    DROP COLUMN `countryId`,
+    DROP COLUMN `brandId`,
+    ADD COLUMN `authUserId` INT NULL COMMENT '供应商用户id' AFTER `id`,
+    ADD COLUMN `status` INT NULL COMMENT '上架状态:0已下架,1已上架' AFTER `authParty`;

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

@@ -0,0 +1,74 @@
+spring:
+  #数据源连接--start
+  datasource:
+    url: jdbc:mysql://119.29.164.246:3306/caimei?characterEncoding=UTF8&serverTimezone=Asia/Shanghai
+    username: developer
+    password: 05bZ/OxTB:X+yd%1
+    # 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: 10.104.50.235
+    #    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/mall2b/logs
+  level:
+    root: info
+
+# swagger文档显示配置
+swagger:
+  enabled: false
+
+#自定义配置
+wx:
+  AppId: wxca7172d7a20bdf7a
+  AppSecret: d7f853a64b73d01ef93f3829852a790e
+  crmAppId: wxea43a0f9ebce9e66
+  crmAppSecret: 1c3cd60908e72dd280840bee9e15f7f6
+
+# 新旧www服务域名
+caimei:
+  oldapi: https://www-b.caimei365.com
+  #支付异步回调地址
+  notifyUrl: https://spi-b.caimei365.com/PayOrder/paymentCallback
+  #支付链接重定向地址
+  redirectLink: https://spi-b.caimei365.com/PayOrder/jumpPage
+  #图片服务器
+  imageDomain: https://img-b.caimei365.com

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

@@ -0,0 +1,79 @@
+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
+
+#自定义配置
+wx:
+  AppId: wxca7172d7a20bdf7a
+  AppSecret: d7f853a64b73d01ef93f3829852a790e
+  crmAppId: wxea43a0f9ebce9e66
+  crmAppSecret: 1c3cd60908e72dd280840bee9e15f7f6
+
+# 新旧www服务域名
+caimei:
+  oldapi: http://localhost:8100
+  #支付异步回调地址
+  notifyUrl: https://spi-b.caimei365.com/PayOrder/paymentCallback
+  #支付链接重定向地址
+  redirectLink: https://spi-b.caimei365.com/PayOrder/jumpPage
+  #图片服务器
+  imageDomain: https://img-b.caimei365.com
+
+#阿里云oss存储
+aliyun:
+  accessKeyId: LTAI4GBL3o4YkWnbKYgf2Xia
+  accessKeySecret: dBjAXqbYiEPP6Ukuk2ZsXQeET7FVkK
+  bucketName: caimei-oss
+  endpoint: https://oss-cn-shenzhen.aliyuncs.com
+

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

@@ -0,0 +1,72 @@
+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/mall2b/logs
+  level:
+    root: info
+
+# swagger文档显示配置
+swagger:
+  enabled: false
+
+
+#自定义配置
+wx:
+  AppId: wxca7172d7a20bdf7a
+  AppSecret: d7f853a64b73d01ef93f3829852a790e
+  crmAppId: wxea43a0f9ebce9e66
+  crmAppSecret: 1c3cd60908e72dd280840bee9e15f7f6
+
+# 新旧www服务域名
+caimei:
+  oldapi: https://www.caimei365.com
+  #支付异步回调地址
+  notifyUrl: https://spi.caimei365.com/PayOrder/paymentCallback
+  #支付链接重定向地址
+  redirectLink: https://spi.caimei365.com/PayOrder/jumpPage
+  #图片服务器
+  imageDomain: https://img-b.caimei365.com

+ 28 - 0
src/main/resources/mapper/AuthMapper.xml

@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.caimei.mapper.AuthMapper">
+    <insert id="insertAuth" ></insert>
+    <update id="updateAuthStatusByAuthId">
+        update cm_brand_auth
+        set status = #{status}
+        where id = #{authId}
+    </update>
+    <update id="updateAuthByAuthId">
+        update cm_brand_auth
+        set authParty = #{authParty},
+            status    = #{status}
+        where id = #{authId}
+    </update>
+    <delete id="deleteAuthByAuthId">
+        delete from cm_brand_auth where id = #{authId}
+    </delete>
+    <select id="getAuthList" resultType="com.caimei.model.vo.AuthVo">
+        select id, authParty, a.status, a.createTime, u.name
+        from cm_brand_auth a
+                 left join cm_brand_auth_user u on a.createBy = u.authUserId
+        where a.authUserId = #{authUserId}
+        <if test="authParty != null and authParty != ''">
+            and a.authParty like CONCAT('%',#{authParty},'%')
+        </if>
+    </select>
+</mapper>

+ 142 - 0
src/main/resources/mapper/ShopMapper.xml

@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.caimei.mapper.ShopMapper">
+    <insert id="insertStatementFile" keyColumn="id" keyProperty="id" useGeneratedKeys="true" parameterType="com.caimei.model.po.CmBrandAuthFilePo">
+        insert into cm_brand_auth_file (`authUserid`, `name`, `ossName`, `md5Hex`, `uploadTime`)
+        values (#{authUserid}, #{name}, #{ossName}, #{md5Hex}, #{uploadTime})
+    </insert>
+    <insert id="insertShop"  keyColumn="authUserId" keyProperty="authUserId" useGeneratedKeys="true" parameterType="com.caimei.model.po.UserPo">
+        insert into cm_brand_auth_user (`name`, `mobile`, `password`, `userIdentity`, `createTime`, `createBy`,
+                                        `status`)
+        values (#{name}, #{mobile}, #{password}, #{userIdentity}, #{createTime}, #{createBy}, #{status})
+    </insert>
+    <insert id="insertShopInfo">
+        insert into cm_brand_auth_shop_info
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            authUserId,type,brandId,countryId,
+            <if test="statementType != null">
+                statementType,
+            </if>
+            <if test="statementContent != null and statementContent != ''">
+                statementContent,
+            </if>
+            <if test="statementLink != null and statementLink != ''">
+                statementLink,
+            </if>
+            <if test="statementImage != null and statementImage != ''">
+                statementImage,
+            </if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            #{authUserId},#{type},#{brandId},#{countryId},
+            <if test="statementType != null">
+                #{statementType},
+            </if>
+            <if test="statementContent != null and statementContent != ''">
+                #{statementContent},
+            </if>
+            <if test="statementLink != null and statementLink != ''">
+                #{statementLink},
+            </if>
+            <if test="statementImage != null and statementImage != ''">
+                #{statementImage},
+            </if>
+        </trim>
+    </insert>
+    <update id="updateShopStatusByUserId">
+        update cm_brand_auth_user
+        set status = #{status}
+        where authUserId = #{authUserId};
+    </update>
+    <update id="updateBrandAuthLogo">
+        update cm_brand
+        set authLogo = #{authLogo}
+        where id = #{brandId}
+    </update>
+    <update id="updateFileUserId">
+        update cm_brand_auth_file
+        set authUserId =#{authUserId}
+        where id = #{statementFileId};
+    </update>
+    <update id="updateShopByUserId">
+        update cm_brand_auth_user
+        set `name`    = #{name},
+            `mobile`  = #{mobile},
+            `linkMan` = #{linkMan},
+            `status`  = #{status}
+        where authUserId = #{authUserId}
+    </update>
+    <update id="updateShopInfoByUserId">
+        update cm_brand_auth_shop_info
+        set type = #{type},brandId = #{brandId},countryId=#{countryId}
+        <if test="statementType != null">
+            ,statementType = #{statementType}
+        </if>
+        <if test="statementContent != null and statementContent != ''">
+            ,statementContent = #{statementContent}
+        </if>
+        <if test="statementLink !=  and statementLink != ''">
+            ,statementLink = #{statementLink}
+        </if>
+        <if test="statementImage !=  and statementImage != ''">
+            ,statementImage = #{statementImage}
+        </if>
+
+    </update>
+    <delete id="deleteStatementFile">
+        delete from cm_brand_auth_file where id = #{id}
+    </delete>
+    <select id="getShopList" resultType="com.caimei.model.vo.ShopVo">
+        select u.authUserId,u.name,s.type,cb.name as brandName,u.mobile,u.linkMan,
+            u.status as shopStatus,u.createTime,
+            (select au.name from cm_brand_auth_user au where au.authUserId = u.createBy) as createBy
+            from cm_brand_auth_user u
+            left join cm_brand_auth_shop_info s on u.authUserId = s.authUserId
+            left join cm_brand cb on cb.id = s.brandId
+        where u.userIdentity = 2
+        <if test="shopName != null and shopName !=''">
+            AND u.name like CONCAT('%',#{shopName},'%')
+        </if>
+        <if test="shopType != null ">
+            AND s.type = #{shopType}
+        </if>
+        <if test="brandId != null">
+            AND s.brandId = #{brandId}
+        </if>
+        <if test="mobile != null and mobile !=''">
+            AND u.mobile like CONCAT('%',#{mobile},'%')
+        </if>
+        <if test="linkMan != null and linkMan !=''">
+            AND u.linkMan like CONCAT('%',#{linkMan},'%')
+        </if>
+        ORDER BY u.createTime DESC
+    </select>
+    <select id="getShopMobileByUserId" resultType="java.lang.String">
+        select mobile from cm_brand_auth_user where authUserId = #{authUserId}
+    </select>
+    <select id="getStatementFile" resultType="com.caimei.model.po.CmBrandAuthFilePo">
+        select id, authUserId, name, ossName, md5Hex, uploadTime
+        from cm_brand_auth_file
+        <where>
+            <if test="id != null">
+                and id = #{id}
+            </if>
+            <if test="authUserId != null">
+                and authUserId = #{authUserId}
+            </if>
+            <if test="md5Hex != null and md5Hex != ''">
+                and md5Hex = #{md5Hex}
+            </if>
+        </where>
+        limit 1
+    </select>
+    <select id="getFileNumByMd5Hex" resultType="java.lang.Integer">
+        select count(*) from cm_brand_auth_file where md5Hex = #{md5Hex}
+    </select>
+    <select id="getShopByAuthUserId" resultType="com.caimei.model.vo.ShopVo">
+        select u.authUserId,u.name,u.mobile,u.linkMan,s.type,s.brandId,s.countryId,b.authLogo
+               from cm_brand_auth_user u
+                   left join cm_brand_auth_shop_info s on u.authUserId = s.authUserId
+                left join cm_brand b on s.brandId = b.id
+    </select>
+</mapper>

+ 27 - 0
src/main/resources/mapper/UserMapper.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.caimei.mapper.UserMapper">
+    <update id="updatePasswordByUserId">
+        update cm_brand_auth_user
+        set password = #{newPassword}
+        where authUserId = #{authUserId};
+    </update>
+    <select id="getAdminUserByName" resultType="com.caimei.model.vo.UserLoginVo">
+        select authUserId, name, password, userIdentity
+        from cm_brand_auth_user
+        where name = #{name}
+          and status = 1
+        limit 1;
+    </select>
+    <select id="getShopUserByMobile" resultType="com.caimei.model.vo.UserLoginVo">
+        select authUserId, name, password, userIdentity, status as shopStatus
+        from cm_brand_auth_user
+        where mobile = #{mobile}
+        limit 1;
+    </select>
+    <select id="getPasswordByUserId" resultType="java.lang.String">
+        select password
+        from cm_brand_auth_user
+        where authUserId = #{authUserId};
+    </select>
+</mapper>

+ 16 - 0
src/test/java/com/caimei/AdminApplicationTests.java

@@ -0,0 +1,16 @@
+package com.caimei;
+
+import com.caimei.utils.JwtUtil;
+import org.junit.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+@SpringBootTest
+public class AdminApplicationTests {
+
+    @Test
+    public void JWTToken(){
+        System.out.println(JwtUtil.createToken(111));
+        System.out.println(JwtUtil.createToken(222));
+        System.out.println(JwtUtil.createToken(111));
+    }
+}