This commit is contained in:
shahaibo
2024-04-02 15:46:31 +08:00
commit a670a2ef2b
229 changed files with 15994 additions and 0 deletions

234
pom.xml Normal file
View File

@@ -0,0 +1,234 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com</groupId>
<artifactId>mixi</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>mixi</name>
<description>mixi</description>
<properties>
<java.version>8</java.version>
<mybatis.plus.version>3.5.2</mybatis.plus.version>
<hutool.version>5.8.2</hutool.version>
<wx.java.version>4.2.7.B</wx.java.version>
<fastjson.version>2.0.6.graal</fastjson.version>
<security.jwt.version>1.1.1.RELEASE</security.jwt.version>
<jjwt.version>0.9.1</jjwt.version>
<guava.version>31.1-jre</guava.version>
<jaxb-api>2.4.0-b180830.0359</jaxb-api>
<jaxb-impl>4.0.0</jaxb-impl>
<jaxb-core>4.0.0</jaxb-core>
<activation>1.1.1</activation>
<easy-captcha>1.6.2</easy-captcha>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.24</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
<version>${security.jwt.version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- 苞米豆代码生成器 -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>${mybatis.plus.version}</version>
</dependency>
<!-- 苞米豆代码生成器2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<!-- freemarker 模板引擎 -->
<!-- https://mvnrepository.com/artifact/org.freemarker/freemarker -->
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>${hutool.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>${jjwt.version}</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.2</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>${jaxb-api}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>${jaxb-impl}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-core</artifactId>
<version>${jaxb-core}</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>${activation}</version>
</dependency>
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>${easy-captcha}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-spring-boot-starter</artifactId>
<version>3.0.3</version>
</dependency>
<!-- /**发送邮件**/-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-ses</artifactId>
<version>3.1.572</version>
</dependency>
<!-- /**发送短信**/-->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId>
<version>3.1.572</version>
</dependency>
<!-- /**easyexcel-start*/-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.1.6</version>
</dependency>
<!-- /**easyexcel-end*/-->
<!--minio-->
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>8.0.3</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>5.2.1</version>
</dependency>
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>mssql-jdbc</artifactId>
<version>9.2.1.jre8</version>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.3.1</version> <!-- 指定版本号 -->
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
<version>2.14.1</version> <!-- 这里根据你的需求选择合适的版本 -->
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.14.1</version> <!-- 这里根据你的需求选择合适的版本 -->
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,17 @@
package com.mixi;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;
@MapperScan("com.mixi.mapper")
@SpringBootApplication
@EnableScheduling
public class MixiApplication {
public static void main(String[] args) {
SpringApplication.run(MixiApplication.class, args);
}
}

View File

@@ -0,0 +1,19 @@
package com.mixi.common.annotation;
import com.mixi.common.enums.ConditionType;
import java.lang.annotation.*;
/**
* @author: dangweijian
* @description: 条件注解
* @create: 2020-01-15 17:24
**/
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Condition {
ConditionType type() default ConditionType.EQ;
boolean isNull() default false;
}

View File

@@ -0,0 +1,18 @@
package com.mixi.common.annotation;
import com.mixi.common.enums.OrderType;
import java.lang.annotation.*;
/**
* @author: dangweijian
* @description: 排序注解
* @create: 2020-01-16 13:24
**/
@Documented
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Order {
OrderType order() default OrderType.DESC;
}

View File

@@ -0,0 +1,44 @@
package com.mixi.common.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* @author yanglei
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "file")
public class FileProperties {
private ElPath mac;
private ElPath linux;
private ElPath windows;
private String linuxDomain;
public ElPath getSys(){
String os = System.getProperty("os.name");
if(os.toLowerCase().startsWith("win")) {
return windows;
} else if(os.toLowerCase().startsWith("mac")){
return mac;
}
return linux;
}
public String getLinuxDomain(){
String os = System.getProperty("os.name");
if((!os.toLowerCase().startsWith("win") )&& (!os.toLowerCase().startsWith("mac"))) {
return linuxDomain;
}
return null;
}
@Data
public static class ElPath{
private String path;
}
}

View File

@@ -0,0 +1,34 @@
package com.mixi.common.config;
import io.minio.MinioClient;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;
@Data
@Component
public class MinIoClientConfig {
@Value("${minio.endpoint}")
private String endpoint;
@Value("${minio.accessKey}")
private String accessKey;
@Value("${minio.secretKey}")
private String secretKey;
/**
* 注入minio 客户端
*
* @return
*/
@Bean
public MinioClient minioClient() {
return MinioClient.builder()
.endpoint(endpoint)
.credentials(accessKey, secretKey)
.build();
}
}

View File

@@ -0,0 +1,227 @@
package com.mixi.common.config;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.generator.FastAutoGenerator;
import com.baomidou.mybatisplus.generator.config.OutputFile;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.baomidou.mybatisplus.generator.fill.Column;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import java.util.*;
/**
* 苞米豆代码自动生成器 可生成 controller service entity mapper
*/
@Slf4j
public class MybatisPlusGenerate {
// TODO:配置数据库信息(需要修改为自己的)
// private static final String URL = "jdbc:mysql://18.167.251.121:3306/mixi?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static final String URL = "jdbc:mysql://localhost:3306/gxyd_5a_theme?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true";
private static final String USERNAME = "root";
// private static final String PASSWORD = "QWa998345";
private static final String PASSWORD = "QWa998345";
// TODO项目根目录需要修改成自己的
private static final String PROJECT_ROOT_PATH = "D:\\codeManager\\code\\mixi";
//TODO这里需要注意IOT-admin是项目模块名 如果是多模块模式就需要加上模块名路径
private static final String BASE_PATH = PROJECT_ROOT_PATH + "\\src\\main\\java\\com\\mixi";
private static final String PARENT_PACKAGE_NAME = "\\com.mixi";
private static final String PACKAGE_GENERATE_LOCATION = "D:\\codeManager\\generate";
// 代码生成方法
@SuppressWarnings("all")
private static void codeGenerator() {
// 六个文件的路径
String entityPath = BASE_PATH + "\\mapper\\entity";
String mapperPath = BASE_PATH + "\\mapper\\";
String mapperXmlPath = PROJECT_ROOT_PATH + "\\src\\main\\resources\\mapper";
String servicePath = BASE_PATH + "\\service";
//暂时不生成impl
// String serviceImplPath = BASE_PATH + "/service/impl";
String controllerPath = BASE_PATH + "\\controller";
FastAutoGenerator.create(URL, "root", PASSWORD)
.globalConfig(builder -> {
builder.author("yanglei") // 设置作者
// 开启覆盖已生成的文件
.fileOverride()
// // 禁止打开输出目录
// .disableOpenDir()
// 开启swagger2。注释掉则默认关闭。
.enableSwagger()
// // 时间策略
.dateType(DateType.TIME_PACK)
// // 时间格式
.commentDate("yyyy-MM-dd")
//鼠标右击蓝色java目录选择Copy Path... 选择 Absolute Path 即可复制路径,粘贴到下面即可
.outputDir(PACKAGE_GENERATE_LOCATION); // 指定输出目录
})
.packageConfig(builder -> {
// 阶段1各个文件的包名设置用来拼接每个java文件的第一句package com.XXX.XXX.XXX.xxx;
builder.parent(PARENT_PACKAGE_NAME) // 设置父包名
// .moduleName("") // 设置父包模块名 需要你就设置
// 父包名配置
.entity("mapper.entity")
.mapper("mapper")
.xml("mapper.xml")
.service("service")
// .serviceImpl("service.impl")
.controller("controller")
.other("other")
// .pathInfo(Collections.singletonMap(OutputFile.mapper, mapperPath)); // 设置mapperXml生成路径
// .pathInfo(new HashMap<OutputFile, String>() {{
// // 实体类的保存路径
// put(OutputFile.entity, entityPath);
// // mapper接口的保存路径
// put(OutputFile.mapper, mapperPath);
// // mapper.xml文件的保存路径
// put(OutputFile.xml, mapperXmlPath);
// // service层接口的保存路径
// put(OutputFile.service, servicePath);
//// // service层接口实现类的保存路径
//// put(OutputFile.serviceImpl, serviceImplPath);
// // 控制类的保存路径
// put(OutputFile.controller, controllerPath);
// }}); // 设置mapperXml生成路径
.pathInfo(new HashMap<OutputFile, String>() {{
// 实体类的保存路径
// put(OutputFile.entity, PARENT_PACKAGE_NAME+"\\mapper\\entity");
// mapper接口的保存路径
// put(OutputFile.mapper, PACKAGE_GENERATE_LOCATION+PARENT_PACKAGE_NAME+"\\mapper");
// // mapper.xml文件的保存路径
// put(OutputFile.xml, PARENT_PACKAGE_NAME+"\\mapper2");
//// // service层接口的保存路径
// put(OutputFile.service, PARENT_PACKAGE_NAME+"\\service");
// // // service层接口实现类的保存路径
// // put(OutputFile.serviceImpl, serviceImplPath);
// // 控制类的保存路径
// put(OutputFile.controller, PARENT_PACKAGE_NAME+"\\controller");
}}); // 设置mapperXml生成路径
})
.strategyConfig(builder -> {
// builder.addInclude(getTables("t_product,t_product_batch,t_product_stock," +
// "t_attribute_type,t_attribute_value,t_product_assortment"))// 设置需要生成的表名
builder.addInclude(getTables("t_behavior_analysis"))// 设置需要生成的表名,数组 逗号分割
// 阶段1Entity实体类策略配置
.entityBuilder()
// 设置父类。会在生成的实体类名后extends BaseEntity
// .superClass(BaseEntity.class)
// 禁用生成 serialVersionUID。不推荐禁用
// .disableSerialVersionUID()
// 开启生成字段常量。
// 会在实体类末尾生成一系列 [public static final String NICKNAME = "nickname";] 的语句。一般在写wapper时会用到
// .enableColumnConstant()
// 开启链式模型。
// 会在实体类前添加 [@Accessors(chain = true)] 注解。用法如 [User user=new User().setAge(31).setName("snzl");]这是Lombok的注解需要添加Lombok依赖
.enableChainModel()
// 开启 lombok 模型。
// 会在实体类前添加 [@Getter] 和 [@Setter] 注解。这是Lombok的注解需要添加Lombok依赖
.enableLombok()
// 开启 Boolean 类型字段移除 is 前缀。
// .enableRemoveIsPrefix()
// 开启生成实体时生成字段注解。
// 会在实体类的属性前,添加[@TableField("nickname")]
// .enableTableFieldAnnotation()
// 逻辑删除字段名(数据库)。
// .logicDeleteColumnName("is_delete")
// 逻辑删除属性名(实体)。
// 会在实体类的该字段属性前加注解[@TableLogic]
// .logicDeletePropertyName("isDelete")
// 数据库表映射到实体的命名策略(默认下划线转驼峰)。一般不用设置
// .naming(NamingStrategy.underline_to_camel)
// 数据库表字段映射到实体的命名策略(默认为 null未指定按照 naming 执行)。一般不用设置
// .columnNaming(NamingStrategy.underline_to_camel)
// 添加父类公共字段。
// 这些字段不会出现在新增的实体类中。
// .addSuperEntityColumns("id", "delete_time")
// 添加忽略字段。
// 这些字段不会出现在新增的实体类中。
// .addIgnoreColumns("password")
// 添加表字段填充
// 会在实体类的该字段上追加注解[@TableField(value = "create_time", fill = FieldFill.INSERT)]
.addTableFills(new Column("create_date", FieldFill.INSERT))
// 会在实体类的该字段上追加注解[@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE)]
.addTableFills(new Column("update_date", FieldFill.INSERT_UPDATE))
// 全局主键类型。如果MySQL主键设置为自增则不需要设置此项。
// .idType(IdType.AUTO)
// 格式化文件名称。
// 如果不设置,如表[sys_user]的实体类名是[SysUser]。设置成下面这样,将是[SysUserEntity]
// .formatFileName("%sEntity")
// builder.addTablePrefix("t_", "c_"). // 设置过滤表前缀 卡尼的表是否存在前缀
// 阶段2Mapper策略配置
.mapperBuilder()
// 设置父类
// 会在mapper接口方法集成[extends BaseMapper<XXXEntity>]
.superClass(CommonMapper.class)
// 开启 @Mapper 注解。
// 会在mapper接口上添加注解[@Mapper]
.enableMapperAnnotation()
// 启用 BaseResultMap 生成。
// 会在mapper.xml文件生成[通用查询映射结果]配置。
.enableBaseResultMap()
// 启用 BaseColumnList。
// 会在mapper.xml文件生成[通用查询结果列 ]配置
.enableBaseColumnList()
// 设置缓存实现类
// .cache(MyMapperCache.class)
// 格式化 mapper 文件名称。
// 如果不设置,如表[sys_user],默认的文件名是[SysUserMapper]。写成下面这种形式后,将变成[SysUserDao]。
// .formatMapperFileName("%sMapper")
// 格式化 xml 实现类文件名称。
// 如果不设置,如表[sys_user],默认的文件名是[SysUserMapper.xml],写成下面这种形式后,将变成[SysUserXml.xml]。
// .formatXmlFileName("%sXml")
// 阶段3Service策略配置
.serviceBuilder()
// 设置 service 接口父类
.superServiceClass(ServiceImpl.class)
// 设置 service 实现类父类
// .superServiceImplClass(BaseServiceImpl.class)
// 格式化 service 接口文件名称
// 如果不设置,如表[sys_user],默认的是[ISysUserService]。写成下面这种形式后,将变成[SysUserService]。
.formatServiceFileName("%sService")
// 格式化 service 实现类文件名称
// 如果不设置,如表[sys_user],默认的是[SysUserServiceImpl]。
// .formatServiceImplFileName("%sServiceImpl")
// 阶段4Controller策略配置
.controllerBuilder()
// 设置父类。
// 会集成此父类。
// .superClass(BaseController.class)
// 开启生成 @RestController 控制器
// 会在控制类中加[@RestController]注解。
.enableRestStyle()
// 开启驼峰转连字符
.enableHyphenStyle()
// 最后:构建
.build();
})
.templateEngine(new FreemarkerTemplateEngine()) // 使用Freemarker引擎模板默认的是Velocity引擎模板
.execute();
log.info("本地表生成完毕!");
}
// 执行main方法
public static void main(String[] args) {
codeGenerator();
}
/**
* @Description 处理控制台输入all情况
* @Params [tables]
* @Return java.util.List<java.lang.String>
* @Author Corey
* @Date 2022/8/8 18:55
*/
private static List<String> getTables(String tables) {
return "all".equals(tables) ? Collections.emptyList() : Arrays.asList(tables.split(","));
}
}

View File

@@ -0,0 +1,17 @@
package com.mixi.common.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Data
@Component
public class RsaProperties {
public static String privateKey;
@Value("${rsa.private_key}")
public void setPrivateKey(String privateKey) {
RsaProperties.privateKey = privateKey;
}
}

View File

@@ -0,0 +1,33 @@
package com.mixi.common.config;
import org.hibernate.validator.HibernateValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.validation.beanvalidation.MethodValidationPostProcessor;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
@Configuration
public class WebConfig {
@Bean
public Validator validator() {
ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class)
.configure()
//failFast为true出现校验失败的情况立即结束校验不再进行后续的校验
.failFast(true)
.buildValidatorFactory();
return validatorFactory.getValidator();
}
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
MethodValidationPostProcessor methodValidationPostProcessor = new MethodValidationPostProcessor();
methodValidationPostProcessor.setValidator(validator());
return methodValidationPostProcessor;
}
}

View File

@@ -0,0 +1,40 @@
package com.mixi.common.config.captcha;
import lombok.Data;
@Data
public class LoginCode {
/**
* 验证码配置
*/
private LoginCodeEnum codeType = LoginCodeEnum.arithmetic;
/**
* 验证码有效期 分钟
*/
private Long expiration = 2L;
/**
* 验证码内容长度
*/
private int length = 2;
/**
* 验证码宽度
*/
private int width = 111;
/**
* 验证码高度
*/
private int height = 36;
/**
* 验证码字体
*/
private String fontName;
/**
* 字体大小
*/
private int fontSize = 25;
public LoginCodeEnum getCodeType() {
return codeType;
}
}

View File

@@ -0,0 +1,21 @@
package com.mixi.common.config.captcha;
public enum LoginCodeEnum {
/**
* 算数
*/
arithmetic,
/**
* 中文
*/
chinese,
/**
* 中文闪图
*/
chinese_gif,
/**
* 闪图
*/
gif,
spec
}

View File

@@ -0,0 +1,28 @@
package com.mixi.common.config.exception;
import com.mixi.common.response.ResultEnum;
import lombok.Data;
/**
* @author: dangweijian
* @description: 业务异常
* @create: 2020-01-01 17:24
**/
@Data
public class BusinessException extends RuntimeException {
private Integer code;
private String msg;
public BusinessException(ResultEnum resultEnum){
super(resultEnum.getMsg());
this.code = resultEnum.getCode();
this.msg = resultEnum.getMsg();
}
public BusinessException(String msg) {
super(msg);
this.code = ResultEnum.FAIL.getCode();
this.msg = msg;
}
}

View File

