diff --git a/.gitignore b/.gitignore
index 1a0d65b..452d367 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,35 +1,25 @@
-# Created by .ignore support plugin (hsz.mobi)
-### Java template
-# Compiled class file
-*.class
-
-# Log file
-*.log
-
-# BlueJ files
-*.ctxt
-
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
-
-# Package Files #
-*.jar
-*.war
-*.nar
-*.ear
-*.zip
-*.tar.gz
-*.rar
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**/target/
+!**/src/test/**/target/
+logs/**
+*/logs/**
-### Example user template template
-### Example user template
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
-# IntelliJ project files
+### IntelliJ IDEA ###
.idea
+*.iws
*.iml
+
out
gen
@@ -45,3 +35,16 @@ uploads/**
.project
.settings
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+!**/src/main/**/build/
+!**/src/test/**/build/
+
+### VS Code ###
diff --git a/open-api/pom.xml b/open-api/pom.xml
new file mode 100644
index 0000000..902a766
--- /dev/null
+++ b/open-api/pom.xml
@@ -0,0 +1,31 @@
+
+
+
+ suimang
+ com.iformall
+ 1.0
+
+ 4.0.0
+
+ open-api
+
+
+
+
+ com.iformall
+ suimangService
+ 1.0
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+
\ No newline at end of file
diff --git a/open-api/src/main/java/com/iformall/OpenApiApplication.java b/open-api/src/main/java/com/iformall/OpenApiApplication.java
new file mode 100644
index 0000000..0cae084
--- /dev/null
+++ b/open-api/src/main/java/com/iformall/OpenApiApplication.java
@@ -0,0 +1,63 @@
+package com.iformall;
+
+import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;
+import org.mybatis.spring.annotation.MapperScan;
+import org.rocketmq.starter.annotation.EnableRocketMQ;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+@SpringBootApplication
+@MapperScan(basePackages = {"com.iformall.mapper"})
+@EnableEncryptableProperties
+@EnableRocketMQ
+@EnableAspectJAutoProxy(exposeProxy = true)
+public class OpenApiApplication {
+
+ @Value("${fm.exception}")
+ private boolean fmException;
+
+ @Value("${fm.exception_emails}")
+ private String fmExceptionEmails;
+
+ @Value("${fm.open}")
+ private boolean fmOpen;
+
+ @Value("${fm.upload_dir}")
+ private String uploadDir;
+
+ @Value("${fm.videoType}")
+ private String videoType;
+
+ @Bean
+ public boolean isFmException() {
+ return fmException;
+ }
+
+ @Bean
+ public String fmExceptionEmails() {
+ return fmExceptionEmails;
+ }
+
+ @Bean
+ public boolean isFmOpen() {
+ return fmOpen;
+ }
+
+ @Bean
+ public String fmUploadDir() {
+ return uploadDir;
+ }
+
+ @Bean
+ public String videoType() {
+ return videoType;
+ }
+
+
+ public static void main(String[] args) {
+ SpringApplication.run(OpenApiApplication.class, args);
+ }
+}
diff --git a/open-api/src/main/java/com/iformall/annotation/RedisCache.java b/open-api/src/main/java/com/iformall/annotation/RedisCache.java
new file mode 100644
index 0000000..1857366
--- /dev/null
+++ b/open-api/src/main/java/com/iformall/annotation/RedisCache.java
@@ -0,0 +1,53 @@
+package com.iformall.annotation;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
+
+
+/**
+ * - /api/wxCouponChannel/change
+ * - /api/user/userinfo
+ * - /api/wxBusiness/listAll
+ * - /api/wxCampaign/list
+ * - /api/mall/mallInfo
+ * - /api/mall/getAppIcon
+ * - /api/mall/getWeapNote
+ */
+@Target({ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+public @interface RedisCache {
+
+ /**
+ * 缓存key的名称
+ * @return
+ */
+ String key() default "";
+
+ /**
+ * 自动生成key
+ * @return
+ */
+ boolean autoKey() default true;
+
+ /**
+ * 参数md5,解决key过长问题
+ * @return
+ */
+ boolean md5() default true ;
+
+ /**
+ * key 过期日期默认60秒
+ * @return
+ */
+ int expireTime() default 60;
+
+ /**
+ * 时间单位默认为秒
+ * @return
+ */
+ TimeUnit dateUnit() default TimeUnit.SECONDS;
+}
diff --git a/open-api/src/main/java/com/iformall/aop/RedisCacheAspect.java b/open-api/src/main/java/com/iformall/aop/RedisCacheAspect.java
new file mode 100644
index 0000000..c5bd5b2
--- /dev/null
+++ b/open-api/src/main/java/com/iformall/aop/RedisCacheAspect.java
@@ -0,0 +1,158 @@
+package com.iformall.aop;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.iformall.annotation.RedisCache;
+import com.iformall.domain.po.base.BaseCUserEntity;
+import com.iformall.service.CUserTokenService;
+import com.iformall.utils.HashUtil;
+import com.iformall.utils.RedisLock;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import javax.servlet.http.HttpServletRequest;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Objects;
+
+@Slf4j
+@Aspect
+@Component
+public class RedisCacheAspect {
+
+ /**
+ * 参数分隔符 param1|param2|param3
+ **/
+ private static final String DELIMITER_PARAMS = "|";
+
+ /**
+ * key 分隔符
+ */
+ private static final String DELIMITER_KEY = ":";
+
+ @Autowired
+ private StringRedisTemplate stringRedisTemplate;
+
+ @Autowired
+ RedisLock redisLock;
+
+ @Autowired
+ private CUserTokenService cUserTokenService;
+
+ @Pointcut("@annotation(com.iformall.annotation.RedisCache)")
+ public void cacheAspect() {
+ }
+
+ @Around("cacheAspect()")
+ public Object round(ProceedingJoinPoint jp) throws Throwable {
+ HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
+ // 查询token信息
+ //从header中获取token
+ String token = request.getHeader("token");
+ //如果header中不存在token,则从参数中获取token
+ if (StringUtils.isBlank(token)) {
+ token = request.getParameter("token");
+ }
+ if(StringUtils.isBlank(token) || "null".equals(token) || "undefined".equals(token)){
+ token="";
+ //throw new MallinkException(ErrorCode.NET_TOKEN_EMPTY.getCode(),"token为空["+token+"]");
+ }
+ log.info("token>>>>>>>>>>>>>>>"+token);
+ String tenantId;
+ BaseCUserEntity cUser = null ;
+ if(StringUtils.isNotBlank(token)) {
+ cUser = cUserTokenService.getByToken(token);
+ }
+ if (Objects.isNull(cUser) || cUser.getExpireTime().getTime() < System.currentTimeMillis()) {
+ tenantId = "0";
+ } else {
+ tenantId = cUser.getTenantId();
+ }
+
+ // 请求参数
+ Object[] args = jp.getArgs();
+ // 接口 返回结果
+ Object result;
+ String redisKey;
+
+ //得到注释的名称
+ MethodSignature signature = (MethodSignature) jp.getSignature();
+ //判断tag是否在用户权限中 如果存在加入参数查询
+ Method method = signature.getMethod();
+ RedisCache cache = method.getAnnotation(RedisCache.class) ;
+ if (cache.autoKey()) {
+ // 构建 redisKey => reqPath:tenantId:md5(param1_param2_param3)
+ String requestUrl = request.getRequestURI();
+ // 接口路径 reqPath => /api/xxx
+ String reqPath = requestUrl.substring(requestUrl.indexOf("/api/"));
+ if (cache.md5()) {
+ String md5Before = StringUtils.join(args, DELIMITER_PARAMS);
+ redisKey = StringUtils.join(reqPath, DELIMITER_KEY, tenantId, DELIMITER_KEY, HashUtil.md5(StringUtils.join(token, md5Before, DELIMITER_PARAMS)));
+ } else {
+ redisKey = StringUtils.join(reqPath, DELIMITER_KEY, tenantId, DELIMITER_KEY, StringUtils.join(token,args, DELIMITER_PARAMS));
+ }
+ } else {
+ redisKey = cache.key();
+ }
+
+ // redisKey 不存在,获取接口数据并返回
+ if (StringUtils.isBlank(redisKey)) {
+ result = jp.proceed(args);
+ } else {
+ ValueOperations valueOperations = stringRedisTemplate.opsForValue();
+ String value = valueOperations.get(redisKey);
+ if (value == null) {
+ String lockKey = StringUtils.join(redisKey, ":", "lock");
+ long time = System.currentTimeMillis() + 2000;
+ String timeStr = String.valueOf(time);
+ try {
+ //分布式锁,保证一个线程读DB,其它线程排队
+ if (redisLock.lock2(lockKey, timeStr)) {
+ log.debug("CacheAspect 读库中, key:{}: " + lockKey);
+ result = jp.proceed(args);
+ String json_data = JSONObject.toJSONString(result);
+ valueOperations.set(redisKey, json_data, cache.expireTime(), cache.dateUnit());
+ log.debug("CacheAspect 缓存不存在,获取接口数据并放入缓存,key:{}, expire:{}", redisKey, cache.expireTime());
+ } else {
+ log.debug("CacheAspect 读库等待中, key:{}: " + lockKey);
+ Thread.sleep(2000);
+ value = valueOperations.get(redisKey);
+ result = parseCache(jp, redisKey, value);
+ }
+ } catch (Throwable throwable) {
+ log.error("CacheAspect proceed error , Illegal argument: {} in {}.{}()", Arrays.toString(jp.getArgs()),
+ jp.getSignature().getDeclaringTypeName(), jp.getSignature().getName(), throwable);
+ throw throwable;
+ } finally {
+ redisLock.unlock(lockKey, timeStr);
+ }
+ } else {
+ result = parseCache(jp, redisKey, value);
+ }
+ // 计数器
+ stringRedisTemplate.opsForHash().increment("hotapi", redisKey, 1);
+ }
+ return result;
+ }
+
+ private Object parseCache(ProceedingJoinPoint jp, String redisKey, String value) {
+ if (StringUtils.isBlank(value)) {
+ log.debug("CacheAspect 缓存不存在,解析缓存数据为空:{},key:{}", value, redisKey);
+ return null;
+ }
+ Class> returnType = ((MethodSignature) jp.getSignature()).getReturnType();
+ log.debug("CacheAspect 缓存存在,解析缓存并返回,key:{}", redisKey);
+ return JSONObject.parseObject(value, returnType);
+ }
+}
diff --git a/open-api/src/main/java/com/iformall/config/MyBatisConfiguration.java b/open-api/src/main/java/com/iformall/config/MyBatisConfiguration.java
new file mode 100644
index 0000000..7b21584
--- /dev/null
+++ b/open-api/src/main/java/com/iformall/config/MyBatisConfiguration.java
@@ -0,0 +1,23 @@
+package com.iformall.config;
+
+import com.iformall.plugin.MyBatisItercepters;
+import com.iformall.plugin.MyBatisPlus;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Configuration
+public class MyBatisConfiguration extends BaseMyBatisConfiguration {
+
+ @Bean
+ public MyBatisItercepters intercepters() {
+ MyBatisItercepters intercepters = new MyBatisItercepters();
+ List plugins = new ArrayList();
+ plugins.add(baseShardingSpherePlugin());
+
+ intercepters.setPlugins(plugins);
+ return intercepters;
+ }
+}
diff --git a/open-api/src/main/java/com/iformall/config/RedisConfig.java b/open-api/src/main/java/com/iformall/config/RedisConfig.java
new file mode 100644
index 0000000..3266ae2
--- /dev/null
+++ b/open-api/src/main/java/com/iformall/config/RedisConfig.java
@@ -0,0 +1,334 @@
+package com.iformall.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.pagehelper.PageInfo;
+import com.iformall.domain.po.*;
+import com.iformall.domain.po.base.BaseCUserEntity;
+import com.iformall.domain.vo.WxCouponCVo;
+import com.iformall.domain.vo.WxCouponChannelVo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cache.CacheManager;
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.cache.RedisCacheConfiguration;
+import org.springframework.data.redis.cache.RedisCacheManager;
+import org.springframework.data.redis.cache.RedisCacheWriter;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Created by Stormeye on 2018/10/1.
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig extends CachingConfigurerSupport {
+
+ private final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+ //缓存管理器
+ @Bean
+ public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
+ //user信息缓存配置
+ RedisCacheConfiguration userCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofSeconds(10)).disableCachingNullValues().prefixKeysWith("user");
+ Map redisCacheConfigurationMap = new HashMap<>();
+ redisCacheConfigurationMap.put("user", userCacheConfiguration);
+ //初始化一个RedisCacheWriter
+ RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
+ // 设置CacheManager的值序列化方式为JdkSerializationRedisSerializer,但其实RedisCacheConfiguration默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value,所以以下注释代码为默认实现
+ // ClassLoader loader = this.getClass().getClassLoader();
+ // JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(loader);
+ // RedisSerializationContext.SerializationPair