@@ -0,0 +1,85 @@
package com.mixi.common.config.exception;
import com.mixi.common.response.Response;
import com.google.common.collect.ImmutableMap;
import com.mixi.common.response.ResultEnum;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author: dangweijian
* @description: 全局异常捕获
* @create: 2019-12-03 10:24
**/
@Slf4j
@ControllerAdvice
public class ExceptionCatch {
/**
* 线程安全,且构建后不可更改
*/
private static ImmutableMap<Class<? extends Throwable>, ResultEnum> EXCEPTIONS;
/**
* 用于构建ImmutableMap
*/
private static ImmutableMap.Builder<Class<? extends Throwable>, ResultEnum> builder = ImmutableMap.builder();
@ResponseBody
@ExceptionHandler(BusinessException.class)
public Response<String> businessExceptionCatch(BusinessException e) {
log.error("发生业务异常,code:[{}],msg:[{}]", e.getCode(), e.getMsg(), e);
return Response.error(e.getCode(), e.getMsg());
}
@ResponseBody
@ExceptionHandler(Exception.class)
public Response<String> exceptionCatch(Exception e) {
log.error("发生系统异常,message:[{}]", e.getMessage(), e);
//如果ImmutableMap集合为空,构建ImmutableMap
if (EXCEPTIONS == null || EXCEPTIONS.size() == 0) {
EXCEPTIONS = builder.build();
}
//获取不可预知异常自定义错误码
if (EXCEPTIONS != null) {
ResultEnum resultEnum = EXCEPTIONS.get(e.getClass());
if (resultEnum != null) {
return Response.error(resultEnum.getCode(), resultEnum.getMsg());
}
}
return Response.error(ResultEnum.ERROR.getCode(), e.getMessage()==null?ResultEnum.ERROR.getMsg():e.getMessage());
}
/**
* 处理参数校验异常
* @param e
* @return ResponseData
*/
@ResponseBody
@ExceptionHandler(BindException.class)
public Response<String> bindExceptionHandler(BindException e) {
log.error("参数错误bind{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return Response.fail(ResultEnum.FAIL.getCode(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
}
/**
* 处理参数校验异常
* @param e
* @return ResponseData
*/
@ResponseBody
@ExceptionHandler(MethodArgumentNotValidException.class)
public Response<String> methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e) {
log.error("参数错误bind{}", e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
return Response.fail(ResultEnum.FAIL.getCode(), e.getBindingResult().getAllErrors().get(0).getDefaultMessage());
}
//初始化,不可预知异常自定义错误编码
static {
// builder.put(FileNotFoundException.class, ResultEnum.FILE_NOT_EXIST);
}
}

View File

@@ -0,0 +1,12 @@
package com.mixi.common.config.mybatis.plus;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import org.apache.ibatis.annotations.Param;
public interface CommonMapper<T> extends BaseMapper<T> {
IPage<T> voPage(IPage<T> page, @Param(Constants.WRAPPER) Wrapper<T> queryWrapper);
}

View File

@@ -0,0 +1,48 @@
package com.mixi.common.config.mybatis.plus;
import cn.hutool.core.collection.CollUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mixi.common.response.PageResponse;
import com.mixi.common.response.Response;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.stream.Collectors;
public class CommonServiceImpl<M extends CommonMapper<T>, T, E> extends ServiceImpl<M, T> {
public PageResponse<E> voPage(QueryCriteria<T, E> criteria) {
IPage<T> tPage = baseMapper.voPage(new Page<>(criteria.getPage(), criteria.getLimit()), criteria.buildWrapper());
if (criteria.getMapper() != null && tPage != null && CollUtil.isNotEmpty(tPage.getRecords())) {
List<E> convert = convert(tPage, criteria.getMapper(), criteria);
Response<List<E>> response = Response.success(convert);
PageResponse<E> pageResponse = new PageResponse<>(response, tPage.getCurrent(), tPage.getSize(), tPage.getTotal(), tPage.getPages());
if (criteria.getPeekAllAfter() != null) {
Consumer<List<E>> peekAllAfter = criteria.getPeekAllAfter();
peekAllAfter.accept(pageResponse.getData());
}
return pageResponse;
}
PageResponse<E> pageResponse = new PageResponse<>(null, criteria.getPage(), criteria.getLimit(), 0, 0);
if (criteria.getPeekAllAfter() != null) {
Consumer<List<E>> peekAllAfter = criteria.getPeekAllAfter();
peekAllAfter.accept(pageResponse.getData());
}
return pageResponse;
}
List<E> convert(IPage<T> page, Function<? super T, E> mapper, QueryCriteria<T, E> criteria) {
if (criteria.getPeekBefore() != null && criteria.getPeekAfter() != null) {
return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList());
} else if (criteria.getPeekBefore() != null && criteria.getPeekAfter() == null) {
return page.getRecords().stream().peek(criteria.getPeekBefore()).map(mapper).collect(Collectors.toList());
} else if (criteria.getPeekBefore() == null && criteria.getPeekAfter() != null) {
return page.getRecords().stream().map(mapper).peek(criteria.getPeekAfter()).collect(Collectors.toList());
}
return page.getRecords().stream().map(mapper).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,19 @@
package com.mixi.common.config.mybatis.plus;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.injector.DefaultSqlInjector;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.springframework.context.annotation.Configuration;
import java.util.List;
@Configuration
public class CustomerSqlInjector extends DefaultSqlInjector {
@Override
public List<AbstractMethod> getMethodList(Class<?> mapperClass, TableInfo tableInfo) {
List<AbstractMethod> methodList = super.getMethodList(mapperClass, tableInfo);
methodList.add(new SelectVoPage());
return methodList;
}
}

View File

@@ -0,0 +1,20 @@
package com.mixi.common.config.mybatis.plus;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.intelligent.curtain.mapper")
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}

View File

@@ -0,0 +1,83 @@
package com.mixi.common.config.mybatis.plus;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mixi.common.annotation.Condition;
import com.mixi.common.annotation.Order;
import com.mixi.common.utils.ConvertUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.Field;
import java.util.Collection;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* @author: dangweijian
* @description:
* @create: 2020-09-14 15:47
**/
@Data
@Slf4j
public abstract class QueryCriteria<T,E> {
private long page = 1;
private long limit = 10;
private Function<T, E> mapper;
private Consumer<QueryWrapper<T>> appendWrapper;
private Consumer<T> peekBefore;
private Consumer<E> peekAfter;
private Consumer<List<E>> peekAllAfter;
public QueryCriteria(Function<T, E> mapper) {
this.mapper = mapper;
}
public QueryWrapper<T> buildWrapper(){
QueryWrapper<T> wrapper = new QueryWrapper<>();
Field[] fields = this.getClass().getDeclaredFields();
for (Field field : fields) {
Condition condition = field.getAnnotation(Condition.class);
if(condition != null){
field.setAccessible(true);
Object value = null;
try {
value = field.get(this);
} catch (IllegalAccessException e) {
log.warn("reflection anomaly!");
}
if(!StrUtil.isEmptyIfStr(value)){
switch (condition.type()){
case EQ:
wrapper.eq(ConvertUtil.humpToLine2(field.getName()), value);
break;
case LIKE:
wrapper.like(ConvertUtil.humpToLine2(field.getName()), value);
case BETWEEN:
if(value instanceof Collection && ((List) value).size() >= 2){
wrapper.between(ConvertUtil.humpToLine2(field.getName()), ((List)value).get(0), ((List)value).get(1));
}
}
}else if(condition.isNull()){
wrapper.isNull(ConvertUtil.humpToLine2(field.getName()));
}
}
Order order = field.getAnnotation(Order.class);
if(order != null){
if(!StrUtil.isEmptyIfStr(order.order())){
switch (order.order()){
case DESC:
wrapper.orderByDesc(ConvertUtil.humpToLine2(field.getName()));
break;
case ASC:
wrapper.orderByAsc(ConvertUtil.humpToLine2(field.getName()));
}
}
}
}
wrapper.func(this.getAppendWrapper() != null, this.getAppendWrapper());
return wrapper;
}
}

View File

@@ -0,0 +1,22 @@
package com.mixi.common.config.mybatis.plus;
import com.baomidou.mybatisplus.core.enums.SqlMethod;
import com.baomidou.mybatisplus.core.injector.AbstractMethod;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlSource;
public class SelectVoPage extends AbstractMethod {
private static final String MAPPER_METHOD = "voPage";
public SelectVoPage() {
super(MAPPER_METHOD);
}
public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) {
String sql = String.format(SqlMethod.SELECT_PAGE.getSql(), this.sqlFirst(), this.sqlSelectColumns(tableInfo, true), tableInfo.getTableName(), this.sqlWhereEntityWrapper(true, tableInfo), this.sqlOrderBy(tableInfo), this.sqlComment());
SqlSource sqlSource = this.languageDriver.createSqlSource(this.configuration, sql, modelClass);
return this.addSelectMappedStatementForTable(mapperClass, MAPPER_METHOD, sqlSource, tableInfo);
}
}

View File

@@ -0,0 +1,33 @@
package com.mixi.common.config.swagger;
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.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2WebMvc;
@Configuration
@EnableSwagger2WebMvc
public class Knife4jConfiguration {
@Bean(value = "MixiApis")
public Docket gxyd5aThemeApis() {
Docket docket=new Docket(DocumentationType.SWAGGER_2)
.apiInfo(new ApiInfoBuilder()
.description("Mixi接口文档文档")
.termsOfServiceUrl("暂无")
.version("1.0")
.build())
//分组名称
.groupName("1.0")
.select()
//这里指定Controller扫描包路径
.apis(RequestHandlerSelectors.basePackage("com.mixi.controller"))
.paths(PathSelectors.any())
.build();
return docket;
}
}

View File

@@ -0,0 +1,9 @@
package com.mixi.common.constant;
/**
* @author yanglei
* 异常类常量
*/
public class ExceptionConstant {
public static final int DATA_SIZE_LIIMIT = 500;
}

View File

@@ -0,0 +1,14 @@
package com.mixi.common.constant;
/**
* @author yanglei
* 异常类常量
*/
public class TokenConstant {
/**
* 固定session
*/
public static final String FIX_SESSION = "qrLS_003b0ff46b42356f_40be06f160c74616b815c680f3cca1f3";
public static final String PERMISSIONS = "9672233956";
}

View File

@@ -0,0 +1,19 @@
package com.mixi.common.context;
import com.mixi.model.vo.AuthPrincipalVo;
public class UserContext {
private static ThreadLocal<AuthPrincipalVo> userHolder= new ThreadLocal<AuthPrincipalVo>();
public static AuthPrincipalVo getUserHolder() {
return userHolder.get();
}
public static void delete() {
userHolder.remove();
}
public static void setUserHolder(AuthPrincipalVo authPrincipalVo) {
userHolder.set(authPrincipalVo);
}
}

View File

@@ -0,0 +1,10 @@
package com.mixi.common.enums;
/**
* @author: dangweijian
* @description: 分页条件类型
* @create: 2020-01-14 17:33
**/
public enum ConditionType {
EQ,LIKE,BETWEEN;
}

View File

@@ -0,0 +1,21 @@
package com.mixi.common.enums;
public enum DataScope {
ALL("全部"),
DEPT("部门");
private String desc;
DataScope(String desc) {
this.desc = desc;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}

View File

@@ -0,0 +1,33 @@
package com.mixi.common.enums;
import lombok.AllArgsConstructor;
import java.util.stream.Stream;
/**
* @author: yanglei
* @description: 标签类型
* @create: 2023-3-6 17:33
**/
@AllArgsConstructor
public enum LabelTypeEnum {
/**
* 自定义标签
*/
CUSTOM("Custom Label"),
/**
* 新品
*/
NEW_PRODUCT("New product"),
/**
* 折扣
*/
SALE("Sale"),;
private String desc;
public static LabelTypeEnum of(String name){
return Stream.of(LabelTypeEnum.values()).filter(v ->v.name().equals(name)).findFirst().orElse(null);
}
}

View File

@@ -0,0 +1,27 @@
package com.mixi.common.enums;
import java.util.stream.Stream;
/**
* @author: yanglei
* @description: 操作类型 登入 忘记密码
* @create: 2022-8-10 17:33
**/
public enum OperationTypeEnum {
/**
*登入
*/
LOGIN,
/**
* 注册
*/
REGISTER,
/**
* 忘记密码
*/
FORGET_PWD;
public static OperationTypeEnum of(String name){
return Stream.of(OperationTypeEnum.values()).filter(v ->v.name().equals(name)).findFirst().orElse(null);
}
}

View File

@@ -0,0 +1,10 @@
package com.mixi.common.enums;
/**
* @author: dangweijian
* @description: 排序类型
* @create: 2020-01-14 17:33
**/
public enum OrderType {
DESC,ASC;
}

View File

@@ -0,0 +1,45 @@
package com.mixi.common.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author: yanglei
* @description: 角色权限操作
* @create: 2023-3-6 17:33
**/
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum RolePermissionOperationEnum {
/**
* 详情
*/
DETAIL("Details", 1),
/**
* 添加
*/
ADD("Add", 2),
/**
* 编辑
*/
EDIT("Edit", 3),
/**
* 删除
*/
DELETE("Delete", 4),
;
private String desc;
private Integer sort;
public static List<String> ofCodeList() {
return Stream.of(RolePermissionOperationEnum.values()).map(RolePermissionOperationEnum::name).collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,162 @@
package com.mixi.common.enums;
import com.google.common.collect.Lists;
import com.mixi.model.vo.RolePermission2OperationVO;
import com.mixi.model.vo.RolePermission2VO;
import com.mixi.model.vo.RolePermission1VO;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author: yanglei
* @description: 角色权限菜单
* @create: 2023-3-7 17:33
**/
@Getter
@AllArgsConstructor
@NoArgsConstructor
public enum RolePermissionResourceEnum {
/**
* 工作台
*/
WORK_BENCH("Workdesk","WORK_BENCH",null,null,null,1),
/**
* 商品列表
*/
PRODUCT_LIST("Product Management","PRODUCT_MANAGER","Product List","PRODUCT_LIST",RolePermissionOperationEnum.ofCodeList(),2),
/**
* 门店列表
*/
STORE_LIST("Store Management","STORE_MANAGER","Store List","STORE_LIST",null,3),
/**
* 标签列表
*/
LABEL_LIST("Label Management","LABEL_MANAGER","Label List","LABEL_LIST",null,4),
/**
* 销售报表
*/
SELLER_REPORT("Sales Report","SELLER_REPORT","Sales Report","SELLER_REPORT",null,5),
/**
* 客户信息
*/
CUSTOMER_INFO("Customer Management","CUSTOMER_MANAGER","Customer Information","CUSTOMER_INFO",null,6),
/**
* 客户浏览记录
*/
CUSTOMER_VISIT("Customer Management","CUSTOMER_MANAGER","Customer Browsing History","CUSTOMER_VISIT",null,7),
/**
* 客户购买记录
*/
CUSTOMER_PURCHASE("Customer Management","CUSTOMER_MANAGER","Customer Purchase History","CUSTOMER_PURCHASE ",null,8),
/**
* 用户管理
*/
USER_MANAGER("System Management","SYS_MANAGER","User Management","USER_MANAGER",null,9),
/**
* 角色管理
*/
ROLE_MANAGER("System Management","SYS_MANAGER","Role Management","ROLE_MANAGER",null,10),
/**
* Mi-Tu 报表
*/
MI_TU_EXPORT("Mi-Tu Export","MI_TU_EXPORT",null,null,null,11),
;
/**
* 一级菜单名称
*/
private String level1ResourceName;
/**
* 一级菜单Code
*/
private String level1ResourceCode;
/**
* 二级菜单名
*/
private String level2ResourceName;
/**
* 二级菜单Code
*/
private String level2ResourceCode;
/**
* 二级菜单对应操作列表
*/
private List<String> operateList;
/**
* 排序值
*/
private Integer sort;
public static RolePermissionResourceEnum ofLevel1Code(String level1Code){
return Stream.of(RolePermissionResourceEnum.values()).filter(v ->v.getLevel1ResourceCode().equals(level1Code)).findFirst().orElse(null);
}
public static List<RolePermission1VO> ofAll(){
Map<String,List<RolePermissionResourceEnum>> level1CodeMap = Stream.of(RolePermissionResourceEnum.values())
.collect(Collectors.groupingBy(RolePermissionResourceEnum::getLevel1ResourceCode));
List<RolePermission1VO> result = Lists.newArrayList();
//组装Level1
level1CodeMap.keySet().forEach(key ->{
RolePermissionResourceEnum level1Resource = ofLevel1Code(key);
RolePermission1VO rolePermissionVO = new RolePermission1VO();
rolePermissionVO.setCode(level1Resource.level1ResourceCode);
rolePermissionVO.setSelect(0);
rolePermissionVO.setSort(level1Resource.sort);
rolePermissionVO.setResource(level1Resource.getLevel1ResourceName());
List<RolePermission2VO> permission2VoList = Lists.newArrayList();
rolePermissionVO.setLevel2ResourceList(permission2VoList);
result.add(rolePermissionVO);
//组装Level2
List<RolePermissionResourceEnum> level2ResourceList = level1CodeMap.get(key);
if(CollectionUtils.isEmpty(level2ResourceList)){
return;
}
level2ResourceList.forEach(level2 ->{
if(StringUtils.isEmpty(level2.level2ResourceCode)){
return;
}
RolePermission2VO rolePermission2VO = new RolePermission2VO();
rolePermission2VO.setCode(level2.level2ResourceCode);
rolePermission2VO.setSelect(0);
rolePermission2VO.setSort(level2.sort);
rolePermission2VO.setResource(level2.getLevel2ResourceName());
List<RolePermission2OperationVO> operationList = Lists.newArrayList();
rolePermission2VO.setOperationList(operationList);
permission2VoList.add(rolePermission2VO);
if(CollectionUtils.isEmpty(level2.operateList)){
return;
}
level2.operateList.forEach(operate ->{
RolePermissionOperationEnum operationEnum = RolePermissionOperationEnum.valueOf(operate);
RolePermission2OperationVO operationVO = RolePermission2OperationVO.builder()
.code(operate)
.resource(operationEnum.getDesc())
.select(0)
.sort(operationEnum.getSort()).build();
operationList.add(operationVO);
});
Collections.sort(operationList, Comparator.comparing(RolePermission2OperationVO::getSort));
});
Collections.sort(permission2VoList, Comparator.comparing(RolePermission2VO::getSort));
});
Collections.sort(result, Comparator.comparing(RolePermission1VO::getSort));
return result;
}
}

View File

@@ -0,0 +1,33 @@
package com.mixi.common.httpdata.token;
public enum TokenApis {
/**
* token
*/
GET_TOKEN("POST", "/api/openApi/v2/Weixin/QrCodeLoginCheck?session="),
GENERATE_USER("POST", "/api/openApi/v2/Welink/TopicGetjson");
private String method;
private String url;
TokenApis(String method, String url) {
this.method = method;
this.url = url;
}
public String getMethod() {
return method;
}
public void setMethod(String method) {
this.method = method;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
}

View File

@@ -0,0 +1,41 @@
package com.mixi.common.httpdata.token;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import java.util.HashMap;
import java.util.Map;
@Slf4j
public class TokenQuery {
private static final String GET_TOKEN_DOMAIN = "https://www.szsige.com";
private static final String GENERATE_USER_DOMAIN = "https://www.szsige.com";
public static JSONObject getToken(String session) {
String url = GET_TOKEN_DOMAIN + TokenApis.GET_TOKEN.getUrl()+ session;
log.info("获取用户token接口请求url:" + url);
HttpResponse httpResponse = HttpUtil.createPost(url).execute();
log.info("获取用户token接口响应" + httpResponse);
if(httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())){
return JSONObject.parseObject(httpResponse.body());
}
return null;
}
public static JSONObject generateUser(Map<String, Object> param,String token) {
HttpResponse httpResponse = HttpUtil.createPost(GENERATE_USER_DOMAIN + TokenApis.GENERATE_USER.getUrl())
.body(JSONObject.toJSONString(param!=null?param:new HashMap<>()))
.header("Authorization", "Bearer "+token)
.header("X-Promiss", "9672233956")
.execute();
log.info("生成用户信息接口响应:" + httpResponse);
if(httpResponse.isOk() && StrUtil.isNotEmpty(httpResponse.body())){
return JSONObject.parseObject(httpResponse.body());
}
return null;
}
}

View File

@@ -0,0 +1,45 @@
package com.mixi.common.response;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @ClassName PageResponse
* @Description 分页响应
* @Author dwjian
* @Date 2020/1/13 0:26
*/
@Data
@NoArgsConstructor
@ApiModel("分页响应结果")
public class PageBaseResponse<T>{
@ApiModelProperty("页码")
private long page;
@ApiModelProperty("每页数量")
private long size;
@ApiModelProperty("总页数")
private long pages;
@ApiModelProperty("总条数")
private long total;
@ApiModelProperty("结果集")
private List<T> content;
public PageBaseResponse(List<T> list, long page, long size, long total, long pages) {
this.page = page;
this.size = size;
this.total = total;
this.pages = pages;
this.content = list;
}
public static <T> com.mixi.common.response.PageBaseResponse<T> success(IPage<T> page){
return new com.mixi.common.response.PageBaseResponse<>(page.getRecords() , page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
}
}

View File

@@ -0,0 +1,46 @@
package com.mixi.common.response;
import com.baomidou.mybatisplus.core.metadata.IPage;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
/**
* @ClassName PageResponse
* @Description 分页响应
* @Author dwjian
* @Date 2020/1/13 0:26
*/
@Data
@NoArgsConstructor
@ApiModel("分页响应结果")
public class PageResponse<T> extends Response<List<T>> {
@ApiModelProperty("页码")
private long page;
@ApiModelProperty("每页数量")
private long size;
@ApiModelProperty("总页数")
private long pages;
@ApiModelProperty("总条数")
private long total;
public PageResponse(Response<List<T>> response, long page, long size, long total, long pages) {
if(response != null) {
this.setData(response.getData());
this.setErrCode(response.getErrCode());
this.setErrMsg(response.getErrMsg());
}
this.page = page;
this.size = size;
this.total = total;
this.pages = pages;
}
public static <T> PageResponse<T> success(IPage<T> page){
Response<List<T>> response = success(page.getRecords());
return new PageResponse<>(response , page.getCurrent(), page.getSize(), page.getTotal(), page.getPages());
}
}

View File

@@ -0,0 +1,96 @@
package com.mixi.common.response;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @ClassName Response
* @Description success代表响应成功 fail代表主动响应失败 error代表系统异常
* @Author dwjian
* @Date 2019/9/8 21:48
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("响应结果")
public class Response<T> implements Serializable {
@ApiModelProperty("响应状态码 0成功 -1失败")
private int errCode;
@ApiModelProperty("提示消息")
private String errMsg;
@ApiModelProperty("数据结果")
private T data;
public static <T> Response<T> success(){
return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null);
}
public static <T> Response<T> success(String msg){
return success(ResultEnum.SUCCESS.getCode(), msg, null);
}
public static <T> Response<T> success(T data){
return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data);
}
public static <T> Response<T> successData(T data){
return success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), data);
}
public static <T> Response<T> success(int code, T data){
return success(code, ResultEnum.SUCCESS.getMsg(), data);
}
public static <T> Response<T> success(int code, String msg, T data){
return getResponse(code, msg, data);
}
public static <T> Response<T> fail(String msg) {
return fail(ResultEnum.FAIL.getCode(), msg);
}
public static <T> Response<T> fail(T data) {
return fail(ResultEnum.FAIL.getCode(), ResultEnum.FAIL.getMsg(), data);
}
public static <T> Response<T> fail(ResultEnum resultEnum) {
return fail(resultEnum.getCode(), resultEnum.getMsg(), null);
}
public static <T> Response<T> fail(int code, String msg) {
return fail(code, msg, null);
}
public static <T> Response<T> fail(int code, String msg, T data) {
return getResponse(code, msg, data);
}
public static <T> Response<T> error(String msg) {
return error(ResultEnum.ERROR.getCode(), msg);
}
public static <T> Response<T> error(T data) {
return error(ResultEnum.ERROR.getCode(), ResultEnum.ERROR.getMsg(), data);
}
public static <T> Response<T> error(int code, String msg) {
return error(code, msg, null);
}
public static <T> Response<T> error(int code, String msg, T data) {
return getResponse(code, msg, data);
}
private static <T> Response<T> getResponse(int code, String msg, T data){
return new Response<>(code, msg, data);
}
}

View File

@@ -0,0 +1,55 @@
package com.mixi.common.response;
/**
* @ClassName ResultEnum
* @Description 响应结果枚举
* @Author dwjian
* @Date 2019/9/8 21:58
*/
public enum ResultEnum {
SUCCESS(true, 0, "SUCCESS"),
FAIL(false, -1, "FAIL"),
ERROR(false, -1, "系统异常"),
PARAMETER_ERROR(false, -2, "参数异常"),
NO_LOGIN(false,-100,"用户未登录"),
NO_PERMISSION(false,-200,"无权限访问"),
ACCOUNT_LOCK(false,-300,"账号已冻结");
private int code;
private String msg;
private boolean isOK;
ResultEnum(boolean isOK, int code, String msg){
this.isOK = isOK;
this.code = code;
this.msg = msg;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public boolean isOK() {
return isOK;
}
public void setOK(boolean OK) {
isOK = OK;
}
}

View File

@@ -0,0 +1,27 @@
package com.mixi.common.security;
import com.mixi.common.response.Response;
import com.mixi.common.response.ResultEnum;
import com.mixi.common.utils.JSONResponseUtils;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName UserAuthAccessDeniedHandler
* @Description 无权限处理类
* @Author dwjian
* @Date 2020/7/9 20:30
*/
@Component
public class UserAuthAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException exception) throws IOException {
Response<String> response = Response.error(ResultEnum.NO_PERMISSION.getCode(), ResultEnum.NO_PERMISSION.getMsg());
JSONResponseUtils.build(httpServletResponse, response);
}
}

View File

@@ -0,0 +1,29 @@
package com.mixi.common.security;
import com.mixi.common.response.Response;
import com.mixi.common.response.ResultEnum;
import com.mixi.common.utils.JSONResponseUtils;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName UserAuthenticationEntryPointHandler
* @Description 未登录处理类
* @Author dwjian
* @Date 2020/7/9 20:13
*/
@Component
public class UserAuthenticationEntryPointHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
Response<String> response = Response.error(ResultEnum.NO_LOGIN.getCode(), ResultEnum.NO_LOGIN.getMsg());
httpServletResponse.setStatus(401);
JSONResponseUtils.build(httpServletResponse, response);
}
}

View File

@@ -0,0 +1,25 @@
package com.mixi.common.security;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* @author: dangweijian
* @description: 认证管理器
* @create: 2020-07-10 15:58
**/
@Component
public class UserAuthenticationManager implements AuthenticationManager {
@Resource
private UserAuthenticationProvider userAuthenticationProvider;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
return userAuthenticationProvider.authenticate(authentication);
}
}

View File

@@ -0,0 +1,59 @@
package com.mixi.common.security;
import com.mixi.common.config.RsaProperties;
import com.mixi.common.utils.RsaDecryptUtils;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
/**
* @author: dangweijian
* @description: 登录校验处理类
* @create: 2020-07-09 14:39
**/
@Component
public class UserAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userName = (String) authentication.getPrincipal();
String password = (String) authentication.getCredentials();
try {
password = RsaDecryptUtils.decrypt(password, RsaProperties.privateKey);
} catch (Exception e) {
throw new BadCredentialsException("用户名或密码错误");
}
// User user = userService.getByUsername(userName);
// if (user == null) {
// throw new UsernameNotFoundException("用户名或密码错误");
// }
// //账号已冻结
// if(user.getStatus() == 1){
// throw new LockedException("账号已冻结");
// }
// if(!passwordEncoder.matches(password, user.getPassword())){
// throw new BadCredentialsException("用户名或密码错误");
// }
// //超级管理员
// Set<SimpleGrantedAuthority> authorities = new HashSet<>();
// if(user.getIsAdmin()) {
// authorities.add(new SimpleGrantedAuthority("admin"));
// return new UsernamePasswordAuthenticationToken(user, password, authorities);
// }else {
// List<RoleMenuDto> userMenus = menuService.getRoleMenusByUserId(user.getId(), null);
// if(CollUtil.isNotEmpty(userMenus)){
// authorities.addAll(userMenus.stream().map(RoleMenuDto::getPermission).filter(StringUtils::isNotEmpty).map(SimpleGrantedAuthority::new).collect(Collectors.toSet()));
// }
// return new UsernamePasswordAuthenticationToken(user, password, authorities);
// }
return null;
}
@Override
public boolean supports(Class<?> aClass) {
return UsernamePasswordAuthenticationToken.class.isAssignableFrom(aClass);
}
}

View File

@@ -0,0 +1,48 @@
package com.mixi.common.security;
import com.mixi.common.response.Response;
import com.mixi.common.response.ResultEnum;
import com.mixi.common.utils.JSONResponseUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.*;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @ClassName UserLoginFailureHandler
* @Description 登录失败处理类
* @Author dwjian
* @Date 2020/7/9 20:17
*/
@Slf4j
@Component
public class UserLoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {
Response<String> response;
if (e instanceof UsernameNotFoundException || e instanceof BadCredentialsException) {
response = Response.fail(e.getMessage());
} else if (e instanceof LockedException) {
response = Response.fail(ResultEnum.ACCOUNT_LOCK);
} else if (e instanceof CredentialsExpiredException) {
response = Response.fail("证书过期,请联系管理员!");
} else if (e instanceof AccountExpiredException) {
response = Response.fail("账户过期,请联系管理员!");
} else if (e instanceof DisabledException) {
response = Response.fail("账户被禁用,请联系管理员!");
} else if (e instanceof AuthenticationServiceException) {
response = Response.fail(e.getMessage());
} else {
log.error("登录失败:", e);
response = Response.fail("登录失败!");
}
JSONResponseUtils.build(httpServletResponse,response);
}
}

View File

@@ -0,0 +1,51 @@
package com.mixi.common.security;
import com.mixi.common.response.Response;
import com.mixi.common.response.ResultEnum;
import com.mixi.common.security.jwt.JWTTokenHelper;
import com.mixi.common.utils.JSONResponseUtils;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author: dangweijian
* @description: 登录成功处理类
* @create: 2020-07-09 14:58
**/
@Component
public class UserLoginSuccessHandler implements AuthenticationSuccessHandler {
@Resource
private JWTTokenHelper jwtTokenHelper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
// User user = (User) authentication.getPrincipal();
// AuthPrincipalVo principal = new AuthPrincipalVo();
// BeanUtils.copyProperties(user, principal);
// // 获取用户角色
// List<UserRoleDto> userRoles = roleService.getUserRoles(user.getId(), 0);
// principal.setRoles(userRoles);
// // 获取角色部门
// if(CollUtil.isNotEmpty(userRoles)){
// principal.setDepts(deptService.getDeptByRoleIds(userRoles.stream().map(UserRoleDto::getRoleId).collect(Collectors.toList())));
// }
// // 用户角色权限
// List<String> authorities = new ArrayList<>(authentication.getAuthorities()).stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList());
// principal.setAuthorities(authorities);
// AuthVo authVo = new AuthVo();
// authVo.setAuthorities(authorities);
// authVo.setToken(jwtTokenHelper.createToken(principal));
// authVo.setPrincipal(principal);
// user.setLastLoginTime(new Date());
// userService.updateById(user);
JSONResponseUtils.build(response, Response.success(ResultEnum.SUCCESS.getCode(), ResultEnum.SUCCESS.getMsg(), null));
}
}

View File

@@ -0,0 +1,34 @@
package com.mixi.common.security;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.io.Serializable;
/**
* @ClassName UserPermissionEvaluator
* @Description 权限校验处理器
* @Author dwjian
* @Date 2020/7/12 10:16
*/
@Component
public class UserPermissionEvaluator implements PermissionEvaluator {
@Override
public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) {
System.out.println(authentication);
System.out.println(targetUrl);
System.out.println(permission);
return false;
}
@Override
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
System.out.println(authentication);
System.out.println(targetId);
System.out.println(targetType);
System.out.println(permission);
return false;
}
}

View File

@@ -0,0 +1,79 @@
package com.mixi.common.security.config;
import com.mixi.common.security.*;
import com.mixi.common.security.*;
import com.mixi.common.security.filter.AuthenticationFilter;
import com.mixi.common.security.filter.UserAuthenticationProcessingFilter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import javax.annotation.Resource;
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableConfigurationProperties(SecurityProperties.class)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private SecurityProperties securityProperties;
@Resource
private UserLoginSuccessHandler userLoginSuccessHandler;
@Resource
private UserLoginFailureHandler userLoginFailureHandler;
@Resource
private UserAuthAccessDeniedHandler userAuthAccessDeniedHandler;
@Resource
private UserAuthenticationEntryPointHandler userAuthenticationEntryPointHandler;
@Resource
private UserAuthenticationManager userAuthenticationManager;
@Resource
private UserAuthenticationProcessingFilter userAuthenticationProcessingFilter;
@Resource
private AuthenticationFilter authenticationFilter;
@Resource
private UserPermissionEvaluator userPermissionEvaluator;
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return this.userAuthenticationManager;
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.cors().disable()//禁用 CSRF
.authorizeRequests()//认证请求
.antMatchers(securityProperties.getIgnorePaths()).permitAll()//忽略的请求
.anyRequest().authenticated()//其余所有的请求都需要认证
.and().headers().frameOptions().disable()// 防止iframe 造成跨域
.and().exceptionHandling().authenticationEntryPoint(userAuthenticationEntryPointHandler)//未登录请求处理
.accessDeniedHandler(userAuthAccessDeniedHandler)//无权限访问处理类 (此配置可以忽略全局异常会先于Security框架处理异常全局异常已特殊处理)
.and().formLogin().loginProcessingUrl(securityProperties.getAuthApi())//指定认证接口
.successHandler(userLoginSuccessHandler)//登录成功处理器
.failureHandler(userLoginFailureHandler)//登录失败处理器
.and().cors().and().csrf().disable();//允许跨域
//自定义过滤器在登录时认证用户名、密码
httpSecurity.addFilterAt(userAuthenticationProcessingFilter, UsernamePasswordAuthenticationFilter.class)
.addFilterBefore(authenticationFilter, BasicAuthenticationFilter.class);
//不创建session会话
httpSecurity.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
//取消头缓存控制
httpSecurity.headers().cacheControl();
}
@Bean
public DefaultWebSecurityExpressionHandler userSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler handler = new DefaultWebSecurityExpressionHandler();
handler.setPermissionEvaluator(userPermissionEvaluator);
return handler;
}
}

View File

@@ -0,0 +1,26 @@
package com.mixi.common.security.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
/**
* @author: dangweijian
* @description: JWT配置类
* @create: 2020-07-09 09:38
**/
@Data
@ConfigurationProperties(prefix = "spring.security")
public class SecurityProperties {
private String jwtSecret;
private String jwtTokenHeader;
private String jwtTokenPrefix;
private long jwtExpiration;
private String[] ignorePaths;
private String authApi;
}

View File

@@ -0,0 +1,121 @@
package com.mixi.common.security.filter;
import cn.hutool.core.util.StrUtil;
import com.mixi.common.context.UserContext;
import com.mixi.common.security.config.SecurityProperties;
import com.mixi.common.security.jwt.JWTTokenHelper;
import com.mixi.common.utils.LocalCacheUtils;
import com.mixi.common.utils.MultiReadHttpServletRequest;
import com.mixi.common.utils.MultiReadHttpServletResponse;
import com.mixi.model.vo.AuthPrincipalVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.util.StopWatch;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;
import javax.annotation.Resource;
import javax.security.sasl.AuthenticationException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
/**
* @author: dangweijian
* @description: 认证拦截器
* @create: 2020-07-10 16:50
**/
@Slf4j
@Configuration
public class AuthenticationFilter extends OncePerRequestFilter {
@Resource
private JWTTokenHelper jwtTokenHelper;
@Resource
private SecurityProperties properties;
private static final List<String> FILTER_URL =
Arrays.asList("/favicon.ico","/doc.html","api/account/login","api/account/resetPwd",
"/webjars/","/swagger-resources","/v2/api-docs",
"/api/python/saveGeneratePicture", "/api/python/getLibraryByUserId","/api/element/initDefaultSysFile"
,"api/app/account/login","api/app/account/resetPwd");
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, @NonNull HttpServletResponse httpServletResponse, @NonNull FilterChain filterChain) throws ServletException, IOException {
String requestURI = httpServletRequest.getRequestURI();
if(calculateUrl(requestURI)){
StopWatch stopWatch = new StopWatch();
HttpServletRequest wrappedRequest = httpServletRequest;
HttpServletResponse wrappedResponse = httpServletResponse;
try{
stopWatch.start();
if ((httpServletRequest.getContentType() == null && httpServletRequest.getContentLength() > 0) || (httpServletRequest.getContentType() != null && !httpServletRequest.getContentType().contains("application/json"))) {
extracted(wrappedRequest);
filterChain.doFilter(wrappedRequest, wrappedResponse);
}else {
wrappedRequest = new MultiReadHttpServletRequest(httpServletRequest);
wrappedResponse = new MultiReadHttpServletResponse(httpServletResponse);
extracted(wrappedRequest);
filterChain.doFilter(wrappedRequest, wrappedResponse);
}
} catch (Exception e) {
SecurityContextHolder.clearContext();
throw e;
} finally {
stopWatch.stop();
}
}else {
filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
private Boolean calculateUrl(String requestURI ){
String filterUrl = FILTER_URL.stream().filter(url ->requestURI.contains(url)).findFirst().orElse(null);
return null == filterUrl ? Boolean.TRUE :Boolean.FALSE;
}
private void extracted(HttpServletRequest request) throws AuthenticationException {
String jwtToken = request.getHeader(properties.getJwtTokenHeader());
log.debug("后台检查令牌:{}", jwtToken);
if (StrUtil.isBlank(jwtToken)) {
throw new RuntimeException("请传入token");
}
// 检查token
boolean validate = jwtTokenHelper.validateToken(jwtToken);
if(validate){
AuthPrincipalVo principal = jwtTokenHelper.parserToUser(jwtToken);
if (principal == null) {
throw new RuntimeException("TOKEN已过期请重新登录");
}
//先清空当前线程变量,防止上一个线程遗留
UserContext.delete();
//存取用户信息到缓存
UserContext.setUserHolder(principal);
//校验token
String cacheToken = LocalCacheUtils.getTokenCache(String.valueOf(principal.getId()));
if(StringUtils.isEmpty(cacheToken)){
//兼容app端
cacheToken = LocalCacheUtils.getTokenCache("APP_"+principal.getId());
}
if(jwtToken.equals("Bearer-eyJhbGciOiJIUzUxMiJ9.eyJqdGkiOiIxIiwic3ViIjoie1wiaWRcIjoxLFwidXNlcm5hbWVcIjpcInlhbmdsZWlcIn0iLCJpYXQiOjE2NzgyNjQwNzMsImlzcyI6IkRXSiIsImF1dGhvcml0aWVzIjoiW10iLCJleHAiOjE2ODY5MDQwNzN9.wHDZWC90sXxom16QUW9MoYXhSr00FXEkRMy6DtsCATCa68PCgIORRXfjoVH9QXPoSVLNYkGKMjG3FR1MjAQ7Pg")){
//写死 暂时放行
return;
}
if(StringUtils.isEmpty(cacheToken)){
throw new RuntimeException("TOKEN已过期请重新登录");
}
//按照同一用户原则,不比较token了 app端和web端用一个做
// if(!cacheToken.equals(jwtToken) ){
// throw new RuntimeException("TOKEN已过期请重新登录");
// }
// UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(null, null);
// SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}

View File

@@ -0,0 +1,69 @@
package com.mixi.common.security.filter;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONObject;
import com.mixi.common.security.UserAuthenticationManager;
import com.mixi.common.security.UserLoginFailureHandler;
import com.mixi.common.security.UserLoginSuccessHandler;
import com.mixi.common.security.config.SecurityProperties;
import com.mixi.common.utils.MultiReadHttpServletRequest;
import com.mixi.common.utils.RedisCacheUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author: dangweijian
* @description: 用户认证过滤器
* @create: 2020-07-10 15:58
**/
@Slf4j
@Component
public class UserAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {
/**
* @param securityProperties 配置从配置中读取登录url
* @param authenticationManager 认证管理器
* @param adminAuthenticationSuccessHandler 认证成功处理器
* @param adminAuthenticationFailureHandler 认证失败处理器
*/
public UserAuthenticationProcessingFilter(SecurityProperties securityProperties, UserAuthenticationManager authenticationManager, UserLoginSuccessHandler adminAuthenticationSuccessHandler, UserLoginFailureHandler adminAuthenticationFailureHandler) {
super(new AntPathRequestMatcher(securityProperties.getAuthApi(), HttpMethod.POST.name()));
this.setAuthenticationManager(authenticationManager);
this.setAuthenticationSuccessHandler(adminAuthenticationSuccessHandler);
this.setAuthenticationFailureHandler(adminAuthenticationFailureHandler);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (request.getContentType() == null || !request.getContentType().contains("application/json")) {
throw new AuthenticationServiceException("请求头类型不支持: " + request.getContentType());
}
UsernamePasswordAuthenticationToken authRequest;
try {
MultiReadHttpServletRequest wrappedRequest = new MultiReadHttpServletRequest(request);
// 将前端传递的数据转换成jsonBean数据格式
JSONObject jsonObject = JSONObject.parseObject(wrappedRequest.getBodyJsonStrByJson(wrappedRequest));
String code = jsonObject.getString("code");
String uuid = jsonObject.getString("uuid");
if (StrUtil.isEmpty(code) || StrUtil.isEmpty(uuid) || !code.equals(RedisCacheUtils.get("code-key-" + uuid, String.class))) {
throw new AuthenticationServiceException("验证码错误");
}
RedisCacheUtils.delete("code-key-" + uuid);
authRequest = new UsernamePasswordAuthenticationToken(jsonObject.get("username"), jsonObject.get("password"), null);
authRequest.setDetails(authenticationDetailsSource.buildDetails(wrappedRequest));
} catch (Exception e) {
throw new AuthenticationServiceException(e.getMessage());
}
return this.getAuthenticationManager().authenticate(authRequest);
}
}

View File

@@ -0,0 +1,68 @@
package com.mixi.common.security.jwt;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.mixi.common.security.config.SecurityProperties;
import com.mixi.model.vo.AuthPrincipalVo;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
/**
* @author: dangweijian
* @description: JWT工具
* @create: 2020-07-09 09:27
**/
@Slf4j
@Component
public class JWTTokenHelper {
@Resource
private SecurityProperties securityProperties;
private static final String ISSUER = "DWJ";
private static final String AUTHORITIES = "authorities";
public String createToken(AuthPrincipalVo principal){
String token = Jwts.builder()
.setId(String.valueOf(principal.getId()))
.setSubject(JSONObject.toJSONString(principal))
.setIssuedAt(new Date())
.setIssuer(ISSUER)
.claim(AUTHORITIES, JSON.toJSONString(new ArrayList<>()))//自定义属性 权限
.setExpiration(new Date(System.currentTimeMillis() + securityProperties.getJwtExpiration()))
.signWith(SignatureAlgorithm.HS512, securityProperties.getJwtSecret())
.compact();
token = securityProperties.getJwtTokenPrefix() + token;
return token;
}
public boolean validateToken(String token){
Claims claims = parser(token);
if (MapUtil.isEmpty(claims)){
return false;
}
return true;
}
public AuthPrincipalVo parserToUser(String token){
String subject = parser(token).getSubject();
if(StrUtil.isNotEmpty(subject)){
return JSONObject.parseObject(subject, AuthPrincipalVo.class);
}
return null;
}
public Claims parser(String token) {
token = token.replaceAll(securityProperties.getJwtTokenPrefix(),"");
return Jwts.parser().setSigningKey(securityProperties.getJwtSecret()).parseClaimsJws(token).getBody();
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,35 @@
package com.mixi.common.tasks.mituExportEntity;
import lombok.Data;
import java.util.Date;
@Data
public class CustomerData {
private String mbrCode;
private String mbrName;
private String mbrMobile;
private String mbrGroup;
private String mbrStatus;
private Date joinDate;
private String mbrIssue;
private int birthMonth;
private String mbrSex;
private double offBonus;
private double effBonus;
private double sumBonus;
private double thisMonth;
private double month1;
private double month2;
private double month3;
private double month4;
private double month5;
private double month6;
private double month7;
private double month8;
private double month9;
private double month10;
private double month11;
private double month12;
}

View File

@@ -0,0 +1,10 @@
package com.mixi.common.tasks.mituExportEntity;
import lombok.Data;
@Data
public class MiTuProductStock {
private String whCode;
private String size;
private Integer num;
}

View File

@@ -0,0 +1,162 @@
package com.mixi.common.tasks.mituExportEntity;
import lombok.Data;
import java.sql.Date;
import java.sql.Timestamp;
@Data
public class TransactionData {
private String trxNo;
private Timestamp trxDate;
private String trxType;
private String trxStatus;
private double trxTotQty;
private String currCode;
private double exchRate;
private double discountPerc;
private double trxAccAmt;
private double trxBasAmt;
private double outstandAmt;
private double receiveAmt;
private double changeAmt;
private double trxTotBonus;
private String depositNo;
private double depositAmt;
private String depositStatus;
private String trxAmtDesc;
private String remark;
private String shCode;
private String whCodeFrom;
private String whCodeTo;
private String issuedBy;
private String clientCode;
private String clientName;
private String salesmanCode;
private String ctypeCode;
private Timestamp updatedOn;
private String docType;
private String refNo;
private String adjType;
private String refType;
private String orderNo;
private String recoverF;
private String recoverT;
private String requestBy;
private String error;
private Timestamp authorizedDate;
private String authorizedBy;
private String changeCurrCode;
private double chgRate;
private String cashier;
private String cashiNo;
private String salesmanCode2;
private String classId;
private double disAmt;
private String acStatus;
private String reprint;
private String alt1;
private String alt2;
private String alt3;
private String alt4;
private String alt5;
private Date altD1;
private Date altD2;
private Date altD3;
private Date altD4;
private Date altD5;
private String salesmanCode3;
private String contractNo;
private Timestamp expireDate;
private double depositNetAmt;
private String clientRestriction;
private String refStatus;
private double mbrDis;
private double pmtDiscount;
private double pmtAmount;
private String pmtNo;
private String refCode;
private String docApproved;
private String refractionNo;
private double ccpTot;
private double ccpRed;
private double ccpExpired;
private int printedTimes;
private String pickupShop;
private Date deliveryDate;
private String deliveryTime;
private String wsCode;
private String clCode;
private String clDesc;
private String ratio;
private String userMember;
private String hflag;
private String issueShop;
private String hoUpdBy;
private Timestamp hoUpdOn;
private double bonusExpired;
private double bonusRed;
private Timestamp confirmedOn;
private String confirmedBy;
private String docConfirmed;
private String brNo;
private double changeAmt2;
private Date salesDate;
private String mbrName;
private String canEntryDis;
private String reactiveClient;
private String reactiveMbr;
private String shUpdBy;
private Timestamp shUpdOn;
private double tax1;
private double tax2;
private double tax3;
private double tax4;
private double tax5;
private String altChar1;
private String altChar2;
private String altChar3;
private String altChar4;
private String altChar5;
private double altNum1;
private double altNum2;
private double altNum3;
private double altNum4;
private double altNum5;
private String newClient;
private String newMbr;
private double pmtExtraDiscount;
private double pmtExtraAmount;
private double manualDiscount;
private double manualAmount;
private double usermbrDiscount;
private double clientDiscount;
private String holdVoid;
private double payBasAmt;
private String payDesc;
private String payCode;
private String cardNo;
private String payCurr;
private double payCurrAmt;
private String onbehalfPaid;
private String onbehalfLoc;
private String oldCardNo;
private int trxYear;
private int trxMonth;
private double sumAmt;
private double thisMonth;
private double month1;
private double month2;
private double month3;
private double month4;
private double month5;
private double month6;
private double month7;
private double month8;
private double month9;
private double month10;
private double month11;
private double month12;
}

View File

@@ -0,0 +1,53 @@
package com.mixi.common.tasks.mituExportEntity;
import lombok.Data;
import java.util.Date;
@Data
public class TransactionNewCustomer {
private Date trxDate;
private String shCode;
private String trxType;
private String trxNo;
private String docType;
private String salesmanCode;
private String salesmanName;
private String vipGroup;
private String vipGrade;
private double salesQty;
private double salesAmt;
private String userMember;
private String mbrName;
private String remark;
private String nationality;
private double balanceAmt;
private double shareBalanceAmt;
private String trxStatus;
private int trxYear;
private int trxMonth;
private int trxDay;
private int trxHour;
private int trxMinute;
private String crnoteStatus;
private double nonshareBalanceAmt;
private double netBalanceAmt;
private String mbrStatus;
private String mbrMobile;
private String mbrPhone;
private String mbrId;
private String mbrAdd;
private String mbrEmail;
private String mbrGroup;
private Date joinDate;
private Date mbrExpireOn;
private String mbrIssue;
private String memberType;
private String birthMonth;
private String mbrRemark;
private String mbrPager;
private String oldCardNo;
private double sumPayBasAmt;
}

View File

@@ -0,0 +1,32 @@
package com.mixi.common.tasks.mituExportEntity;
import lombok.Data;
import java.util.Date;
@Data
public class TransactionSummary {
private String PLU_CODE;
private String ItemName;
private String CATEGORY;
private String SUB_CAT;
private int totalSaleNum;
private int retailOnHand;
private double priceOriginal;
private int MAS_count;
private int MEL_count;
private int MPC_count;
private int MPS_count;
private int MTF_count;
private int MWP_count;
private int MYO_count;
private Date toShopDate;
private int salesDay;
private int toRetailQty;
// private int ttlSalesQty;
private int lwSalesQty;
private String salesRate;
}

View File

@@ -0,0 +1,38 @@
package com.mixi.common.tasks.mituExportEntity;
import lombok.Data;
@Data
public class WeeklyHeavyStock {
private String PLU_CODE;
private String item_name;
private String item_barcode;
private String cat;
private String sub_cat;
private String Col;
private String Size;
private double price_sales;
private int MAS;
private int MEL;
private int MPC;
private int MPS;
private int MTF;
private int MWP;
private int MYO;
private int MHZ;
private int MRT;
private int MBZ;
private int TLT;
private int subtotal;
private int G_TLT;
private String SH_CODE;
private int MASSOLD;
private int MELSOLD;
private int MPCSOLD;
private int MPSSOLD;
private int MTFSOLD;
private int MWPSOLD;
private int MYOSOLD;
}

View File

@@ -0,0 +1,41 @@
package com.mixi.common.utils;
import com.mixi.common.config.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
/**
* 流量访问限制工具类
*/
@Slf4j
public class AccessLimitUtils {
/**
* 校验是否超过指定流量限制
*
* @param interfaceName
* @return
*/
public static void validate(String interfaceName, Integer count) {
Integer useCount = LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName);
if (useCount > count) {
//系统繁忙
throw new BusinessException("system busy !");
} else {
useCount++;
LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName, useCount);
}
}
/**
* 校验过后 接口完毕 去掉限流
*
* @param interfaceName
* @return
*/
public static void validateOut(String interfaceName) {
Integer useCount = LocalCacheUtils.getAidaInterfaceCurrentLimitingCache(interfaceName);
useCount--;
LocalCacheUtils.setAidaInterfaceCurrentLimitingCache(interfaceName, useCount);
}
}

View File

@@ -0,0 +1,47 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mixi.common.utils;
import java.io.Closeable;
/**
* @author Zheng Jie
* @website https://el-admin.vip
* @description 用于关闭各种连接,缺啥补啥
* @date 2021-03-05
**/
public class CloseUtil {
public static void close(Closeable closeable) {
if (null != closeable) {
try {
closeable.close();
} catch (Exception e) {
// 静默关闭
}
}
}
public static void close(AutoCloseable closeable) {
if (null != closeable) {
try {
closeable.close();
} catch (Exception e) {
// 静默关闭
}
}
}
}

View File

@@ -0,0 +1,68 @@
package com.mixi.common.utils;
import cn.hutool.core.util.StrUtil;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author: dangweijian
* @description: 驼峰下划线处理工具
* @create: 2020-01-02 22:33
**/
public class ConvertUtil {
private static Pattern linePattern = Pattern.compile("_(\\w)");
/**
* 下划线转驼峰
*/
public static String lineToHump(String str) {
str = str.toLowerCase();
Matcher matcher = linePattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, matcher.group(1).toUpperCase());
}
matcher.appendTail(sb);
return sb.toString();
}
/**
* 驼峰转下划线(简单写法,效率低于{@link #humpToLine2(String)})
*/
public static String humpToLine(String str) {
return str.replaceAll("[A-Z]", "_$0").toLowerCase();
}
private static Pattern humpPattern = Pattern.compile("[A-Z]");
/**
* 驼峰转下划线,效率比上面高
*/
public static String humpToLine2(String str) {
Matcher matcher = humpPattern.matcher(str);
StringBuffer sb = new StringBuffer();
while (matcher.find()) {
matcher.appendReplacement(sb, "_" + matcher.group(0).toLowerCase());
}
matcher.appendTail(sb);
return sb.toString();
}
public static String lowerCaseFirstLetter(String str){
if(StrUtil.isNotBlank(str)){
str = str.trim();
String result = str.substring(0, 1).toLowerCase();
if(str.length() > 1){
result += str.substring(1);
}
return result;
}
return null;
}
}

View File

@@ -0,0 +1,127 @@
package com.mixi.common.utils;
import org.apache.logging.log4j.util.BiConsumer;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class CopyUtil {
public static <T> T copyObject(Object source, Class<T> tClass) throws BeansException {
return entityToModel(source, tClass);
}
public static <F, T> List<T> copyList(List<F> source, Class<T> tClass) {
if (source == null || source.isEmpty()) {
return new ArrayList<>();
}
List<T> tList = new ArrayList<>();
for (F f : source) {
T t = entityToModel(f, tClass);
tList.add(t);
}
return tList;
}
public static <F, T> List<T> copyList(List<F> source, Class<T> tClass, BiConsumer<F, T> consumer) {
if (source == null || source.isEmpty()) {
return new ArrayList<>();
}
List<T> tList = new ArrayList<>();
for (F f : source) {
T t = entityToModel(f, tClass);
consumer.accept(f, t);
tList.add(t);
}
return tList;
}
public static List<String> copyListToString(List source, String fieldName) {
List<String> list = new ArrayList<>();
if (null == source || source.isEmpty()) {
return list;
}
for (int i = 0; i < source.size(); i++) {
try {
Class c = source.get(i).getClass();
if (null != c) {
Method methodGetKey = c.getMethod(fieldName);
String key = "" + methodGetKey.invoke(source.get(i));
list.add(key);
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
return list;
}
/**
* 复制对象
*
* @param entity
* @param modelClass
* @param <F>
* @param <T>
* @return
*/
private static <F, T> T entityToModel(F entity, Class<T> modelClass) {
Object model = null;
if (entity == null || modelClass == null) {
return null;
}
try {
model = modelClass.newInstance();
} catch (Exception e) {
//忽略
}
BeanUtils.copyProperties(entity, model);
return (T) model;
}
public static <K, V, F> Map<K, V> listToMap(List<F> list, Class<V> c) {
List<V> vList = CopyUtil.copyList(list, c);
return list2Map(vList, c);
}
public static <K, V, F> Map<K, V> listToMap(List<F> list, Class<V> c, String fieldName) {
List<V> vList = CopyUtil.copyList(list, c);
return list2Map(vList, c, fieldName);
}
public static <K, V> Map<K, V> list2Map(List<V> list, Class<V> c) {
return list2Map(list, c, "getId");
}
public static <K, V> Map<K, V> list2Map(List<V> list, Class<V> c, String fieldName) {
Map<K, V> map = new HashMap<>();
if (list != null) {
try {
Method methodGetKey = c.getMethod(fieldName);
for (int i = 0; i < list.size(); i++) {
V value = list.get(i);
@SuppressWarnings("unchecked")
K key = (K) methodGetKey.invoke(list.get(i));
map.put(key, value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
return map;
}
}

View File

@@ -0,0 +1,65 @@
package com.mixi.common.utils;
import lombok.extern.slf4j.Slf4j;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.TimeZone;
@Slf4j
public class DateUtil {
public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
public static final String YYYYMM = "yyyyMM";
public static final String YYYY_MM_DD = "yyyyMMdd";
/**
* LocalDate -> Date
*/
public static Date asDate(LocalDate localDate) {
return Date.from(localDate.atStartOfDay().atZone(ZoneId.systemDefault()).toInstant());
}
/**
* LocalDateTime -> Date
*/
public static Date asDate(LocalDateTime localDateTime) {
return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant());
}
/**
* date 装 String
* @param date
* @param formatter
* @return
*/
public static String dateToStr(Date date, String formatter) {
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(formatter);
Instant instant = date.toInstant();
ZoneId zoneId = ZoneId.systemDefault();
LocalDateTime localDateTime = LocalDateTime.ofInstant(instant, zoneId);
return dateTimeFormatter.format(localDateTime);
}
/**
* 根据时区获取时间
* @param timeZone "Asia/Tokyo"
* @return
*/
public static Date getByTimeZone(String timeZone) {
String dateStr = dateToStr(new Date(),YYYY_MM_DD_HH_MM_SS);
SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD_HH_MM_SS);
// 设置时区
sdf.setTimeZone(TimeZone.getTimeZone(timeZone));
Date date = null;
try{
date = sdf.parse(dateStr);
}catch (ParseException parseException){
log.error("时间转换异常!",parseException);
}
return date;
}
}

View File

@@ -0,0 +1,266 @@
package com.mixi.common.utils;
import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.mixi.common.config.exception.BusinessException;
import com.mixi.model.vo.FileVO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
public class FileUtil extends cn.hutool.core.io.FileUtil {
private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
/**
* 系统临时目录
* <br>
* windows 包含路径分割符但Linux 不包含,
* 在windows \\==\ 前提下,
* 为安全起见 同意拼装 路径分割符,
* <pre>
* java.io.tmpdir
* windows : C:\Users/xxx\AppData\Local\Temp\
* linux: /temp
* </pre>
*/
public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
/**
* 定义GB的计算常量
*/
private static final int GB = 1024 * 1024 * 1024;
/**
* 定义MB的计算常量
*/
private static final int MB = 1024 * 1024;
/**
* 定义KB的计算常量
*/
private static final int KB = 1024;
/**
* 格式化小数
*/
private static final DecimalFormat DF = new DecimalFormat("0.00");
public static final String IMAGE = "图片";
public static final String TXT = "文档";
public static final String MUSIC = "音乐";
public static final String VIDEO = "视频";
public static final String OTHER = "其他";
/**
* MultipartFile转File
*/
public static File toFile(MultipartFile multipartFile) {
// 获取文件名
String fileName = multipartFile.getOriginalFilename();
// 获取文件后缀
String prefix = "." + getExtensionName(fileName);
File file = null;
try {
// 用uuid作为文件名防止生成的临时文件重复
file = new File(SYS_TEM_DIR + IdUtil.simpleUUID() + prefix);
// MultipartFile to File
multipartFile.transferTo(file);
} catch (IOException e) {
log.error(e.getMessage(), e);
}
return file;
}
// public static void main(String[] args) {
// File file = new File(
// "http://18.162.111.141:5568/download/202211/userFile/collection/Printboard/1/a3c9838c-2171-44d7-af54-c94ee6affcd9print_2.jpg.png");
// FileUtil.getFileSize()
// }
/**
* 获取文件扩展名,不带 .
*/
public static String getExtensionName(String filename) {
if ((filename != null) && (filename.length() > 0)) {
int dot = filename.lastIndexOf('.');
if ((dot > -1) && (dot < (filename.length() - 1))) {
return filename.substring(dot + 1);
}
}
return filename;
}
/**
* inputStream 转 File
*/
static File inputStreamToFile(InputStream ins, String name) {
File file = new File(SYS_TEM_DIR + name);
if (file.exists()) {
return file;
}
OutputStream os = null;
try {
os = new FileOutputStream(file);
int bytesRead;
int len = 8192;
byte[] buffer = new byte[len];
while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
os.write(buffer, 0, bytesRead);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
CloseUtil.close(os);
CloseUtil.close(ins);
}
return file;
}
/**
* 获取文件尺寸
*/
public static FileVO getFileSize(MultipartFile file) {
int width = 0;
int height = 0;
try{
// 图片对象
BufferedImage bufferedImage = ImageIO.read(file.getInputStream());
// 宽度
width = bufferedImage.getWidth();
// 高度
height = bufferedImage.getHeight();
}catch (IOException ioException){
log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
}
return new FileVO(height,width);
}
/**
* 获取文件尺寸
*/
public static FileVO getFileSize(InputStream inputStream) {
int width = 0;
int height = 0;
try{
// 图片对象
BufferedImage bufferedImage = ImageIO.read(inputStream);
// 宽度
width = bufferedImage.getWidth();
// 高度
height = bufferedImage.getHeight();
}catch (IOException ioException){
log.error("获取文件尺寸异常###{}", ExceptionUtil.stacktraceToString(ioException));
}
return new FileVO(height,width);
}
/**
* 获取远程文件流
*/
public static InputStream getOriginFile(String path) {
try{
//远程
URL url = new URL(path);
return url.openStream();
}catch (IOException ioException){
log.error("获取文件尺寸异常###{}###path##{}", ExceptionUtil.stacktraceToString(ioException),path);
throw new BusinessException("get file is failed!");
}
}
/**
* 将文件名解析成文件的上传路径
*/
public static File upload(MultipartFile file, String filePath) {
Date date = new Date();
SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
String suffix = getExtensionName(file.getOriginalFilename());
String nowStr = format.format(date)+"-" ;
try {
String fileName = file.getOriginalFilename();
String path = filePath + fileName;
// getCanonicalFile 可解析正确各种路径
File dest = new File(path).getCanonicalFile();
// 检测是否存在目录
if (!dest.getParentFile().exists()) {
if (!dest.getParentFile().mkdirs()) {
System.out.println("was not successful.");
}
}
// 文件写入
file.transferTo(dest);
return dest;
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return null;
}
/**
* 删除文件
*/
public static boolean delete(String path) {
File file = new File(path);
if (file.exists()) {
return file.delete();
}
return false;
}
/**
* 获取指定文件夹下所有文件,不含文件夹里的文件
*
* @param dirFilePath 文件夹路径
* @return
*/
public static List<File> getAllFile(String dirFilePath) {
if (StrUtil.isBlank(dirFilePath)){
return null;
}
return getAllFile(new File(dirFilePath));
}
/**
* 获取指定文件夹下所有文件,不含文件夹里的文件
*
* @param dirFile 文件夹
* @return
*/
public static List<File> getAllFile(File dirFile) {
// 如果文件夹不存在或着不是文件夹,则返回 null
if (Objects.isNull(dirFile) || !dirFile.exists() || dirFile.isFile()){
return null;
}
File[] childrenFiles = dirFile.listFiles();
if (Objects.isNull(childrenFiles) || childrenFiles.length == 0){
return null;
}
List<File> files = new ArrayList<>();
for (File childFile : childrenFiles) {
// 如果是文件,直接添加到结果集合
if (childFile.isFile()) {
files.add(childFile);
}
//以下几行代码取消注释后可以将所有子文件夹里的文件也获取到列表里
else {
// 如果是文件夹,则将其内部文件添加进结果集合
List<File> cFiles = getAllFile(childFile);
if (Objects.isNull(cFiles) || cFiles.isEmpty()){
continue;
}
files.addAll(cFiles);
}
}
return files;
}
}

View File

@@ -0,0 +1,42 @@
package com.mixi.common.utils;
import com.alibaba.fastjson.JSON;
import com.mixi.common.response.Response;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ServletResponse;
import java.io.PrintWriter;
/**
* @author: dangweijian
* @description: 构造JSON响应工具类
* @Author dwjian
* @Date 2020/7/10 15:51
**/
@Slf4j
public class JSONResponseUtils {
/**
* 使用response输出JSON
*
* @param servletResponse
* @param response
*/
public static void build(ServletResponse servletResponse, Response<?> response) {
PrintWriter out = null;
try {
servletResponse.setCharacterEncoding("UTF-8");
servletResponse.setContentType("application/json");
out = servletResponse.getWriter();
out.println(JSON.toJSONString(response));
} catch (Exception e) {
log.error(e + "输出JSON出错");
} finally {
if (out != null) {
out.flush();
out.close();
}
}
}
}

View File

@@ -0,0 +1,277 @@
package com.mixi.common.utils;
import com.google.common.cache.*;
import com.mixi.model.dto.ProductProcessDTO;
import lombok.extern.slf4j.Slf4j;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
/**
* @author: yanglei
* @description: 本地缓存工具
* @create: 2022-08-11 9:23
**/
@Slf4j
public final class LocalCacheUtils {
/**
* token
*/
private static LoadingCache<String, String> tokenCache = loadTokenCache();
/**
* 邮箱,短信验证码
*/
private static LoadingCache<String, String> emailCache = CacheBuilder.newBuilder()
//设置并发级别为5并发级别是指可以同时写缓存的线程数
.concurrencyLevel(5)
//设置写缓存后一分钟过期
.expireAfterWrite(60, TimeUnit.SECONDS)
//刷新机制 每隔一定时间刷新缓存loader 只有调用get具体的操作才生效(懒加载) 不设置则不刷新
// .refreshAfterWrite(60, TimeUnit.SECONDS)
//设置缓存容器的初始容量为100
.initialCapacity(100)
//设置缓存最大容量10000超过100之后就会按照LRU最近虽少使用算法来移除缓存项
.maximumSize(10000)
//设置要统计缓存的命中率
.recordStats()
//build方法中可以指定CacheLoader在缓存不存在时通过CacheLoader的实现自动加载缓存
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
return RandomsUtil.generateVerifyCode(1000L,9999L);
}
});;
/**
*
*缓存接口这里是LoadingCacheLoadingCache在缓存项不存在时可以自动加载缓存
*/
private static LoadingCache<String, String> loadTokenCache(){
LoadingCache<String, String> tokenCache = CacheBuilder.newBuilder()
.concurrencyLevel(20)
.expireAfterWrite(24*100, TimeUnit.HOURS)
.initialCapacity(100)
.maximumSize(10000)
.recordStats()
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
return "null";
}
});
return tokenCache;
}
/**
* aida 接口限流(先粗暴做)
*/
private static LoadingCache<String, Integer> aidaInterfaceCurrentLimiting = CacheBuilder.newBuilder()
//设置并发级别为5并发级别是指可以同时写缓存的线程数
.concurrencyLevel(20)
//设置写缓存后30天过期
.expireAfterWrite(60*60*24*30, TimeUnit.SECONDS)
//设置缓存容器的初始容量为100
.initialCapacity(5)
//设置缓存最大容量50000超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
.maximumSize(20)
//设置要统计缓存的命中率
.recordStats()
//build方法中可以指定CacheLoader在缓存不存在时通过CacheLoader的实现自动加载缓存
.build(new CacheLoader<String, Integer>() {
@Override
public Integer load(String key) throws Exception {
return 0;
}
});
/**
* 商品文件进度统计
*/
private static LoadingCache<Long, ProductProcessDTO> productProcessCache = CacheBuilder.newBuilder()
//设置并发级别为10并发级别是指可以同时写缓存的线程数
.concurrencyLevel(1000)
//设置写缓存后5分钟过期
.expireAfterWrite(60*30, TimeUnit.SECONDS)
//设置缓存容器的初始容量为100
.initialCapacity(5)
//设置缓存最大容量50000超过50000之后就会按照LRU最近虽少使用算法来移除缓存项
.maximumSize(100)
//设置要统计缓存的命中率
.recordStats()
//build方法中可以指定CacheLoader在缓存不存在时通过CacheLoader的实现自动加载缓存
.build(new CacheLoader<Long, ProductProcessDTO>() {
@Override
public ProductProcessDTO load(Long key) throws Exception {
return new ProductProcessDTO(0,0,"Attribute",0);
}
});
/**
* 添加token本地缓存
* @param key
* @param value
*/
public static void setTokenCache(String key, String value) {
tokenCache.put(key, value);
}
/**
* 获取token本地缓存
* @param key
* @return
*/
public static String getTokenCache(String key) {
try {
String value = tokenCache.get(key);
if ("null".equals(value)) {
return null;
}
return value;
} catch (ExecutionException e) {
log.error("getTokenCache方法错误", e);
}
return null;
}
/**
* 获取token本地缓存
* @param key
* @return
*/
public static void clearTokenCache(String key) {
try {
tokenCache.invalidate(key);
} catch (Exception e) {
log.error("clearTokenCache方法错误", e);
}
}
/**
* 设置本次接口流量数
* @param key
* @param value
*/
public static void setAidaInterfaceCurrentLimitingCache(String key, Integer value) {
aidaInterfaceCurrentLimiting.put(key, value);
}
/**
* 获取本次接口流量数
* @param key
* @return
*/
public static Integer getAidaInterfaceCurrentLimitingCache(String key) {
try {
return aidaInterfaceCurrentLimiting.get(key);
} catch (ExecutionException e) {
log.error("getAidaInterfaceCurrentLimitingCache方法错误", e);
}
return null;
}
/**
* 添加token本地缓存
* @param key
* @param value
*/
public static void setEmailCache(String key, String value) {
emailCache.put(key, value);
}
/**
* 获取验证码本地缓存
* @param key
* @return
*/
public static String getVerifyCodeCache(String key) {
try {
String value = emailCache.get(key);
if ("null".equals(value)) {
return null;
}
return value;
} catch (ExecutionException e) {
log.error("getTokenCache方法错误", e);
}
return null;
}
/**
* 添加商品文件进度统计
* @param key
* @param productProcess
*/
public static void setProductUploadProcessCache(Long key, ProductProcessDTO productProcess) {
productProcessCache.put(key, productProcess);
}
/**
* 获取商品文件进度统计
* @param key
* @return
*/
public static ProductProcessDTO getProductUploadProcessCache(Long key) {
try {
return productProcessCache.get(key);
} catch (ExecutionException e) {
log.error("getProductUploadProcessCache方法错误", e);
}
return null;
}
/**
* 进度统计完后 删除进度
* @param key
* @return
*/
public static void delProductUploadProcessCache(Long key) {
try {
productProcessCache.invalidate(key);
} catch (Exception e) {
log.error("delProductUploadProcessCache方法错误", e);
}
}
/**
* 预签名URL缓存
*/
private static LoadingCache<String, String> presignedUrlCache = CacheBuilder.newBuilder()
.concurrencyLevel(10)
.expireAfterWrite((24 * 60 - 1), TimeUnit.MINUTES)
.initialCapacity(100)
.maximumSize(10000)
.recordStats()
.build(new CacheLoader<String, String>() {
@Override
public String load(String key) throws Exception {
return "null";
}
});
/**
* 添加预签名URL到缓存
*
* @param key URL的唯一标识
* @param value 预签名URL
*/
public static void setPresignedUrlCache(String key, String value) {
presignedUrlCache.put(key, value);
}
/**
* 获取预签名URL
*
* @param key URL的唯一标识
* @return 预签名URL如果不存在则返回null
*/
public static String getPresignedUrlCache(String key) {
try {
String value = presignedUrlCache.get(key);
if ("null".equals(value)) {
return null;
}
return value;
} catch (ExecutionException e) {
log.error("getPresignedUrlCache方法错误", e);
}
return null;
}
}

View File

@@ -0,0 +1,116 @@
package com.mixi.common.utils;
import cn.hutool.core.exceptions.ExceptionUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.DigestUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.math.BigInteger;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* MD5加密工具
*/
@Slf4j
public class MD5Utils {
/**
* MD5加密
*
* @param str
* @return
*/
public static String encrypt(String str) {
byte[] mdBytes = null;
try {
mdBytes = MessageDigest.getInstance("MD5").digest(
str.getBytes());
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException("MD5算法不存在");
}
String mdCode = new BigInteger(1, mdBytes).toString(16);
if (mdCode.length() < 32) {
int a = 32 - mdCode.length();
for (int i = 0; i < a; i++) {
mdCode = "0" + mdCode;
}
}
// 默认返回32位小写
return mdCode;
}
/**
* MD5加密文件
*
* @param file
* @return
*/
public static String encryptFile(MultipartFile file) {
String md5 = null;
try {
md5 = DigestUtils.md5DigestAsHex(file.getInputStream());
} catch (IOException ioException) {
log.error("文件MultipartFile md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException));
}
return md5;
}
/**
* MD5加密文件
*
* @param inputStream
* @return
*/
public static String encryptFile(FileInputStream inputStream) {
String md5 = null;
try {
md5 = DigestUtils.md5DigestAsHex(inputStream);
} catch (IOException ioException) {
log.error("文件MultipartFile md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException));
}
return md5;
}
public static void main(String[] args) throws FileNotFoundException, IOException {
File file1 = new File("/Users/yanglei/Documents/阳磊日报2019-04-23.numbers");
File file2 = new File("/Users/yanglei/Documents/7777.numbers");
FileInputStream fileInputStream1 = new FileInputStream(file1);
FileInputStream fileInputStream2 = new FileInputStream(file2);
String md51 = DigestUtils.md5DigestAsHex(fileInputStream1);
String md52 = DigestUtils.md5DigestAsHex(fileInputStream2);
if (md51.equals(md52)) {
System.out.println(md51);
}
System.out.println("md51==" + md51);
System.out.println("md52==" + md52);
}
/**
* MD5加密文件
*
* @param path
* @return
*/
public static String encryptFile(String path, Boolean isLocal) {
String md5 = null;
try {
InputStream inputStream = null;
if (isLocal) {
File file = new File(path);
inputStream = new FileInputStream(file);
} else {
//远程
inputStream = FileUtil.getOriginFile(path);
}
md5 = DigestUtils.md5DigestAsHex(inputStream);
} catch (IOException ioException) {
log.error("文件File md5加密异常ioException##{}", ExceptionUtil.getThrowableList(ioException));
}
return md5;
}
}

View File

@@ -0,0 +1,419 @@
package com.mixi.common.utils;
import com.mixi.common.config.exception.BusinessException;
import io.minio.*;
import io.minio.errors.MinioException;
import io.minio.http.Method;
import io.minio.messages.DeleteError;
import io.minio.messages.DeleteObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @description minio工具类
* @version3.0
*/
@Component
public class MinioUtil {
@Autowired
private MinioClient minioClient;
/**
* description: 判断bucket是否存在不存在则创建
*
* @return: void
*/
public void existBucket(String name) {
try {
boolean exists = minioClient.bucketExists(BucketExistsArgs.builder().bucket(name).build());
if (!exists) {
minioClient.makeBucket(MakeBucketArgs.builder().bucket(name).build());
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 创建存储bucket
*
* @param bucketName 存储bucket名称
* @return Boolean
*/
public Boolean makeBucket(String bucketName) {
try {
minioClient.makeBucket(MakeBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 删除存储bucket
*
* @param bucketName 存储bucket名称
* @return Boolean
*/
public Boolean removeBucket(String bucketName) {
try {
minioClient.removeBucket(RemoveBucketArgs.builder()
.bucket(bucketName)
.build());
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* description: 上传文件
*
* @param bucketName
* @param path
* @param multipartFile
* @return: java.lang.String
*/
public List<String> uploadBatch(String bucketName, String path, MultipartFile[] multipartFile) {
List<String> names = new ArrayList<>(multipartFile.length);
for (MultipartFile file : multipartFile) {
String fileName = file.getOriginalFilename();
String[] split = fileName.split("\\.");
if (split.length > 1) {
fileName = path + "/" + UUID.randomUUID() + "." + split[1];
} else {
fileName = path + "/" + UUID.randomUUID();
}
InputStream in = null;
try {
in = file.getInputStream();
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(in, in.available(), -1)
.contentType(file.getContentType())
.build()
);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
names.add(fileName);
}
return names;
}
/**
* description: 上传文件
*
* @param bucketName
* @param path
* @param file
* @return: java.lang.String
*/
public String upload(String bucketName, String path, MultipartFile file) {
String fileName = file.getOriginalFilename();
// String[] split = fileName.split("\\.");
fileName = path;
InputStream in = null;
try {
in = file.getInputStream();
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(fileName)
.stream(in, in.available(), -1)
.contentType(file.getContentType())
.build()
);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bucketName + "/" + fileName;
}
public String upload(String bucketName, String path, MultipartFile file, String copy) {
InputStream in = null;
try {
in = file.getInputStream();
minioClient.putObject(PutObjectArgs.builder()
.bucket(bucketName)
.object(path)
.stream(in, in.available(), -1)
.contentType(file.getContentType())
.build()
);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return bucketName + "/" + path;
}
// public String upload(String bucketName, String path, File file) {
// InputStream in = null;
// try {
// in = new FileInputStream(file);
// minioClient.putObject(PutObjectArgs.builder()
// .bucket(bucketName)
// .object(path)
// .stream(in, in.available(), -1)
// .contentType(file.getContentType())
// .build()
// );
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// if (in != null) {
// try {
// in.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// }
// return fileName;
// }
public InputStream download(String bucketName, String objectName) throws MinioException, IOException {
try {
return minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
} catch (InvalidKeyException e) {
throw new RuntimeException(e);
} catch (NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}
public InputStream download(String path) throws MinioException, IOException {
if (!path.contains("/")) {
throw new BusinessException("the.path.is.error");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
String objectName = path.substring(index + 1);
return download(bucketName, objectName);
}
/**
* description: 下载文件
*
* @param path
* @param bucketName
* @return: org.springframework.http.ResponseEntity<byte [ ]>
*/
// public ResponseEntity<byte[]> download(String path, String bucketName) {
// ResponseEntity<byte[]> responseEntity = null;
// InputStream in = null;
// ByteArrayOutputStream out = null;
// try {
// in = minioClient.getObject(GetObjectArgs.builder().bucket(bucketName).object(path).build());
// out = new ByteArrayOutputStream();
// IOUtils.copy(in, out);
// //封装返回值
// byte[] bytes = out.toByteArray();
// HttpHeaders headers = new HttpHeaders();
// try {
// headers.add("Content-Disposition", "attachment;filename=" + URLEncoder.encode(path, "UTF-8"));
// } catch (UnsupportedEncodingException e) {
// e.printStackTrace();
// }
// headers.setContentLength(bytes.length);
// headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
// headers.setAccessControlExposeHeaders(Arrays.asList("*"));
// responseEntity = new ResponseEntity<byte[]>(bytes, headers, HttpStatus.OK);
// } catch (Exception e) {
// e.printStackTrace();
// } finally {
// try {
// if (in != null) {
// try {
// in.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// if (out != null) {
// out.close();
// }
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
// return responseEntity;
// }
/**
* 查看文件对象
*
* @param bucketName 存储bucket名称
* @return 存储bucket内文件对象信息
*/
// public List<ObjectItem> listObjects(String bucketName) {
// Iterable<Result<Item>> results = minioClient.listObjects(
// ListObjectsArgs.builder().bucket(bucketName).build());
// List<ObjectItem> objectItems = new ArrayList<>();
// try {
// for (Result<Item> result : results) {
// Item item = result.get();
// ObjectItem objectItem = new ObjectItem();
// objectItem.setObjectName(item.objectName());
// objectItem.setSize(item.size());
// objectItems.add(objectItem);
// }
// } catch (Exception e) {
// e.printStackTrace();
// return null;
// }
// return objectItems;
// }
/**
* 批量删除文件对象
*
* @param bucketName 存储bucket名称
* @param objects 对象名称集合
*/
public Iterable<Result<DeleteError>> removeObjects(String bucketName, List<String> objects) {
List<DeleteObject> dos = objects.stream().map(e -> new DeleteObject(e)).collect(Collectors.toList());
Iterable<Result<DeleteError>> results = minioClient.removeObjects(RemoveObjectsArgs.builder().bucket(bucketName).objects(dos).build());
return results;
}
public void deleteObject(String bucketName, String objectName) {
try {
minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
System.out.println("Object " + objectName + " successfully removed from bucket " + bucketName);
} catch (Exception e) {
e.printStackTrace();
System.err.println("Error while removing object " + objectName + " from bucket " + bucketName + ": " + e.getMessage());
}
}
public void deleteObject(String path) {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
String objectName = path.substring(index + 1);
deleteObject(bucketName, objectName);
}
/**
* 获取文件的临时URL
*
* @param bucketName 存储桶名称
* @param fileName 文件名
* @param expiry 过期时间(单位:分)
* @return 文件的临时URL如果出现异常则返回null
*/
public String getPresignedUrl(String bucketName, String fileName, int expiry) {
try {
return minioClient.getPresignedObjectUrl(
GetPresignedObjectUrlArgs.builder()
.bucket(bucketName)
.object(fileName)
.expiry(expiry, TimeUnit.MINUTES)
.method(Method.GET)
.build()
);
} catch (MinioException | InvalidKeyException | IOException | NoSuchAlgorithmException e) {
e.printStackTrace();
throw new BusinessException(e.getMessage());
}
}
public String getPresignedUrl(String path, int expiry) {
if (LocalCacheUtils.getPresignedUrlCache(path) != null) {
return LocalCacheUtils.getPresignedUrlCache(path);
} else {
if (!path.contains("/")) {
throw new BusinessException("The path is error!");
}
int index = path.indexOf("/");
String bucketName = path.substring(0, index);
String fileName = path.substring(index + 1);
String presignedUrl = getPresignedUrl(bucketName, fileName, expiry);
LocalCacheUtils.setPresignedUrlCache(path, presignedUrl);
return presignedUrl;
}
}
/**
* 将桶名、文件名从url中分离出来
*
* @param url 带桶名、文件名的url
* @param expiry 图片过期时间
* @return 可以直接访问的minio图片地址
*/
public String splitThenGetPreviewUrl(String url, int expiry) {
String[] parts = url.split("/");
String bucketName = parts[0];
StringBuilder fileName = new StringBuilder();
for (int i = 1; i < parts.length; i++) {
fileName.append(parts[i]);
if (i != parts.length - 1) {
fileName.append("/");
}
}
return getPresignedUrl(bucketName, String.valueOf(fileName), expiry);
}
public boolean doesObjectExist(String bucketName, String objectName) {
try {
minioClient.statObject(
StatObjectArgs.builder()
.bucket(bucketName)
.object(objectName)
.build()
);
return true;
} catch (Exception e) {
// 如果发生异常,说明文件不存在或者出现了其他错误
return false;
}
}
public String getMinioPath(Long accountId, String itemGroup, String subGroup, String originalFilename) {
return accountId + "/" + itemGroup+ "/" + subGroup+ "/" + originalFilename;
}
}

View File

@@ -0,0 +1,170 @@
package com.mixi.common.utils;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
/**
* 多次读写BODY用HTTP REQUEST - 解决流只能读一次问题
*/
@Slf4j
public class MultiReadHttpServletRequest extends HttpServletRequestWrapper {
private final byte[] body;
public MultiReadHttpServletRequest(HttpServletRequest request) {
super(request);
String sessionStream = getBodyString(request);
body = sessionStream.getBytes(StandardCharsets.UTF_8);
}
/**
* 获取请求Body
*
* @param request 请求
* @return Body字符串
*/
private String getBodyString(final ServletRequest request) {
StringBuilder sb = new StringBuilder();
InputStream inputStream = null;
BufferedReader reader = null;
try {
inputStream = cloneInputStream(request.getInputStream());
reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
String line = "";
while ((line = reader.readLine()) != null) {
sb.append(line);
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
if (inputStream != null) {
try {
inputStream.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
if (reader != null) {
try {
reader.close();
}
catch (IOException e) {
e.printStackTrace();
}
}
}
return sb.toString();
}
/**
* 复制输入流
* @param inputStream 请求输入流
* @return 复制出来的输入流
*/
private InputStream cloneInputStream(ServletInputStream inputStream) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len;
try {
while ((len = inputStream.read(buffer)) > -1) {
byteArrayOutputStream.write(buffer, 0, len);
}
byteArrayOutputStream.flush();
}
catch (IOException e) {
e.printStackTrace();
}
return new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
}
@Override
public BufferedReader getReader() {
return new BufferedReader(new InputStreamReader(getInputStream()));
}
@Override
public ServletInputStream getInputStream() {
final ByteArrayInputStream bais = new ByteArrayInputStream(body);
return new ServletInputStream() {
@Override
public int read() {
return bais.read();
}
@Override
public boolean isFinished() {
return false;
}
@Override
public boolean isReady() {
return false;
}
@Override
public void setReadListener(ReadListener readListener) {
}
};
}
/**
* 将前端请求的表单数据转换成json字符串 - 前后端一体的情况下使用
*
* @param request:
* @return: java.lang.String
*/
public static String getBodyJsonStrByForm(ServletRequest request) {
Map<String, Object> bodyMap = new HashMap<>(16);
try {
// 参数定义
String paraName = null;
// 获取请求参数并转换
Enumeration<String> e = request.getParameterNames();
while (e.hasMoreElements()) {
paraName = e.nextElement();
bodyMap.put(paraName, request.getParameter(paraName));
}
} catch (Exception e) {
log.error("请求参数转换错误!", e);
}
return JSONObject.toJSONString(bodyMap);
}
/**
* 将前端传递的json数据转换成json字符串 - 前后端分离的情况下使用
*
* @param request:
* @return: java.lang.String
*/
public static String getBodyJsonStrByJson(ServletRequest request) {
StringBuffer json = new StringBuffer();
String line;
try {
BufferedReader reader = request.getReader();
while ((line = reader.readLine()) != null) {
json.append(line);
}
} catch (Exception e) {
log.error("请求参数转换错误!", e);
}
return json.toString();
}
}

View File

@@ -0,0 +1,77 @@
package com.mixi.common.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
/**
* 多次读写BODY用HTTP RESPONSE - 解决流只能读一次问题
*/
public class MultiReadHttpServletResponse extends HttpServletResponseWrapper {
private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
private HttpServletResponse response;
public MultiReadHttpServletResponse(HttpServletResponse response) {
super(response);
response.setCharacterEncoding("UTF-8");
response.setContentType("application/json");
this.response = response;
}
public byte[] getBody() {
return byteArrayOutputStream.toByteArray();
}
@Override
public ServletOutputStream getOutputStream() {
return new ServletOutputStreamWrapper(this.byteArrayOutputStream, this.response);
}
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(new OutputStreamWriter(getOutputStream(), this.response.getCharacterEncoding()));
}
@Data
@AllArgsConstructor
private static class ServletOutputStreamWrapper extends ServletOutputStream {
private ByteArrayOutputStream outputStream;
private HttpServletResponse response;
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener listener) {
}
@Override
public void write(int b) throws IOException {
this.outputStream.write(b);
}
@Override
public void flush() throws IOException {
if (!this.response.isCommitted()) {
byte[] body = this.outputStream.toByteArray();
ServletOutputStream outputStream = this.response.getOutputStream();
outputStream.write(body);
outputStream.flush();
}
}
}
}

View File

@@ -0,0 +1,34 @@
package com.mixi.common.utils;
import java.lang.reflect.Field;
public class ObjectUtils {
/**
* 判断该对象是否所有属性为空
* 返回ture表示所有属性为null返回false表示不是所有属性都是null
*/
public static boolean isAllFieldNull(Object object) {
boolean flag = true;
Class clazz = object.getClass();
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
//设置属性是可以访问的(私有的也可以)
field.setAccessible(true);
Object value = null;
try {
value = field.get(object);
// 只要有1个属性不为空,那么就不是所有的属性值都为空
if (value != null) {
flag = false;
break;
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
return flag;
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 2019-2020 Zheng Jie
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.mixi.common.utils;
import cn.hutool.core.util.RandomUtil;
import java.text.DecimalFormat;
/**
* @author yanglei
* @description 随机数工具类
* @date 2022-07
**/
public class RandomsUtil {
private static String PREFIX = "ver";
/**
* 生成验证码
*
* @param randomStart
* @param randomEnd
*/
public static String generateVerifyCode(Long randomStart, Long randomEnd) {
return String.valueOf(RandomUtil.randomLong(randomStart,randomEnd));
}
}

View File

@@ -0,0 +1,50 @@
package com.mixi.common.utils;
import cn.hutool.core.util.StrUtil;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* @author: dangweijian
* @description: redis缓存工具
* @create: 2021-01-08 9:23
**/
public final class RedisCacheUtils {
private static RedisTemplate<String, Object> getRedisTemplate(){
return SpringUtils.getBean("redisTemplate");
}
private static <T> RedisTemplate<String, T> getRedisTemplate(Class<T> clazz){
return SpringUtils.getBean("redisTemplate");
}
private static <T> RedisTemplate<String, List<T>> getListRedisTemplate(Class<T> clazz){
return SpringUtils.getBean("redisTemplate");
}
public static <T> T get(String key, Class<T> clazz){
return getRedisTemplate(clazz).opsForValue().get(key);
}
public static <T> List<T> getList(String key, Class<T> clazz){
return getListRedisTemplate(clazz).opsForValue().get(key);
}
public static void set(String key, Object value){
getRedisTemplate().opsForValue().set(key, value);
}
public static void set(String key, Object value, long time, TimeUnit unit){
getRedisTemplate().opsForValue().set(key, value, time, unit);
}
public static boolean delete(String key){
if(StrUtil.isNotEmpty(key)){
return Boolean.TRUE.equals(getRedisTemplate().delete(key));
}
return false;
}
}

View File

@@ -0,0 +1,70 @@
package com.mixi.common.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.*;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
/**
* Rsa解密工具
*/
@Slf4j
public class RsaDecryptUtils {
public static final String PRIVATE_KEY = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJA0JB/XhdVz/rxlt/XI8LmB7WvPhT1ZpoLXaMfg7zNN+jRWOpuYc+NDr17uA07yl9h2FHOZ6aG5eoobyUP13gAopQuS7BJYwrrA0HLJjZuROWPw/djA8uxQQ97q22k7evlnZ4a1mVJRONbzQxUKQEgLM0S7+l699/NIZGyI4+XPAgMBAAECgYBlyjh5tZPGIbP93rtlJqst91XVVU4TCVZtY4qWFOQkTfXAveFu9cVP9fYzx0TUlI+0/1zeYRW20At8s7J1Y3eJhurZTLns+GpbFD2qExZVL9w5hqmn9fvOE4jCP7uTlTzVgT9zDxAvCid8mSVHz4z7MWG3/zrJloWQzE2riqeeyQJBAOiqfE4M5dQPopFKGhJBBWdKYLAK+trfi4iqstMfdndCiExGd0Nlw9/RS21LXZFk7RwCood6Q/XyKyXTZMwbTHUCQQCeqnTXhEhYlnRIHOuGKYGVHEFMrIGhPH0LZ7ZQUBp+q0wzUsCY79D9ppIwJPHggDsyJOZatm5eMtHb0dDEqbCzAkEAmHF72LfirjtATOm8g1FO9Qpqp23KRzZI+la9rE7lE+bn3vIcmnBHEpLTVN0YhXcXVE71psaZWMA/PR1w4brRMQJADJvPHTFN7nxGUVS7ArZZrdfI+KbcxktgRH/BZTB4aoiCTbHNzFmCaiXKiDjnX8fQ7HMyOxM0QhgXxTgvNvGlMQJATbRaCq7Ytw1SpHRuRbThjwkKVuinSX9y8rRhof7vEKTYomhoDoH7ZITWq421kXT81mj66ahtkPBccw1NeOqYCg==";
public static String decrypt(String content, String privateKey) {
byte[] result;
try {
PKCS8EncodedKeySpec pkcs8EncodedKeySpec5 = new PKCS8EncodedKeySpec(Base64.decodeBase64(privateKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PrivateKey privateKeyText = keyFactory.generatePrivate(pkcs8EncodedKeySpec5);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.DECRYPT_MODE, privateKeyText);
result = doLongerCipherFinal(cipher, Base64.decodeBase64(content));
} catch (Exception e) {
log.error("RSA解密失败", e);
return null;
}
return new String(result);
}
private static byte[] doLongerCipherFinal(Cipher cipher, byte[] source) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
out.write(cipher.doFinal(source));
out.close();
return out.toByteArray();
}
/**
* 构建RSA密钥对
* @param args
*/
// public static void main(String[] args) throws NoSuchAlgorithmException {
// KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
// keyPairGenerator.initialize(1024);
// KeyPair keyPair = keyPairGenerator.generateKeyPair();
// RSAPublicKey rsaPublicKey = (RSAPublicKey) keyPair.getPublic();
// RSAPrivateKey rsaPrivateKey = (RSAPrivateKey) keyPair.getPrivate();
// String publicKeyString = Base64.encodeBase64String(rsaPublicKey.getEncoded());
// String privateKeyString = Base64.encodeBase64String(rsaPrivateKey.getEncoded());
// System.out.println("公钥:" + publicKeyString);
// System.out.println("私钥:" + privateKeyString);
// }
/**
* 解密
* @param args
* @throws NoSuchAlgorithmException
*/
public static void main(String[] args) throws Exception {
String privateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJA0JB/XhdVz/rxlt/XI8LmB7WvPhT1ZpoLXaMfg7zNN+jRWOpuYc+NDr17uA07yl9h2FHOZ6aG5eoobyUP13gAopQuS7BJYwrrA0HLJjZuROWPw/djA8uxQQ97q22k7evlnZ4a1mVJRONbzQxUKQEgLM0S7+l699/NIZGyI4+XPAgMBAAECgYBlyjh5tZPGIbP93rtlJqst91XVVU4TCVZtY4qWFOQkTfXAveFu9cVP9fYzx0TUlI+0/1zeYRW20At8s7J1Y3eJhurZTLns+GpbFD2qExZVL9w5hqmn9fvOE4jCP7uTlTzVgT9zDxAvCid8mSVHz4z7MWG3/zrJloWQzE2riqeeyQJBAOiqfE4M5dQPopFKGhJBBWdKYLAK+trfi4iqstMfdndCiExGd0Nlw9/RS21LXZFk7RwCood6Q/XyKyXTZMwbTHUCQQCeqnTXhEhYlnRIHOuGKYGVHEFMrIGhPH0LZ7ZQUBp+q0wzUsCY79D9ppIwJPHggDsyJOZatm5eMtHb0dDEqbCzAkEAmHF72LfirjtATOm8g1FO9Qpqp23KRzZI+la9rE7lE+bn3vIcmnBHEpLTVN0YhXcXVE71psaZWMA/PR1w4brRMQJADJvPHTFN7nxGUVS7ArZZrdfI+KbcxktgRH/BZTB4aoiCTbHNzFmCaiXKiDjnX8fQ7HMyOxM0QhgXxTgvNvGlMQJATbRaCq7Ytw1SpHRuRbThjwkKVuinSX9y8rRhof7vEKTYomhoDoH7ZITWq421kXT81mj66ahtkPBccw1NeOqYCg==";
String decrypt = decrypt("EzAxC/373prww88TXDayIZTvxS3uFAvGhhzLNs+5cOfJU6zm3x/1RA5KcouuWwcYs0bbvNV7zSitLeEGeo23aPUxzr+rsNvCqKHrPNKbcl/oyOFBtOfguVbuHVEy8Q4cpVxfWCd/aEXx9OJXkLEAvlDdDF6SHyKhf+RUmSGEQOg=", privateKey);
System.out.println(decrypt);
}
}

View File

@@ -0,0 +1,46 @@
package com.mixi.common.utils;
import org.apache.tomcat.util.codec.binary.Base64;
import javax.crypto.Cipher;
import java.io.ByteArrayOutputStream;
import java.security.KeyFactory;
import java.security.PublicKey;
import java.security.spec.X509EncodedKeySpec;
/**
* Rsa加密工具
*/
public class RsaEncryptUtils {
/**
* 加密方法
*
* @param content 需要加密的内容
* @param publicKey 公钥
* @return 加密后得到的字符串
* @throws Exception
*/
public static String encrypt(String content, String publicKey) throws Exception {
X509EncodedKeySpec x509EncodedKeySpec2 = new X509EncodedKeySpec(Base64.decodeBase64(publicKey));
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKeyText = keyFactory.generatePublic(x509EncodedKeySpec2);
Cipher cipher = Cipher.getInstance("RSA");
cipher.init(Cipher.ENCRYPT_MODE, publicKeyText);
byte[] result = doLongerCipherFinal(cipher, content.getBytes());
return Base64.encodeBase64String(result);
}
private static byte[] doLongerCipherFinal(Cipher cipher, byte[] source) throws Exception {
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offset = 0;
int totalSize = source.length;
while (totalSize - offset > 0) {
int size = Math.min(cipher.getOutputSize(0) - 11, totalSize - offset);
out.write(cipher.doFinal(source, offset, size));
offset += size;
}
out.close();
return out.toByteArray();
}
}

View File

@@ -0,0 +1,32 @@
package com.mixi.common.utils;
import com.mixi.model.vo.AuthPrincipalVo;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
public class SecurityContextUtils {
public static AuthPrincipalVo getCurrentUser() {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if(authentication != null && authentication.getPrincipal() != null){
return (AuthPrincipalVo) authentication.getPrincipal();
}
return null;
}
public static Long getCurrentUserId() {
AuthPrincipalVo currentUser = getCurrentUser();
if(currentUser != null){
return currentUser.getId();
}
return null;
}
public static String getCurrentUsername() {
AuthPrincipalVo currentUser = getCurrentUser();
if(currentUser != null){
return currentUser.getUsername();
}
return null;
}
}

View File

@@ -0,0 +1,103 @@
package com.mixi.common.utils;
import com.alibaba.fastjson.JSONObject;
import com.mixi.common.config.exception.BusinessException;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.ses.v20201002.SesClient;
import com.tencentcloudapi.ses.v20201002.models.SendEmailRequest;
import com.tencentcloudapi.ses.v20201002.models.SendEmailResponse;
import com.tencentcloudapi.ses.v20201002.models.Template;
import lombok.extern.slf4j.Slf4j;
/**
* 邮件发送类
*/
@Slf4j
public class SendEmailUtil {
/**
* 秘钥id
*/
private static String SECRET_ID = "AKIDylJaZIkunPkZ7OPAermRovlKccLnysVr";
/**
* 秘钥key
*/
private static String SECRET_KEy = "5tQgeLlumPmshFVUCdngIcfXeU4NPAdq";
/**
* 发信地址
*/
private static String SEND_ADDRESS = "intelligent.curtain@w.mbzn360.com";
/**
* 登入主题
*/
public static String LOGIN_SUBJECT = "智能窗帘登入";
/**
* 忘记密码主题
*/
public static String FORGET_PWD_SUBJECT = "智能窗帘忘记密码";
/**
* 注册主题
*/
public static String REGISTER_SUBJECT = "智能窗帘注册";
/**
* 登入操作
*/
public static String LOGIN_OPERATION = "智能窗帘登入操作";
/**
* 忘记密码操作
*/
public static String FORGET_PWD_OPERATION = "智能窗帘忘记密码操作";
/**
* 注册操作
*/
public static String REGISTER_OPERATION = "智能窗帘注册";
/**
* 模板id
*/
private static Long TEMPLATE_ID = 34986L;
public static Boolean send(String receiverAddress,String subject,String operation,String verifyCode) {
try{
// 实例化一个认证对象入参需要传入腾讯云账户secretIdsecretKey,此处还需注意密钥对的保密
// 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
// 实例化一个http选项可选的没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint("ses.tencentcloudapi.com");
// 实例化一个client选项可选的没有特殊需求可以跳过
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
// 实例化要请求产品的client对象,clientProfile是可选的
SesClient client = new SesClient(cred, "ap-hongkong", clientProfile);
// 实例化一个请求对象,每个接口都会对应一个request对象
SendEmailRequest req = new SendEmailRequest();
req.setFromEmailAddress(SEND_ADDRESS);
req.setDestination(new String[]{receiverAddress});
req.setSubject(subject);
req.setTemplate(contractTemplate(operation, verifyCode));
// 返回的resp是一个SendEmailResponse的实例与请求对象对应
SendEmailResponse resp = client.SendEmail(req);
// 输出json格式的字符串回包
log.info("短信发送结果res###{}",SendEmailResponse.toJsonString(resp));
return Boolean.TRUE;
} catch (TencentCloudSDKException e) {
log.info("邮件发送失败###{}",e.toString());
throw new BusinessException(e.getMessage());
}
}
private static Template contractTemplate(String operation,String verifyCode){
Template template = new Template();
template.setTemplateID(TEMPLATE_ID);
JSONObject jsonObject = new JSONObject();
jsonObject.put("operation",operation);
jsonObject.put("code",verifyCode);
template.setTemplateData(jsonObject.toJSONString());
return template;
}
}

View File

@@ -0,0 +1,106 @@
package com.mixi.common.utils;
import com.mixi.common.config.exception.BusinessException;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import com.tencentcloudapi.sms.v20210111.SmsClient;
import com.tencentcloudapi.sms.v20210111.models.*;
import lombok.extern.slf4j.Slf4j;
import org.bouncycastle.util.Arrays;
import java.util.Objects;
/**
* 短信发送类
*/
@Slf4j
public class SendSmsUtil {
/**
* 秘钥id
*/
private static String SECRET_ID = "AKIDylJaZIkunPkZ7OPAermRovlKccLnysVr";
/**
* 秘钥key
*/
private static String SECRET_KEy = "5tQgeLlumPmshFVUCdngIcfXeU4NPAdq";
/**
* sdkAppId
*/
private static String SDK_APP_ID = "1400722195";
/**
* 签名
*/
public static String SIGN_NAME = "深呼吸智能窗帘";
/**
* 忘记密码模板
*/
public static String FORGET_TEMPLATE_ID = "1514353";
/**
* 登入模板
*/
public static String LOGIN_TEMPLATE_ID = "1514349";
/**
* 登入操作
*/
public static String LOGIN_OPERATION = "登入";
/**
* 忘记密码操作
*/
public static String FORGET_PWD_OPERATION = "忘记密码操作";
public static Boolean send(String phone, String templateId, String verifyCode) {
try{
// 实例化一个认证对象入参需要传入腾讯云账户secretIdsecretKey,此处还需注意密钥对的保密
// 密钥可前往https://console.cloud.tencent.com/cam/capi网站进行获取
Credential cred = new Credential(SECRET_ID, SECRET_KEy);
// 实例化一个http选项可选的没有特殊需求可以跳过
HttpProfile httpProfile = new HttpProfile();
httpProfile.setReqMethod("POST");
/* SDK有默认的超时时间非必要请不要进行调整
* 如有需要请在代码中查阅以获取最新的默认值 */
httpProfile.setConnTimeout(60);
/* 指定接入地域域名,默认就近地域接入域名为 sms.tencentcloudapi.com ,也支持指定地域域名访问,例如广州地域的域名为 sms.ap-guangzhou.tencentcloudapi.com */
httpProfile.setEndpoint("sms.tencentcloudapi.com");
/* 非必要步骤:
* 实例化一个客户端配置对象,可以指定超时时间等配置 */
ClientProfile clientProfile = new ClientProfile();
/* SDK默认用TC3-HMAC-SHA256进行签名
* 非必要请不要修改这个字段 */
clientProfile.setSignMethod("HmacSHA256");
clientProfile.setHttpProfile(httpProfile);
/* 实例化要请求产品(以sms为例)的client对象
* 第二个参数是地域信息可以直接填写字符串ap-guangzhou支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8 */
SmsClient client = new SmsClient(cred, "ap-guangzhou",clientProfile);
SendSmsRequest req = new SendSmsRequest();
req.setSmsSdkAppId(SDK_APP_ID);
req.setSignName(SIGN_NAME);
req.setTemplateId(templateId);
//模板参数
String[] templateParamSet = {verifyCode};
req.setTemplateParamSet(templateParamSet);
/* 下发手机号码,采用 E.164 标准,+[国家或地区码][手机号]
* 示例如:+8613711112222 其中前面有一个+号 86为国家码13711112222为手机号最多不要超过200个手机号 */
String[] phoneNumberSet = {phone};
req.setPhoneNumberSet(phoneNumberSet);
//发送短信
SendSmsResponse res = client.SendSms(req);
log.info("短信发送结果res###{}",SendSmsResponse.toJsonString(res));
if(Objects.isNull(res)|| Arrays.isNullOrContainsNull(res.getSendStatusSet())
||(! res.getSendStatusSet()[0].getCode().equals("Ok")) ){
SendStatus message = res.getSendStatusSet()[0];
throw new BusinessException(message.getMessage());
}
// 输出json格式的字符串回包
} catch (TencentCloudSDKException e) {
log.error(e.toString());
return Boolean.FALSE;
}
return Boolean.TRUE;
}
}

View File

@@ -0,0 +1,44 @@
package com.mixi.common.utils;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;
/**
* @ClassName SpringUtils
* @Description springBean工具
* @Author dwjian
* @Date 2020/1/15 17:10
*/
@Component
public class SpringUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public static <T> T getBean(Class<T> clazz) {
return applicationContext.getBean(clazz);
}
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtils.applicationContext = applicationContext;
}
public static <T> T getBean(String beanName) {
if(applicationContext.containsBean(beanName)){
return (T) applicationContext.getBean(beanName);
}else{
return null;
}
}
public static <T> Map<String, T> getBeansOfType(Class<T> baseType){
return applicationContext.getBeansOfType(baseType);
}
public static ApplicationContext getApplicationContext(){
return applicationContext;
}
}

View File

@@ -0,0 +1,89 @@
package com.mixi.common.utils.export;
import com.alibaba.excel.metadata.CellData;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.util.StyleUtil;
import com.alibaba.excel.write.handler.CellWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteTableHolder;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import org.apache.poi.ss.usermodel.*;
import java.util.List;
/**
* @author yanglei
* @date 2023/5/27 21:04
*/
public class ProductCellWriteHandler implements CellWriteHandler {
@Override
public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Row row, Head head, Integer columnIndex, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
}
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
//当前行的第i列
int i = cell.getColumnIndex();
int r = cell.getRowIndex();
// 根据单元格获取workbook
Sheet sheet = cell.getSheet();
sheet.setColumnWidth(i,20*256);
Workbook workbook = sheet.getWorkbook();
if (0 == r) {
// 单元格策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 设置背景颜色白色
//contentWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
// 设置垂直居中为居中对齐
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
// 设置左右对齐为靠左对齐
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 设置单元格上下左右边框为细边框
contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
contentWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
contentWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
contentWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
contentWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle);
cellStyle.setWrapText(true);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//设置前景填充样式
cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());//前景填充色
//设置当前行第i列的样式
cell.getRow().getCell(i).setCellStyle(cellStyle);
} else {
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 设置垂直居中为居中对齐
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 设置单元格上下左右边框为细边框
contentWriteCellStyle.setBorderBottom(BorderStyle.THIN);
contentWriteCellStyle.setBorderLeft(BorderStyle.THIN);
contentWriteCellStyle.setBorderRight(BorderStyle.THIN);
contentWriteCellStyle.setBorderTop(BorderStyle.THIN);
contentWriteCellStyle.setBottomBorderColor(IndexedColors.BLACK.getIndex());
contentWriteCellStyle.setLeftBorderColor(IndexedColors.BLACK.getIndex());
contentWriteCellStyle.setRightBorderColor(IndexedColors.BLACK.getIndex());
contentWriteCellStyle.setTopBorderColor(IndexedColors.BLACK.getIndex());
CellStyle cellStyle = StyleUtil.buildHeadCellStyle(workbook, contentWriteCellStyle);
cellStyle.setWrapText(true);
cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);//设置前景填充样式
cellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());//前景填充色
//设置当前行第i列的样式
cell.getRow().getCell(i).setCellStyle(cellStyle);
}
}
}

View File

@@ -0,0 +1,78 @@
package com.mixi.controller;
import com.mixi.common.response.PageBaseResponse;
import com.mixi.common.response.Response;
import com.mixi.model.dto.*;
import com.mixi.model.vo.AccountLoginVO;
import com.mixi.model.vo.AccountVO;
import com.mixi.service.AccountService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
@Api(tags = "账户")
@Slf4j
@RestController
@RequestMapping("/api/account")
public class AccountController {
@Resource
private AccountService accountService;
@ApiOperation(value = "用户分页列表")
@PostMapping("/queryUserPage")
public Response<PageBaseResponse<AccountVO>> queryUserPage(@Valid @RequestBody QueryAccountPageDTO query) {
return Response.success(accountService.queryUserPage(query));
}
@ApiOperation(value = "添加或编辑账号")
@PostMapping("/saveOrEdit")
public Response<Boolean> saveOrEdit(@Valid @RequestBody AccountEditDTO accountEditDTO) {
return Response.success(accountService.saveOrEdit(accountEditDTO));
}
@ApiOperation(value = "删除账户")
@PostMapping("/delete")
public Response<Boolean> delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) {
return Response.success(accountService.delete(storeDeleteDTO));
}
@ApiOperation(value = "禁用/停用账户")
@PostMapping("/enable")
public Response<Boolean> enableAccount(@Valid @RequestBody AccountEnableDTO accountEnableDTO) {
return Response.success(accountService.enableAccount(accountEnableDTO));
}
@ApiOperation(value = "登入")
@PostMapping("/login")
public Response<AccountLoginVO> login(@Valid @RequestBody AccountLoginDTO accountDTO) {
return Response.success(accountService.login(accountDTO));
}
@ApiOperation(value = "忘记密码")
@PostMapping("/resetPwd")
public Response<Object> resetPwd(@Valid @RequestBody AccountRegisterDTO accountRegisterDTO) {
accountService.forgetPwd(accountRegisterDTO);
return Response.success();
}
@ApiOperation(value = "登出")
@PostMapping("/logout")
public Response<Boolean> logout(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) {
return Response.success( accountService.logout(accountLogoutDTO));
}
@ApiOperation(value = "是否登入")
@PostMapping("/isLogin")
public Response<Boolean> isLogin(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) {
return Response.success( accountService.isLogin(accountLogoutDTO));
}
}

View File

@@ -0,0 +1,68 @@
package com.mixi.controller;
import com.mixi.common.response.Response;
import com.mixi.model.dto.AccountLoginDTO;
import com.mixi.model.dto.AccountLogoutDTO;
import com.mixi.model.dto.AccountRegisterDTO;
import com.mixi.model.dto.AppAccountLoginDTO;
import com.mixi.model.vo.AccountLoginVO;
import com.mixi.model.vo.AppAccountLoginVO;
import com.mixi.model.vo.StoreVO;
import com.mixi.service.AccountService;
import com.mixi.service.StoreService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
@Api(tags = "app端-账户")
@Slf4j
@RestController
@RequestMapping("/api/app/account")
public class AppAccountController {
@Resource
private AccountService accountService;
@Resource
private StoreService storeService;
@ApiOperation(value = "app端登入")
@PostMapping("/login")
public Response<AppAccountLoginVO> login(@Valid @RequestBody AppAccountLoginDTO accountDTO) {
return Response.success(accountService.appLogin(accountDTO));
}
@ApiOperation(value = "忘记密码")
@PostMapping("/resetPwd")
public Response<Object> resetPwd(@Valid @RequestBody AccountRegisterDTO accountRegisterDTO) {
accountService.appForgetPwd(accountRegisterDTO);
return Response.success();
}
@ApiOperation(value = "登出")
@PostMapping("/logout")
public Response<Boolean> logout(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) {
return Response.success(accountService.appLogout(accountLogoutDTO));
}
@ApiOperation(value = "是否登入")
@PostMapping("/isLogin")
public Response<Boolean> isLogin(@Valid @RequestBody AccountLogoutDTO accountLogoutDTO) {
return Response.success(accountService.appIsLogin(accountLogoutDTO));
}
@ApiOperation(value = "下拉-查询当前用户店铺")
@PostMapping("/queryUserStore")
public Response<List<StoreVO>> queryUserStore() {
return Response.success(storeService.queryUserStore(null,null));
}
}

View File

@@ -0,0 +1,98 @@
package com.mixi.controller;
import com.mixi.common.response.PageBaseResponse;
import com.mixi.common.response.Response;
import com.mixi.common.utils.MD5Utils;
import com.mixi.model.dto.*;
import com.mixi.model.vo.*;
import com.mixi.service.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Stream;
@Api(tags = "App端-商品")
@Slf4j
@RestController
@RequestMapping("/api/app/product")
public class AppProductController {
@Resource
private TAttributeTypeService tAttributeTypeService;
@Resource
private TProductService tProductService;
@Resource
private TAppProductService tAppProductService;
@ApiOperation(value = "新品推荐列表")
@PostMapping("/queryNewProductPage")
public Response<PageBaseResponse<AppNewProductVO>> queryNewProductPage(@Valid @RequestBody QueryNewProductPageDTO query) {
return Response.success(tAppProductService.queryAppNewProductPage(query));
}
@ApiOperation(value = "个性化推荐列表")
@PostMapping("/queryRecommendPage")
public Response<PageBaseResponse<AppNewProductVO>> queryRecommendPage(@Valid @RequestBody QueryRecommendPageDTO query) {
return Response.success(tAppProductService.queryRecommendPage(query));
}
@ApiOperation(value = "商品销量排行,取前10个")
@PostMapping("/queryProductSaleRank")
public Response<List<AppProductSaleRankVO>> queryProductSaleRank(@Valid @RequestBody QueryProductRankDTO query) {
return Response.success(tAppProductService.queryProductSaleRank(query));
}
@ApiOperation(value = "相似度搭配,展示相似度前5")
@PostMapping("/productSimilarityMatch")
public Response<List<AppNewProductVO>> productSimilarityMatch(@Valid @RequestBody ProductSimilaDTO query) {
return Response.success(tAppProductService.productSimilarityMatch(query));
}
@ApiOperation(value = "提取主色(默认返回5组主色,前端默认取第一组,识别时候需传5组主色过去python)")
@PostMapping("/colorExtract")
public Response<List<AppProductColorExtractVO>> colorExtract(@Valid @RequestBody ProductColorExtratDTO query) {
return Response.success(tAppProductService.colorExtract(query));
}
@ApiOperation(value = "颜色搭配,展示前5")
@PostMapping("/productColorMatch")
public Response<List<AppNewProductVO>> productColorMatch(@Valid @RequestBody ProductColorDTO query) {
return Response.success(tAppProductService.productColorMatch(query));
}
@ApiOperation(value = "商品详情")
@GetMapping("/detail")
public Response<ProductVO> detail(@ApiParam(value = "商品id") @RequestParam(value = "id") String id) {
return Response.success(tProductService.detail(id));
}
@ApiOperation(value = "检索商品分页列表")
@PostMapping("/searchProductPage")
public Response<PageBaseResponse<AppNewProductVO>> searchProductPage(@Valid @RequestBody SearchProductPageDTO query) {
return Response.success(tAppProductService.searchProductPage(query));
}
@ApiOperation(value = "下拉-查询所有属性值")
@GetMapping("/queryAllAttribute")
public Response<List<AttributeVO>> queryAllAttribute() {
return Response.success(tAttributeTypeService.queryAll());
}
@ApiOperation(value = "app端上传单个文件-要识别的图片(不入库)")
@PostMapping("/uploadFileSingle")
public Response<AppProductSingleUploadVo> uploadFileSingle(@RequestParam("file") MultipartFile file) {
Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()), "Please select a file!");
return Response.success(tAppProductService.singleUploadProduct(file, MD5Utils.encryptFile(file)));
}
}

View File

@@ -0,0 +1,33 @@
package com.mixi.controller;
import com.mixi.common.response.Response;
import com.mixi.model.vo.AttributeVO;
import com.mixi.service.TAttributeTypeService;
import com.mixi.service.TAttributeValueService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jdk.nashorn.internal.objects.annotations.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import java.util.List;
@Api(tags = "python属性值")
@Slf4j
@RestController
@RequestMapping("/api/attribute")
public class AttributeTypeController {
@Resource
private TAttributeTypeService tAttributeTypeService;
@Resource
private TAttributeValueService tAttributeValueService;
@ApiOperation(value = "下拉-查询所有属性值")
@GetMapping("/queryAll")
public Response<List<AttributeVO>> queryAll() {
return Response.success(tAttributeTypeService.queryAll());
}
}

View File

@@ -0,0 +1,61 @@
package com.mixi.controller;
import com.mixi.common.response.Response;
import com.mixi.mapper.entity.TCustomBuriedPointRecord;
import com.mixi.model.dto.CustomBuriedPointDTO;
import com.mixi.model.dto.CustomLogoutDTO;
import com.mixi.model.dto.CustomRegisterDTO;
import com.mixi.model.dto.LabelAddOrEditDTO;
import com.mixi.model.vo.CustomRegisterVO;
import com.mixi.service.TCustomBuriedPointRecordService;
import com.mixi.service.TCustomRegisterService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
/**
* <p>
* 客户登入 前端控制器
* </p>
*
* @author yanglei
* @since 2023-04-01
*/
@Api(tags = "App端-客户")
@Slf4j
@RestController
@RequestMapping("/api/app/custom")
public class CustomController {
@Resource
private TCustomRegisterService tCustomRegisterService;
@Resource
private TCustomBuriedPointRecordService tCustomBuriedPointRecordService;
@ApiOperation(value = "客户登入")
@PostMapping("/register")
public Response<CustomRegisterVO> register(@Valid @RequestBody CustomRegisterDTO customRegisterDTO) {
return Response.success(tCustomRegisterService.register(customRegisterDTO));
}
@ApiOperation(value = "客户登出")
@PostMapping("/logout")
public Response<Object> logout(@Valid @RequestBody CustomLogoutDTO customLogoutDTO) {
tCustomRegisterService.logout(customLogoutDTO);
return Response.success();
}
@ApiOperation(value = "客户数据埋点")
@PostMapping("/buriedPoint")
public Response<Object> buriedPoint(@Valid @RequestBody CustomBuriedPointDTO customBuriedPointDTO) {
tCustomBuriedPointRecordService.buriedPoint(customBuriedPointDTO);
return Response.success();
}
}

View File

@@ -0,0 +1,55 @@
package com.mixi.controller;
import com.mixi.common.response.PageBaseResponse;
import com.mixi.common.response.Response;
import com.mixi.model.dto.*;
import com.mixi.model.vo.AllRoleVO;
import com.mixi.model.vo.LabelVO;
import com.mixi.model.vo.StoreVO;
import com.mixi.service.LabelService;
import com.mixi.service.StoreService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
@Api(tags = "标签管理")
@Slf4j
@RestController
@RequestMapping("/api/label")
public class LabelController {
@Resource
private LabelService labelService;
@ApiOperation(value = "标签分页列表")
@PostMapping("/queryStorePage")
public Response<PageBaseResponse<LabelVO>> queryStorePage(@Valid @RequestBody QueryLabelPageDTO query) {
return Response.success(labelService.queryLabelPage(query));
}
@ApiOperation(value = "新增或编辑标签")
@PostMapping("/saveOrEdit")
public Response<Boolean> saveOrEdit(@Valid @RequestBody LabelAddOrEditDTO labelAddOrEditDTO) {
return Response.success(labelService.saveOrEdit(labelAddOrEditDTO));
}
@ApiOperation(value = "删除标签")
@PostMapping("/delete")
public Response<Boolean> delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) {
return Response.success(labelService.delete(storeDeleteDTO));
}
@ApiOperation(value = "下拉-查询所有商品标签")
@PostMapping("/queryProductLabel")
public Response<List<LabelVO>> queryAll() {
return Response.success(labelService.queryProductLabel());
}
}

View File

@@ -0,0 +1,49 @@
package com.mixi.controller;
import com.mixi.common.response.PageBaseResponse;
import com.mixi.common.response.Response;
import com.mixi.mapper.entity.MiTuExport;
import com.mixi.model.dto.QueryMiTuExportPageDTO;
import com.mixi.model.dto.QueryStorePageDTO;
import com.mixi.model.dto.StoreAddOrEditDTO;
import com.mixi.model.dto.StoreDeleteDTO;
import com.mixi.model.vo.StoreVO;
import com.mixi.service.MiTuExportService;
import com.mixi.service.StoreService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.FileNotFoundException;
import java.util.List;
@Api(tags = "mi-tu报表")
@Slf4j
@RestController
@RequestMapping("/api/miTuExport")
public class MiTuExportController {
@Resource
private MiTuExportService miTuExportService;
@ApiOperation(value = "MiTu报表查询")
@PostMapping("/miTuExportPage")
public Response<PageBaseResponse<MiTuExport>> queryMiTuExportPage(@Valid @RequestBody QueryMiTuExportPageDTO query) {
return Response.success(miTuExportService.queryMiTuExportPage(query));
}
@ApiOperation(value = "下载MiTu报表")
@GetMapping("/export/{id}")
public void exportMiTuReport(@PathVariable Long id, HttpServletResponse response) throws FileNotFoundException {
miTuExportService.exportMiTuReport(id, response);
}
}

View File

@@ -0,0 +1,130 @@
package com.mixi.controller;
import com.mixi.common.response.PageBaseResponse;
import com.mixi.common.response.Response;
import com.mixi.common.utils.MD5Utils;
import com.mixi.model.dto.*;
import com.mixi.model.vo.*;
import com.mixi.service.TProductService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
@Api(tags = "商品管理")
@Slf4j
@RestController
@RequestMapping("/api/product")
public class ProductController {
@Resource
private TProductService tProductService;
@ApiOperation(value = "首页工作台统计")
@GetMapping("/countWorkBench")
public Response<CountWorkBentchVO> countWorkBench(String storeId) {
return Response.success(tProductService.countWorkBench(storeId));
}
@ApiOperation(value = "商品分页列表")
@PostMapping("/queryProductPage")
public Response<PageBaseResponse<ProductVO>> queryProductPage(@Valid @RequestBody QueryProductPageDTO query) {
return Response.success(tProductService.queryProductPage(query));
}
@ApiOperation(value = "商品导出")
@PostMapping("/exportProduct")
public Response<String> exportProduct(@Valid @RequestBody QueryProductPageDTO query) throws IOException {
return Response.successData(tProductService.exportProduct(query));
}
@ApiOperation(value = "商品详情")
@GetMapping("/detail")
public Response<ProductVO> detail(@ApiParam(value = "商品id") @RequestParam(value = "id") String id) {
return Response.success(tProductService.detail(id));
}
@ApiOperation(value = "编辑商品")
@PostMapping("/edit")
public Response<Boolean> edit(@Valid @RequestBody EditProductDTO editProductDTO) {
return Response.success(tProductService.edit(editProductDTO));
}
@ApiOperation(value = "删除商品")
@PostMapping("/delete")
public Response<Boolean> delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) {
return Response.success(tProductService.delete(storeDeleteDTO));
}
@ApiOperation(value = "批量上传商品,前端适配不了 暂时不用")
@PostMapping("/batchUploadProduct")
public Response<TProductBatchUploadVo> batchUploadProduct(@RequestParam("files") MultipartFile[] files,
@ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@RequestParam(value = "timeZone") String timeZone) {
Assert.notNull(files,"Please select a file !");
Assert.isTrue(files.length <=10,"A maximum of 10 images can be uploaded !");
Stream.of(files).forEach(file ->{
Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()),"Please select a file!");
});
return Response.success(tProductService.batchUploadProduct(files,timeZone));
}
@ApiOperation(value = "上传单个文件,保存用")
@PostMapping("/uploadFileSingle")
public Response<TProductSingleUploadVo> uploadFileSingle(@RequestParam("file") MultipartFile file,
@ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@RequestParam(value = "timeZone") String timeZone) {
Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()), "Please select a file!");
return Response.success(tProductService.singleUploadProduct(file, MD5Utils.encryptFile(file),timeZone));
}
@ApiOperation(value = "批量上传商品后传对应的关联信息")
@PostMapping("/batchUploadProductRelation")
public Response<TProductBatchUploadRelationVo> batchUploadProductRelation(@Valid @RequestBody BatchUploadProductDTO product) {
return Response.success(tProductService.batchUploadProductRelation(product));
}
@ApiOperation(value = "商品搭配分页列表")
@PostMapping("/queryProductAssortmentPage")
public Response<PageBaseResponse<ProductAssortmentInnerVO>> queryProductAssortmentPage(@Valid @RequestBody QueryProductAssortmentPageDTO query) {
return Response.success(tProductService.queryProductAssortmentPage(query));
}
@ApiOperation(value = "上传文件,编辑用")
@PostMapping("/uploadFile")
public Response<TProductUploadVo> uploadFile(@RequestParam("file") MultipartFile file,
@ApiParam("本地时区,比如 'Asia/Tokyo' 东京时间 , 'Asia/Shanghai' 北京时间 由js本地获取")
@RequestParam(value = "timeZone") String timeZone,
@ApiParam("商品id") @RequestParam(value = "id") String id) {
Assert.isTrue(!StringUtils.isEmpty(file.getOriginalFilename()), "Please select a file!");
return Response.success(tProductService.upload(file, MD5Utils.encryptFile(file),timeZone,id));
}
@ApiOperation(value = "统计商品批量上传进度")
@PostMapping("/countProductUpdateProcess")
public Response<ProductProcessDTO> countProductUpdateProcess() {
return Response.success(tProductService.countProductUpdateProcess());
}
@ApiOperation(value = "上架/下架商品")
@PostMapping("/doOnSale")
public Response<Boolean> enableAccount(@Valid @RequestBody ProductOnSaleDTO productOnSaleDTO) {
return Response.success(tProductService.enableAccount(productOnSaleDTO));
}
@ApiOperation(value = "获取category")
@GetMapping("/getCategory")
public Response<Set<String>> getCategory(@RequestParam("category") String category) {
return Response.success(tProductService.getCategory(category));
}
}

View File

@@ -0,0 +1,66 @@
package com.mixi.controller;
import com.mixi.common.response.PageBaseResponse;
import com.mixi.common.response.Response;
import com.mixi.model.dto.QueryStorePageDTO;
import com.mixi.model.dto.RoleAddOrEditDTO;
import com.mixi.model.dto.StoreDeleteDTO;
import com.mixi.model.vo.AllRoleVO;
import com.mixi.model.vo.RolePermission1VO;
import com.mixi.model.vo.RoleVO;
import com.mixi.model.vo.StoreVO;
import com.mixi.service.RoleService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
@Api(tags = "角色管理")
@Slf4j
@RestController
@RequestMapping("/api/role")
public class RoleController {
@Resource
private RoleService roleService;
@ApiOperation(value = "角色分页列表")
@PostMapping("/queryRolePage")
public Response<PageBaseResponse<RoleVO>> queryStorePage(@Valid @RequestBody QueryStorePageDTO query) {
return Response.success(roleService.queryRolePage(query));
}
@ApiOperation(value = "查询权限列表")
@GetMapping("/queryPermissionList")
public Response<List<RolePermission1VO>> queryPermissionList() {
return Response.success(roleService.queryPermissionListTemplate());
}
@ApiOperation(value = "新增或编辑角色")
@PostMapping("/saveOrEdit")
public Response<Boolean> saveOrEdit(@Valid @RequestBody RoleAddOrEditDTO roleAddOrEditDTO) {
return Response.success(roleService.saveOrEdit(roleAddOrEditDTO));
}
@ApiOperation(value = "删除标签")
@PostMapping("/delete")
public Response<Boolean> delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) {
return Response.success(roleService.delete(storeDeleteDTO));
}
@ApiOperation(value = "下拉-查询所有角色")
@PostMapping("/queryAll")
public Response<List<AllRoleVO>> queryAll() {
return Response.success(roleService.queryAll());
}
@ApiOperation(value = "查询用户角色权限")
@GetMapping("/queryUsrPermission")
public Response<RoleVO> queryUsrPermission() {
return Response.success(roleService.queryUsrPermission());
}
}

View File

@@ -0,0 +1,62 @@
package com.mixi.controller;
import com.mixi.common.response.PageBaseResponse;
import com.mixi.common.response.Response;
import com.mixi.model.dto.*;
import com.mixi.model.vo.AccountLoginVO;
import com.mixi.model.vo.AccountVO;
import com.mixi.model.vo.LabelVO;
import com.mixi.model.vo.StoreVO;
import com.mixi.service.AccountService;
import com.mixi.service.StoreService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
@Api(tags = "门店管理")
@Slf4j
@RestController
@RequestMapping("/api/store")
public class StoreController {
@Resource
private StoreService storeService;
@ApiOperation(value = "门店分页列表")
@PostMapping("/queryStorePage")
public Response<PageBaseResponse<StoreVO>> queryStorePage(@Valid @RequestBody QueryStorePageDTO query) {
return Response.success(storeService.queryStorePage(query));
}
@ApiOperation(value = "新增或编辑门店")
@PostMapping("/saveOrEdit")
public Response<Boolean> saveOrEdit(@Valid @RequestBody StoreAddOrEditDTO storeAddOrEditDTO) {
return Response.success(storeService.saveOrEdit(storeAddOrEditDTO));
}
@ApiOperation(value = "删除门店")
@PostMapping("/delete")
public Response<Boolean> delete(@Valid @RequestBody StoreDeleteDTO storeDeleteDTO) {
return Response.success(storeService.delete(storeDeleteDTO));
}
@ApiOperation(value = "下拉-查询所有店铺")
@PostMapping("/queryAll")
public Response<List<StoreVO>> queryAll() {
return Response.success(storeService.queryAll());
}
@ApiOperation(value = "下拉-查询所有商品店铺")
@PostMapping("/queryProductStore")
public Response<List<StoreVO>> queryProductStore() {
return Response.success(storeService.queryUserStore(null,null));
}
}

View File

@@ -0,0 +1,14 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TAccount;
/**
* Mapper 接口
*
* @author easy-generator
* @since 2022-06-13
*/
public interface AccountMapper extends CommonMapper<TAccount> {
}

View File

@@ -0,0 +1,15 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.ColorLookupTable;
/**
* Mapper 接口
*
* @author easy-generator
* @since 2022-09-30
*/
public interface ColorLoopUpTableMapper extends CommonMapper<ColorLookupTable> {
}

View File

@@ -0,0 +1,16 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.ColorLookupTable;
import com.mixi.mapper.entity.MiTuExport;
/**
* Mapper 接口
*
* @author easy-generator
* @since 2022-09-30
*/
public interface MiTuExportMapper extends CommonMapper<MiTuExport> {
}

View File

@@ -0,0 +1,15 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.MiTuProduct;
/**
* Mapper 接口
*
* @author easy-generator
* @since 2022-09-30
*/
public interface MiTuProductMapper extends CommonMapper<MiTuProduct> {
}

View File

@@ -0,0 +1,19 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.PanTone;
import com.mixi.model.dto.GetRgbByHsvBatchDTO;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* Mapper 接口
*
* @author easy-generator
* @since 2022-06-13
*/
public interface PanToneMapper extends CommonMapper<PanTone> {
List<PanTone> getRgbByHsvBatch(@Param("rgbByHsvBatch") List<GetRgbByHsvBatchDTO> rgbByHsvBatch);
}

View File

@@ -0,0 +1,17 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TAccount;
/**
* <p>
* 账户表,用户表 Mapper 接口
* </p>
*
* @author generate-auto
* @since 2023-03-06
*/
public interface TAccountMapper extends CommonMapper<TAccount> {
}

View File

@@ -0,0 +1,16 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TAccountStore;
/**
* <p>
* 用户店铺关联表 Mapper 接口
* </p>
*
* @author generate-auto
* @since 2023-03-06
*/
public interface TAccountStoreMapper extends CommonMapper<TAccountStore> {
}

View File

@@ -0,0 +1,18 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TAttributeType;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 属性类型表 Mapper 接口
* </p>
*
* @author yanglei
* @since 2023-03-15
*/
@Mapper
public interface TAttributeTypeMapper extends CommonMapper<TAttributeType> {
}

View File

@@ -0,0 +1,19 @@
package com.mixi.mapper;
import com.mixi.mapper.entity.TAttributeValue;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TAttributeValue;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 属性值表(对应python识别的标签信息) Mapper 接口
* </p>
*
* @author yanglei
* @since 2023-03-15
*/
@Mapper
public interface TAttributeValueMapper extends CommonMapper<TAttributeValue> {
}

View File

@@ -0,0 +1,18 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TCustomBuriedPointRecord;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 客户埋点记录表 Mapper 接口
* </p>
*
* @author yanglei
* @since 2023-04-01
*/
@Mapper
public interface TCustomBuriedPointRecordMapper extends CommonMapper<TCustomBuriedPointRecord> {
}

View File

@@ -0,0 +1,19 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TCustomRegister;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 客户登入记录表 Mapper 接口
* </p>
*
* @author yanglei
* @since 2023-04-01
*/
@Mapper
public interface TCustomRegisterMapper extends CommonMapper<TCustomRegister> {
}

View File

@@ -0,0 +1,16 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TLabel;
/**
* <p>
* 标签表 Mapper 接口
* </p>
*
* @author generate-auto
* @since 2023-03-06
*/
public interface TLablelMapper extends CommonMapper<TLabel> {
}

View File

@@ -0,0 +1,18 @@
package com.mixi.mapper;
import com.mixi.common.config.mybatis.plus.CommonMapper;
import com.mixi.mapper.entity.TProductAssortment;
import org.apache.ibatis.annotations.Mapper;
/**
* <p>
* 商品搭配表 Mapper 接口
* </p>
*
* @author yanglei
* @since 2023-03-15
*/
public interface TProductAssortmentMapper extends CommonMapper<TProductAssortment> {
}

Some files were not shown because too many files have changed in this diff Show More