Przeglądaj źródła

add publicApiProject

release_toaliyun_real
xiaohanzi 5 lat temu
rodzic
commit
ba2a331b25
26 zmienionych plików z 2423 dodań i 0 usunięć
  1. +154
    -0
      mallinkPublicApi/pom.xml
  2. +60
    -0
      mallinkPublicApi/src/main/java/com/iformall/PublicApiApplication.java
  3. +53
    -0
      mallinkPublicApi/src/main/java/com/iformall/annotation/RedisCache.java
  4. +161
    -0
      mallinkPublicApi/src/main/java/com/iformall/aop/RedisCacheAspect.java
  5. +24
    -0
      mallinkPublicApi/src/main/java/com/iformall/config/MyBatisConfiguration.java
  6. +335
    -0
      mallinkPublicApi/src/main/java/com/iformall/config/RedisConfig.java
  7. +61
    -0
      mallinkPublicApi/src/main/java/com/iformall/config/Swagger2Config.java
  8. +106
    -0
      mallinkPublicApi/src/main/java/com/iformall/config/WebMvcConfig.java
  9. +57
    -0
      mallinkPublicApi/src/main/java/com/iformall/controller/BaseController.java
  10. +68
    -0
      mallinkPublicApi/src/main/java/com/iformall/interceptor/AuthorizationInterceptor.java
  11. +76
    -0
      mallinkPublicApi/src/main/java/com/iformall/interceptor/BodyReaderHttpServletRequestWrapper.java
  12. +70
    -0
      mallinkPublicApi/src/main/java/com/iformall/interceptor/HttpServletRequestWrapperFilter.java
  13. +123
    -0
      mallinkPublicApi/src/main/java/com/iformall/interceptor/RequestInterceptor.java
  14. +72
    -0
      mallinkPublicApi/src/main/java/com/iformall/interceptor/WebLogAspect.java
  15. +125
    -0
      mallinkPublicApi/src/main/java/com/iformall/interceptor/XssHttpServletRequestWrapper.java
  16. +175
    -0
      mallinkPublicApi/src/main/java/com/iformall/utils/ImgIdeaUtil.java
  17. +14
    -0
      mallinkPublicApi/src/main/java/com/iformall/utils/UrlCheck.java
  18. +167
    -0
      mallinkPublicApi/src/main/resources/application-dev.yml
  19. +122
    -0
      mallinkPublicApi/src/main/resources/application-prod.yml
  20. +145
    -0
      mallinkPublicApi/src/main/resources/application-prodDetry.yml
  21. +100
    -0
      mallinkPublicApi/src/main/resources/application-test.yml-bak
  22. +54
    -0
      mallinkPublicApi/src/main/resources/application.yml
  23. BIN
      mallinkPublicApi/src/main/resources/imgTemp/gertificate.jpg
  24. +100
    -0
      mallinkPublicApi/src/main/resources/logback-spring.xml
  25. BIN
      mallinkPublicApi/src/main/resources/opt/HWLS.TTF
  26. +1
    -0
      pom.xml

+ 154
- 0
mallinkPublicApi/pom.xml Wyświetl plik

@@ -0,0 +1,154 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>mallink</artifactId>
<groupId>com.iformall</groupId>
<version>1.0</version>
</parent>

<artifactId>mallinkPublicApi</artifactId>

<dependencies>
<dependency>
<groupId>com.iformall</groupId>
<artifactId>mallinkService</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<executable>true</executable>
<layout>ZIP</layout>
<excludeGroupIds>
antlr,
cn.afterturn,
ch.qos.logback,
com.alibaba,
com.amazonaws,
com.baomidou,
com.mchange,
com.fasterxml.jackson.core,
com.fasterxml.jackson.dataformat,
com.fasterxml.jackson.datatype,
com.fasterxml.jackson.module,
com.fasterxml.uuid,
com.fasterxml,
com.github.axet,
com.github.jsqlparser,
com.github.pagehelper,
com.github.ulisesbocchio,
com.github.virtuald,
com.google.code.findbugs,
com.google.code.gson,
com.google.errorprone,
com.google.guava,
com.google.protobuf,
com.google.zxing,
com.jayway.jsonpath,
com.jhlabs,
com.puppycrawl.tools,
com.rabbitmq,
com.squareup.okhttp3,
com.squareup.okio,
com.sun,
com.sun.mail,
com.thoughtworks.xstream,
com.zaxxer,
commons-beanutils,
commons-cli,
commons-codec,
commons-collections,
commons-fileupload,
commons-io,
commons-logging,
io.lettuce,
io.netty,
io.projectreactor,
io.springfox,
io.swagger,
io.undertow,
javax.activation,
javax.annotation,
javax.mail,
javax.persistence,
javax.servlet,
javax.validation,
javax.xml.bind,
javax.xml.soap,
javax.xml.ws,
joda-time,
junit,
mysql,
net.bytebuddy,
net.minidev,
net.sf.dozer,
net.sf.saxon,
ognl,
org.antlr,
org.apache.commons,
org.apache.httpcomponents,
org.apache.logging.log4j,
org.apache.poi,
org.apache.poi.wso2,
org.apache.rocketmq,
org.apache.shiro,
org.apache.tomcat.embed,
org.apache.xmlbeans,
org.aspectj,
org.assertj,
org.bouncycastle,
org.checkerframework,
org.codehaus.mojo,
org.crazycake,
org.dom4j,
org.flowable,
org.flywaydb,
org.glassfish,
org.hibernate.validator,
org.jasypt,
org.javassist,
org.jboss.logging,
org.jboss.spec.javax.annotation,
org.jboss.spec.javax.websocket,
org.jboss.xnio,
org.jdom,
org.jodd,
org.jvnet.mimepull,
org.jvnet.staxex,
org.mapstruct,
org.mockito,
org.mybatis,
org.mybatis.generator,
org.mybatis.spring.boot,
org.ow2.asm,
org.projectlombok,
org.quartz-scheduler,
org.reactivestreams,
org.reflections,
org.rocketmq.spring.boot,
org.slf4j,
org.springframework,
org.springframework.amqp,
org.springframework.boot,
org.springframework.data,
org.springframework.retry,
org.springframework.ws,
org.yaml,
redis.clients,
software.amazon.ion,
tk.mybatis,
xmlpull,
xpp3
</excludeGroupIds>
</configuration>
</plugin>
</plugins>
</build>
</project>

+ 60
- 0
mallinkPublicApi/src/main/java/com/iformall/PublicApiApplication.java Wyświetl plik

@@ -0,0 +1,60 @@
package com.iformall;

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;

import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties;

/**
* @author chenkx
* @date 2017-12-26
*/
@SpringBootApplication
@MapperScan(basePackages = {"com.iformall.mapper"})
@EnableEncryptableProperties
@EnableRocketMQ
@EnableAspectJAutoProxy(exposeProxy = true)
public class PublicApiApplication {

@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;

@Bean
public boolean isFmException() {
return fmException;
}

@Bean
public String fmExceptionEmails() {
return fmExceptionEmails;
}

@Bean
public boolean isFmOpen() {
return fmOpen;
}

@Bean
public String fmUploadDir() {
return uploadDir;
}


public static void main(String[] args) {
SpringApplication.run(PublicApiApplication.class, args);
}
}

+ 53
- 0
mallinkPublicApi/src/main/java/com/iformall/annotation/RedisCache.java Wyświetl plik

@@ -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;
}

+ 161
- 0
mallinkPublicApi/src/main/java/com/iformall/aop/RedisCacheAspect.java Wyświetl plik

@@ -0,0 +1,161 @@
package com.iformall.aop;


import com.alibaba.fastjson.JSONObject;
import com.iformall.annotation.RedisCache;
import com.iformall.common.ErrorCode;
import com.iformall.domain.po.WxCUser;
import com.iformall.domain.po.base.BaseCUserEntity;
import com.iformall.exception.MallinkException;
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<String, String> 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);
}
}

+ 24
- 0
mallinkPublicApi/src/main/java/com/iformall/config/MyBatisConfiguration.java Wyświetl plik

@@ -0,0 +1,24 @@
package com.iformall.config;

import com.iformall.plugin.MyBatisItercepters;
import com.iformall.plugin.MyBatisPlus;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class MyBatisConfiguration extends BaseMyBatisConfiguration {

@Bean
public MyBatisItercepters intercepters() {
MyBatisItercepters intercepters = new MyBatisItercepters();
List<MyBatisPlus> plugins = new ArrayList<MyBatisPlus>();
plugins.add(baseShardingSpherePlugin());
intercepters.setPlugins(plugins);
return intercepters;
}
}

+ 335
- 0
mallinkPublicApi/src/main/java/com/iformall/config/RedisConfig.java Wyświetl plik

@@ -0,0 +1,335 @@
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.ArrayList;
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<String, RedisCacheConfiguration> 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<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jdkSerializer);
// RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig();
//设置默认超过期时间是30秒
defaultCacheConfig.entryTtl(Duration.ofSeconds(30));
//初始化RedisCacheManager
RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig, redisCacheConfigurationMap);
return cacheManager;
}

@Bean("pushLimitRedisTemplate")
public RedisTemplate<String, PushLimit> getPushLimitRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, PushLimit> template = new RedisTemplate<String, PushLimit>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<PushLimit> j = new Jackson2JsonRedisSerializer<PushLimit>(PushLimit.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("scoreRuleRedisTemplate")
public RedisTemplate<String, WxScoreRules> getScoreRuleRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxScoreRules> template = new RedisTemplate<String, WxScoreRules>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<WxScoreRules> j = new Jackson2JsonRedisSerializer<WxScoreRules>(WxScoreRules.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("cuserTokenRedisTemplate")
public RedisTemplate<String, WxCUser> getCUserTokenRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxCUser> template = new RedisTemplate<String, WxCUser>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<WxCUser> j = new Jackson2JsonRedisSerializer<WxCUser>(WxCUser.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("baseCUserTokenRedisTemplate")
public RedisTemplate<String, BaseCUserEntity> getBaseCUserTokenRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, BaseCUserEntity> template = new RedisTemplate<String, BaseCUserEntity>();

template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<BaseCUserEntity> j = new Jackson2JsonRedisSerializer<BaseCUserEntity>(BaseCUserEntity.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
@Bean("cUserBasicInfoRedisTemplate")
public RedisTemplate<String, WxCUserBasicInfo> getCUserBasicInfoRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxCUserBasicInfo> template = new RedisTemplate<String, WxCUserBasicInfo>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<WxCUserBasicInfo> j = new Jackson2JsonRedisSerializer<WxCUserBasicInfo>(WxCUserBasicInfo.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("mallRedisTemplate")
public RedisTemplate<String, WxMall> getMallRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxMall> template = new RedisTemplate<String, WxMall>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<WxMall> j = new Jackson2JsonRedisSerializer<WxMall>(WxMall.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("subMallListRedisTemplate")
public RedisTemplate<String, List<WxMall>> getSubMallListRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, List<WxMall>> template = new RedisTemplate<String, List<WxMall>>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<List> j = new Jackson2JsonRedisSerializer<List>(List.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("couponDetailRedisTemplate")
public RedisTemplate<String, WxCouponCVo> getCouponDetailRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxCouponCVo> template = new RedisTemplate<String, WxCouponCVo>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<WxCouponCVo> j = new Jackson2JsonRedisSerializer<WxCouponCVo>(WxCouponCVo.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);
// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("couponChannelRedisTemplate")
public RedisTemplate<String, PageInfo<WxCouponChannelVo>> getCouponChannelRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, PageInfo<WxCouponChannelVo>> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<PageInfo> j = new Jackson2JsonRedisSerializer<PageInfo>(PageInfo.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);

// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("buserTokenRedisTemplate")
public RedisTemplate<String, WxBuser> getBuserTokenRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxBuser> template = new RedisTemplate();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<WxBuser> j = new Jackson2JsonRedisSerializer(WxBuser.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);

// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("pressOrderRedisTemplate")
public RedisTemplate<String, WxOrder> getPressOrderRedisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, WxOrder> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<WxOrder> j = new Jackson2JsonRedisSerializer<WxOrder>(WxOrder.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);

// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}

@Bean("stringValueOperations")
public ValueOperations<String, String> getStringValueOperations(RedisConnectionFactory connectionFactory) {
StringRedisTemplate template = new StringRedisTemplate();
template.setConnectionFactory(connectionFactory);
template.afterPropertiesSet();
return template.opsForValue();
}
@Bean("objectCommonRedisTemplate")
public RedisTemplate<String, Object> getObjectValueOperations(RedisConnectionFactory connectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
Jackson2JsonRedisSerializer<Object> j = new Jackson2JsonRedisSerializer<Object>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
j.setObjectMapper(om);

// value值的序列化
template.setValueSerializer(j);
template.setHashValueSerializer(j);

// key的序列化
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.afterPropertiesSet();
return template;
}
}

+ 61
- 0
mallinkPublicApi/src/main/java/com/iformall/config/Swagger2Config.java Wyświetl plik

@@ -0,0 +1,61 @@
package com.iformall.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.ParameterBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.schema.ModelRef;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.Parameter;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.paths.RelativePathProvider;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

import javax.servlet.ServletContext;
import java.util.ArrayList;
import java.util.List;

//参考:http://blog.csdn.net/catoop/article/details/50668896
@Configuration
@EnableSwagger2
public class Swagger2Config {

@Autowired
private ServletContext servletContext;

@Bean
public Docket createRestApi() {
ParameterBuilder tokenPar = new ParameterBuilder();
List<Parameter> pars = new ArrayList<Parameter>();
//增加一个request的header参数
tokenPar.name("token").description("令牌").modelRef(new ModelRef("string")).parameterType("header").required(false).build();
pars.add(tokenPar.build());
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.iformall.controller"))
.paths(PathSelectors.any())
.build()
.globalOperationParameters(pars)
.pathProvider(new RelativePathProvider(servletContext) {
@Override
public String getApplicationBasePath() {
return "/api";
}
});
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("c端 api")
.description("c api")
.termsOfServiceUrl("http://localhost:7000")
.version("2.0")
.build();
}

}

+ 106
- 0
mallinkPublicApi/src/main/java/com/iformall/config/WebMvcConfig.java Wyświetl plik

@@ -0,0 +1,106 @@
package com.iformall.config;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.databind.DeserializationConfig;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.iformall.interceptor.AuthorizationInterceptor;
import com.iformall.interceptor.HttpServletRequestWrapperFilter;
import com.iformall.interceptor.RequestInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.config.annotation.*;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.util.List;

/**
* MVC配置
*
* @author stormeye.wu
* @email wugq@mippoint.com
* @date 2017-04-20 22:30
*/
@Configuration
@EnableWebMvc
public class WebMvcConfig implements WebMvcConfigurer {
@Autowired
private AuthorizationInterceptor authorizationInterceptor;
@Autowired
private RequestInterceptor requestInterceptor;

@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authorizationInterceptor).addPathPatterns("/api/**");
registry.addInterceptor(requestInterceptor).addPathPatterns("/api/**");
}

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("swagger-ui.html")
.addResourceLocations("classpath:/META-INF/resources/");
registry.addResourceHandler("/webjars/**")
.addResourceLocations("classpath:/META-INF/resources/webjars/");
//registry.addResourceHandler("/app/**").addResourceLocations("classpath:/app/");

}

@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("*")
.allowCredentials(true)
.allowedMethods("GET", "POST", "DELETE", "PUT")
.maxAge(3600);
}

@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter();
//ObjectMapper 是Jackson库的主要类。它提供一些功能将转换成Java对象匹配JSON结构,反之亦然
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();

//不显示为null的字段
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

DeserializationConfig dc = objectMapper.getDeserializationConfig();
// 设置反序列化日期格式、忽略不存在get、set的属性
objectMapper.setConfig(
dc.with(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"))
.without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
);
//序列化将Long转String类型
simpleModule.addSerializer(Long.class, ToStringSerializer.instance);
simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance);
SimpleModule bigIntegerModule = new SimpleModule();
//序列化将BigInteger转String类型
bigIntegerModule.addSerializer(BigInteger.class, ToStringSerializer.instance);
SimpleModule bigDecimalModule = new SimpleModule();
//序列化将BigDecimal转String类型
bigDecimalModule.addSerializer(BigDecimal.class, ToStringSerializer.instance);
objectMapper.registerModule(simpleModule);
objectMapper.registerModule(bigDecimalModule);
objectMapper.registerModule(bigIntegerModule);
jackson2HttpMessageConverter.setObjectMapper(objectMapper);
converters.add(jackson2HttpMessageConverter);
}

@Bean
public FilterRegistrationBean<HttpServletRequestWrapperFilter> Filters() {
FilterRegistrationBean<HttpServletRequestWrapperFilter> registrationBean = new FilterRegistrationBean<HttpServletRequestWrapperFilter>();
registrationBean.setFilter(new HttpServletRequestWrapperFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("koalaSignFilter");
return registrationBean;
}
}

+ 57
- 0
mallinkPublicApi/src/main/java/com/iformall/controller/BaseController.java Wyświetl plik

@@ -0,0 +1,57 @@
package com.iformall.controller;

import com.iformall.utils.IPUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.beans.PropertyEditorSupport;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

@RestController
public class BaseController {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Autowired
@Qualifier("objectCommonRedisTemplate")
RedisTemplate<String, Object> objectCommonRedisTemplate;
@InitBinder
public void InitBinder(WebDataBinder dataBinder) {
dataBinder.registerCustomEditor(Date.class, new PropertyEditorSupport() {
public void setAsText(String value) {
try {
setValue(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value));
} catch (ParseException e) {
try {
setValue(new SimpleDateFormat("yyyy-MM-dd ").parse(value));
} catch (ParseException e1) {
setValue(null);
}
}
}

public String getAsText() {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) getValue());
}

});
}

public String getIpAddr() {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
String ipaddress = IPUtil.getIpAddr(request);
return ipaddress;
}
}

+ 68
- 0
mallinkPublicApi/src/main/java/com/iformall/interceptor/AuthorizationInterceptor.java Wyświetl plik

@@ -0,0 +1,68 @@
package com.iformall.interceptor;


import com.iformall.common.ErrorCode;
import com.iformall.exception.MallinkException;
import com.iformall.utils.HashUtil;
import com.iformall.utils.RedisCacheUtils;

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 权限(Token)验证
* @author stormeye.wu
* @email wuguoqiang@iformall.com
* @date 2017-03-23 15:38
*/
@Component
public class AuthorizationInterceptor extends HandlerInterceptorAdapter {

@Autowired
@Qualifier("objectCommonRedisTemplate")
RedisTemplate<String, Object> redisTemplate;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String cid = request.getParameter("cId");//调用方ID
String nonceStr = request.getParameter("nonceStr");//随机字符串
String signKey = request.getParameter("signKey");//随机字符串

if(StringUtils.isBlank(cid) || "null".equals(cid) || "undefined".equals(cid)){
throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR.getCode(),"cId为空["+cid+"]");
}
if(StringUtils.isBlank(nonceStr) || "null".equals(nonceStr) || "undefined".equals(nonceStr)){
throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR.getCode(),"nonceStr为空["+nonceStr+"]");
}
if(StringUtils.isBlank(signKey) || "null".equals(signKey) || "undefined".equals(signKey)){
throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR.getCode(),"signKey为空["+signKey+"]");
}

//nonceStr必须唯一,为防止接口盗刷,每次只能调用一次
Integer cache = RedisCacheUtils.getCacheInteger(redisTemplate, "publicApi:"+nonceStr);
if (null != cache) {
throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR.getCode(),"不能重复调用");
}
//TODO singnKey是根据cid+cid对应的密钥+nonceStr
String secretKey = "";//TODO 根据cid查询密钥,缓存
String signstr = HashUtil.md5(cid+secretKey+nonceStr);
if (!signKey.equals(signstr)) {
throw new MallinkException(ErrorCode.SYS_PARAMETER_ERROR.getCode(),"加密串校验失败");
}
RedisCacheUtils.cache(redisTemplate, "publicApi:"+nonceStr, 1, 600);
return true;
}
}

+ 76
- 0
mallinkPublicApi/src/main/java/com/iformall/interceptor/BodyReaderHttpServletRequestWrapper.java Wyświetl plik

@@ -0,0 +1,76 @@
package com.iformall.interceptor;

import javax.servlet.ReadListener;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import java.io.*;

public class BodyReaderHttpServletRequestWrapper extends XssHttpServletRequestWrapper {
private final String body;

public BodyReaderHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
super(request);
StringBuilder stringBuilder = new StringBuilder();
BufferedReader bufferedReader = null;
try {
InputStream inputStream = request.getInputStream();
if (inputStream != null) {
bufferedReader = new BufferedReader(new InputStreamReader(inputStream,"utf-8"));
char[] charBuffer = new char[1024];
int bytesRead = -1;
while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
stringBuilder.append(charBuffer, 0, bytesRead);
}
} else {
stringBuilder.append("");
}
} catch (IOException ex) {
throw ex;
} finally {
if (bufferedReader != null) {
try {
bufferedReader.close();
} catch (IOException ex) {
throw ex;
}
}
}
body = stringBuilder.toString();
}

@Override
public ServletInputStream getInputStream() throws IOException {
final ByteArrayInputStream byteArrayInputStream =
new ByteArrayInputStream(body.getBytes("utf-8"));
return new ServletInputStream() {
@Override
public boolean isFinished() {
return false;
}

@Override
public boolean isReady() {
return false;
}

@Override
public void setReadListener(ReadListener readListener) {

}

@Override
public int read() throws IOException {
return byteArrayInputStream.read();
}
};
}

@Override
public BufferedReader getReader() throws IOException {
return new BufferedReader(new InputStreamReader(this.getInputStream()));
}

public String getBody() {
return this.body;
}
}

+ 70
- 0
mallinkPublicApi/src/main/java/com/iformall/interceptor/HttpServletRequestWrapperFilter.java Wyświetl plik

@@ -0,0 +1,70 @@
package com.iformall.interceptor;

import com.iformall.utils.UrlCheck;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

public class HttpServletRequestWrapperFilter implements Filter {
private final Logger logger = LoggerFactory.getLogger(this.getClass());
// 多个跨域域名设置
// public static final String[] ALLOW_DOMAIN = {"https://admin.malls.iformall.com"};
@Override
public void init(FilterConfig filterConfig) throws ServletException {

}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
logger.debug("doFilter start");
long start = System.currentTimeMillis();
ServletRequest requestWrapper = null;

/* // 跨域访问
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
String originHeader = req.getHeader("Origin");

if (Arrays.asList(ALLOW_DOMAIN).contains(originHeader)) {
//通过在响应 header 中设置 ‘*’ 来允许来自所有域的跨域请求访问。
res.setHeader("Access-Control-Allow-Origin", originHeader);
//通过对 Credentials 参数的设置,就可以保持跨域 Ajax 时的 Cookie
//设置了Allow-Credentials,Allow-Origin就不能为*,需要指明具体的url域
res.setHeader("Access-Control-Allow-Credentials", "true");
//请求方式
res.setHeader("Access-Control-Allow-Methods", "*");
//(预检请求)的返回结果(即 Access-Control-Allow-Methods 和Access-Control-Allow-Headers 提供的信息) 可以被缓存多久
res.setHeader("Access-Control-Max-Age", "86400");
//首部字段用于预检请求的响应。其指明了实际请求中允许携带的首部字段
//res.setHeader("Access-Control-Allow-Headers", "*");
res.setHeader("Access-Control-Allow-Headers",
"Timestamp,Origin, No-Cache, X-Requested-With, If-Modified-Since, Pragma, Last-Modified, Cache-Control, Expires, Content-Type, X-E4M-With,userId,token,Access-Control-Allow-Headers");
}
*/

//sql,xss过滤
XssHttpServletRequestWrapper xssHttpServletRequestWrapper = new XssHttpServletRequestWrapper((HttpServletRequest)request);
String url = "";
if (request instanceof HttpServletRequest) {
url = ((HttpServletRequest) request).getRequestURI();
if (!UrlCheck.checkUrl(url)) {
requestWrapper = new BodyReaderHttpServletRequestWrapper((HttpServletRequest) request);
}
}
if (null == requestWrapper) {
chain.doFilter(xssHttpServletRequestWrapper, response);
} else {
chain.doFilter(requestWrapper, response);
}
logger.debug("doFilter end: " + url + " "+ (System.currentTimeMillis()- start) + "ms");
}

@Override
public void destroy() {

}
}

+ 123
- 0
mallinkPublicApi/src/main/java/com/iformall/interceptor/RequestInterceptor.java Wyświetl plik

@@ -0,0 +1,123 @@
package com.iformall.interceptor;

import com.iformall.common.ErrorCode;
import com.iformall.exception.MallinkException;
import com.iformall.utils.HashUtil;
import com.iformall.utils.IPUtil;
import com.iformall.utils.UrlCheck;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import redis.clients.jedis.Protocol;
import redis.clients.jedis.util.SafeEncoder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.Enumeration;
import java.util.concurrent.TimeUnit;

/**
* 幂等检查
* @author stormeye.wu
* @email wuguoqiang@iformall.com
* @date 2017-03-23 15:38
*/
@Component
public class RequestInterceptor extends HandlerInterceptorAdapter {

private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Resource
private RedisTemplate<String, String> redisTemplate;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
logger.debug("preHandle start");
if ("GET".equalsIgnoreCase(request.getMethod())) {
// 获取不检查幂等
logger.debug("preHandle start 1");
return true;
}
String ipaddress = IPUtil.getIpAddr(request);
String url = request.getRequestURL().toString();
if (UrlCheck.checkUrl(url)) {
// pvlog不检查幂等
// awsFileUpload不检查幂等
// stopFee
return true;
}
StringBuilder sb = new StringBuilder();

sb.append(url);

sb.append("method=").append(request.getMethod()).append("&");

sb.append("ip=").append(ipaddress).append("&");

final Enumeration parameterNames = request.getParameterNames();
while (parameterNames.hasMoreElements()) {
String key = (String) parameterNames.nextElement();
if(key.equalsIgnoreCase("ran")) // 跳过ran
continue;
String parameter = request.getParameter(key);
sb.append(key).append("=").append(parameter).append("&");
}

InputStream inStream = request.getInputStream();
ByteArrayOutputStream outSteam = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int len = 0;
while ((len = inStream.read(buffer)) != -1) {
outSteam.write(buffer, 0, len);
}
String resultBody = new String(outSteam.toByteArray(), Charset.forName("UTF-8"));
inStream.close();
outSteam.close();

sb.append(resultBody);

String key = "request:C:" + HashUtil.md5(sb.toString());
Boolean isAbsent = redisTemplate.<Boolean>execute(new RedisCallback<Boolean>() {
@Override
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
RedisSerializer valueSerializer = redisTemplate.getValueSerializer();
RedisSerializer keySerializer = redisTemplate.getKeySerializer();
Object obj = connection.execute("set", keySerializer.serialize(key),
valueSerializer.serialize(key),
SafeEncoder.encode("NX"),
SafeEncoder.encode("EX"),
Protocol.toByteArray(3)); // 3s
return obj != null;
}
});
if (isAbsent) {
logger.info(key + ": 第一次提交");
logger.debug("preHandle start 2");
return true;
}
logger.info(key + ": 第二次提交");
logger.debug("preHandle start 3");
throw new MallinkException(ErrorCode.SYS_REPEAT_SUBMIT_EXCEPTION);
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
logger.debug("postHandle");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
logger.debug("afterCompletion");
}
}

+ 72
- 0
mallinkPublicApi/src/main/java/com/iformall/interceptor/WebLogAspect.java Wyświetl plik

@@ -0,0 +1,72 @@
package com.iformall.interceptor;

import com.iformall.utils.IPUtil;
import lombok.Data;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.util.Arrays;

@Aspect
@Component
public class WebLogAspect {
private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Data
private class MethodInfo {
Long startTime;
String url;
String ip;
String method;
String classMethod;
}

ThreadLocal<MethodInfo> startInfo = new ThreadLocal<>();


@Pointcut("execution(public * com.iformall.controller..*.*(..))")
public void webLog() {}

@Before("webLog()")
public void doBefore(JoinPoint joinPoint) throws Throwable {
logger.debug("aspect start");
// 接收到请求,记录请求内容
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();

MethodInfo info = new MethodInfo();
info.setUrl(request.getRequestURL().toString());
info.setStartTime(System.currentTimeMillis());
info.setIp(IPUtil.getIpAddr(request));
info.setMethod(request.getMethod());
info.setClassMethod(joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());
startInfo.set(info);
logger.debug("aspect start ...");
}

@AfterReturning(returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret) throws Throwable {
logger.debug("aspect after");
// 处理完请求,返回内容
MethodInfo info = startInfo.get();
StringBuilder sb = new StringBuilder();
sb.append("URL: ").append(info.getUrl())
.append(", METHOD: ").append(info.getMethod())
.append(", DO: ").append(info.getClassMethod())
.append(", IP: ").append(info.getIp())
.append(", SPEND TIME: ").append(System.currentTimeMillis() -info.getStartTime()).append("ms");
logger.info(sb.toString());
logger.debug("aspect after ..");
}


}

+ 125
- 0
mallinkPublicApi/src/main/java/com/iformall/interceptor/XssHttpServletRequestWrapper.java Wyświetl plik

@@ -0,0 +1,125 @@
package com.iformall.interceptor;


import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
* 防止sql注入,xss攻击
* 前端可以对输入信息做预处理,后端也可以做处理。
*/
public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper {
private final Logger log = LoggerFactory.getLogger(getClass());
private static String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+";
private static Set<String> notAllowedKeyWords = new HashSet<String>(0);
private static String replacedString="INVALID";
static {
String keyStr[] = key.split("\\|");
for (String str : keyStr) {
notAllowedKeyWords.add(str);
}
}

private String currentUrl;

public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) {
super(servletRequest);
currentUrl = servletRequest.getRequestURI();
}


/**覆盖getParameter方法,将参数名和参数值都做xss过滤。
* 如果需要获得原始的值,则通过super.getParameterValues(name)来获取
* getParameterNames,getParameterValues和getParameterMap也可能需要覆盖
*/
@Override
public String getParameter(String parameter) {
String value = super.getParameter(parameter);
if (value == null) {
return null;
}
return cleanXSS(value);
}
@Override
public String[] getParameterValues(String parameter) {
String[] values = super.getParameterValues(parameter);
if (values == null) {
return null;
}
int count = values.length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++) {
encodedValues[i] = cleanXSS(values[i]);
}
return encodedValues;
}
@Override
public Map<String, String[]> getParameterMap(){
Map<String, String[]> values=super.getParameterMap();
if (values == null) {
return null;
}
Map<String, String[]> result=new HashMap<>();
for(String key:values.keySet()){
String encodedKey=cleanXSS(key);
int count=values.get(key).length;
String[] encodedValues = new String[count];
for (int i = 0; i < count; i++){
encodedValues[i]=cleanXSS(values.get(key)[i]);
}
result.put(encodedKey,encodedValues);
}
return result;
}
/**
* 覆盖getHeader方法,将参数名和参数值都做xss过滤。
* 如果需要获得原始的值,则通过super.getHeaders(name)来获取
* getHeaderNames 也可能需要覆盖
*/
@Override
public String getHeader(String name) {
if(name.equalsIgnoreCase("user-agent")) {
return super.getHeader(name);
}
String value = super.getHeader(name);
if (value == null) {
return null;
}
return cleanXSS(value);
}

private String cleanXSS(String valueP) {
// You'll need to remove the spaces from the html entities below
String value = valueP.replaceAll("<", "&lt;").replaceAll(">", "&gt;");
value = value.replaceAll("<", "& lt;").replaceAll(">", "& gt;");
value = value.replaceAll("\\(", "& #40;").replaceAll("\\)", "& #41;");
value = value.replaceAll("'", "& #39;");
value = value.replaceAll("eval\\((.*)\\)", "");
value = value.replaceAll("[\\\"\\\'][\\s]*javascript:(.*)[\\\"\\\']", "\"\"");
value = value.replaceAll("script", "");
value = cleanSqlKeyWords(value);
return value;
}

private String cleanSqlKeyWords(String value) {
String paramValue = value;
for (String keyword : notAllowedKeyWords) {
if (paramValue.length() > keyword.length() + 4
&& (paramValue.contains(" "+keyword)||paramValue.contains(keyword+" ")||paramValue.contains(" "+keyword+" "))) {
paramValue = StringUtils.replace(paramValue, keyword, replacedString);
log.error(this.currentUrl + "已被过滤,因为参数中包含不允许sql的关键词(" + keyword
+ ")"+";参数:"+value+";过滤后的参数:"+paramValue);
}
}
return paramValue;
}

}

+ 175
- 0
mallinkPublicApi/src/main/java/com/iformall/utils/ImgIdeaUtil.java Wyświetl plik

@@ -0,0 +1,175 @@
package com.iformall.utils;

import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.HanyuPinyinVCharType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class ImgIdeaUtil {

private static final Logger logger = LoggerFactory.getLogger(ImgIdeaUtil.class);

//模板图片
private static final String imgTempPath = "imgTemp/gertificate.jpg";
//字体路径
private static final String fontPath = "opt/HWLS.TTF";

/**
* 生成图片证书
* @return
*/
public static byte[] imgGertificate(String name, String englishName, LocalDateTime date){
if(StringUtils.isBlank(name)){
logger.error("名字为空,无法生成证书");
return null;
}
if(name.length() == 2){
name = name.replaceAll("(\\S)", "$0 ");
}
if(StringUtils.isBlank(englishName)){
englishName = getUpEname(name);
}
if(date == null){
date = LocalDateTime.now();
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dMMM yyyy", Locale.UK);
String dateFormat = date.format(formatter);

try {

InputStream backImgUrl = ClassLoader.getSystemResourceAsStream(imgTempPath);
//InputStream backImgUrl = ImgIdeaUtil.class.getClassLoader().getResourceAsStream(imgTempPath);

Font font = Font.createFont(Font.TRUETYPE_FONT, ResourceUtils.getFile("classpath:"+fontPath));
BufferedImage backImg = ImageIO.read(backImgUrl);
Graphics g = backImg.getGraphics();

//图片加中文名
Font fTxtBottomName = font.deriveFont(Font.PLAIN, 170);
//Font fTxtBottomName = new Font("华文隶书", Font.PLAIN, 170);
FontMetrics metricsName = g.getFontMetrics(fTxtBottomName);
int xName = (backImg.getWidth() - metricsName.stringWidth(name)) / 2;
Color myColorTxtBottomName = Color.BLACK; //颜色
g.setColor(myColorTxtBottomName);
g.setFont(fTxtBottomName);
g.drawString(name, xName , 1150);//g.drawString(文字, x 位置, y 位置);

//图片加英文名
Font fTxtBottomEname = font.deriveFont(Font.PLAIN, 120);
//Font fTxtBottomEname = new Font("华文隶书", Font.PLAIN, 120);
FontMetrics metricsEname = g.getFontMetrics(fTxtBottomEname);
int xEname = (backImg.getWidth() - metricsEname.stringWidth(englishName)) / 2;
Color myColorTxtBottomEname = Color.BLACK;
g.setColor(myColorTxtBottomEname);
g.setFont(fTxtBottomEname);
g.drawString(englishName, xEname, 1300);

//图片加日期
Font fTxtBottomDate = font.deriveFont(Font.PLAIN, 90);
//Font fTxtBottomDate = new Font("华文隶书", Font.PLAIN, 90);
Color myColorTxtBottomDate = Color.BLACK;
g.setColor(myColorTxtBottomDate);
g.setFont(fTxtBottomDate);
g.drawString(dateFormat, 440, 2100);

//调这个方法就是开始这个整合 (可以多张图片,多个文字整合成一张图片,只有把他们放在这方法里面就行)
g.dispose();

ByteArrayOutputStream out = new ByteArrayOutputStream();
ImageIO.write(backImg, "png", out);

return out.toByteArray();
} catch (Exception e) {
e.printStackTrace();
logger.error("生成证书异常", e.getMessage());
}
return null;
}

/**
* //姓、名的第一个字母需要为大写
* @param name
* @return
*/
public static String getUpEname(String name) {
char[] strs = name.toCharArray();
String newname = null;

if (strs.length == 2) {
newname = toUpCase(getEname("" + strs[0])) + " " + toUpCase(getEname("" + strs[1]));
} else if (strs.length == 3){
newname = toUpCase(getEname("" + strs[0])) + " "
+ toUpCase(getEname("" + strs[1] + strs[2]));
}else if (strs.length == 4){
newname = toUpCase(getEname("" + strs[0] + strs[1])) + " "
+ toUpCase(getEname("" + strs[2] + strs[3]));
} else{
newname = toUpCase(getEname(name));
}
return newname;
}


/**
* //将中文转换为英文
* @param name
* @return
*/
public static String getEname(String name){
HanyuPinyinOutputFormat pyFormat = new HanyuPinyinOutputFormat();
pyFormat.setCaseType(HanyuPinyinCaseType.LOWERCASE);
pyFormat.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
pyFormat.setVCharType(HanyuPinyinVCharType.WITH_V);
String s = "";
try {
s = PinyinHelper.toHanyuPinyinString(name, pyFormat, "");
} catch (BadHanyuPinyinOutputFormatCombination badHanyuPinyinOutputFormatCombination) {
badHanyuPinyinOutputFormatCombination.printStackTrace();
}
return s;
}
/**
* 首字母大写
* @param str
* @return
*/
private static String toUpCase(String str) {
StringBuffer newstr = new StringBuffer();
newstr.append((str.substring(0, 1)).toUpperCase()).append(
str.substring(1, str.length()));
return newstr.toString();
}


// public static void main(String[] args) {
// String serverUploadImgUrl = "C:/Users/xiaohu/Desktop/img"; // 图片保存路径
// try {
// byte[] bytes = imgGertificate("郑方元", null, null);
// ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
// BufferedImage bi1 =ImageIO.read(bais);
//
// ImageIO.write(bi1, "png", new File(serverUploadImgUrl+"/0.png"));
//
// } catch (Exception e) {
// e.printStackTrace();
// }
// System.out.println("结束");
// }
}

+ 14
- 0
mallinkPublicApi/src/main/java/com/iformall/utils/UrlCheck.java Wyświetl plik

@@ -0,0 +1,14 @@
package com.iformall.utils;

/**
* @author gongbiao
*/
public class UrlCheck {

public static boolean checkUrl(String url) {
return url.contains("awsFileUpload")
|| url.contains("awsFilesUpload")
|| url.contains("getCarStopFee");
}

}

+ 167
- 0
mallinkPublicApi/src/main/resources/application-dev.yml Wyświetl plik

@@ -0,0 +1,167 @@
spring:
profiles:
#include: aliyunRocketMQ
include: rabbitMQ
# JDBC
datasource:
url: jdbc:mysql://101.200.130.134:3306/mallink?characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useUnicode=true&useSSL=false&useAffectedRows=true
username: root
password: fm2020test
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 28000
minEvictableIdleTimeMillis: 28000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
#jackson:
#date-format: yyyy-MM-dd HH:mm:ss

# REDIS
redis:
host: 101.200.130.134
port: 6379
password: iF0rm@2l2ol9
timeout: 3600
expire: 1800 #30分钟
database: 5
jedis:
pool:
max-active: 200
max-idle: 100
max-wait: -1
min-idle: 0

# SMS
aliyun:
sms:
accessKeyId: LTAI4G7ixY4AhvM35F8o3W3V
accessKeySecret: VfWqGb83qIQrS9us45utskl8itd7ry
product: Dysmsapi
domain: dysmsapi.aliyuncs.com
regionId: cn-hangzhou
dateFormat: yyyyMMdd
endpointName: cn-hangzhou

oss:
endpoint: oss-cn-beijing.aliyuncs.com
keyid: LTAI4G7ixY4AhvM35F8o3W3V
keysecret: VfWqGb83qIQrS9us45utskl8itd7ry
bucketname: formall
filehost: malinkcapi
filedomain: https://formall.oss-accelerate.aliyuncs.com

# EMAIL
mail:
host: smtp.exmail.qq.com
username: service@iformall.com
password: jGvApygXN7wc5SzN # 授权密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
# ROCKETMQ
rocketmq:
nameServer: 127.0.0.1:9876
producer:
retry-times-when-send-async-failed: 0
send-msg-timeout: 300000
compress-msg-body-over-howmuch: 4096
max-message-size: 4194304
retry-another-broker-when-not-store-ok: false
retry-times-when-send-failed: 2
# RABBITMQ
rabbitmq:
host: 101.200.130.134
port: 5672
username: fumao
password: f9l98
publisher-confirms: true
publisher-returns: false
virtual-host: /
aliyunRocketmq:
accessKeyId: "LTAI4G7ixY4AhvM35F8o3W3V"
accessKeySecret: "VfWqGb83qIQrS9us45utskl8itd7ry"
groupId: "GID_P_1"
namesrvAddr: "http://MQ_INST_1796289517488555_Bcqaq2is.cn-beijing.mq-internal.aliyuncs.com:8080"

aws:
clientRegion: cn-northwest-1
bucketName: iformall-net
access: ENC(3gx5ghDFBqGrEhO3Wf8aYmXsnwHO7Cj3HNKJGOeUj0o=)
secret: ENC(HVKIJwCJKVXLlUpGlQPwNqJOlnpxn4xYuy91SH0seTSm2uAttIQHvA49fXWWax90v5wloIk0QuU=)

#wechat:
# open:
# componentAppId: "wxdfc8fb4e62d6b52b"
# componentSecret: "98daa62b316dd6feabaad708327ce233"
# componentToken: "formall2018"
# componentAesKey: "htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN"
# redis:
# host: 101.201.103.81
# port: 6379
# password: ENC(xPFDlgd6v8zUhJMbcKc0KmmQiqs9qHtk)
# timeout: 3600
# expire: 1800 #30分钟
# database: 2
# defaultExpiration: 2592000 # 默认生命周期30天
# jedis:
# pool:
# max-active: 100
# max-idle: 500
# max-wait: -1
# min-idle: 10

wechat:
web:
appId: "wx091907dd0bfd3f6b"
secret: "2a2ca10738998b9ef92c1fe8a4d366a6"
url: "https://admintest.malls.iformall.com"
open:
componentAppId: wxdfc8fb4e62d6b52b
componentSecret: 98daa62b316dd6feabaad708327ce233
componentToken: formall2018
componentAesKey: htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN
redis:
host: 101.200.130.134
port: 6379
password: iF0rm@2l2ol9
timeout: 3600
expire: 1800 #30分钟
database: 2
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 100
max-wait: -1
min-idle: 10

jasypt:
encryptor:
password: oRqdnDbK5pj3eMmB

fm:
exception: false
exception_emails: houtaikaifa@iformall.com
deploy: 1
open: true
upload_dir: /home/test/server/uploads/

logging:
level:
com.iformall: debug
path: ./logs/c

+ 122
- 0
mallinkPublicApi/src/main/resources/application-prod.yml Wyświetl plik

@@ -0,0 +1,122 @@
spring:
profiles:
include: aliyunRocketMQ
# JDBC
datasource:
url: jdbc:mysql://zc349w82qvn56ftl5e64-rw4rm.rwlb.rds.aliyuncs.com:3306/mallink?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true
username: ENC(nUefcxWYlMS/1cDxikIKwA==)
password: ENC(neToS+hzeFjgSFB/7UEl5qYnW2rUjrPq)
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 28000
minEvictableIdleTimeMillis: 28000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
# REDIS
redis:
host: r-2zeaglwf13qqmnllj5.redis.rds.aliyuncs.com
port: 6379
password: mallone:iF0rm@2l2ol9
timeout: 3600
expire: 1800 #30分钟
database: 1
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 100
max-wait: -1
min-idle: 10
# SMS
aliyun:
sms:
accessKeyId: LTAI4G7ixY4AhvM35F8o3W3V
accessKeySecret: VfWqGb83qIQrS9us45utskl8itd7ry
product: Dysmsapi
domain: dysmsapi.aliyuncs.com
regionId: cn-hangzhou
dateFormat: yyyyMMdd
endpointName: cn-hangzhou
oss:
endpoint: oss-cn-beijing.aliyuncs.com
keyid: LTAI4G7ixY4AhvM35F8o3W3V
keysecret: VfWqGb83qIQrS9us45utskl8itd7ry
bucketname: formall
filehost: malinkadmin
filedomain: https://formall.oss-accelerate.aliyuncs.com
# EMAIL
mail:
host: smtp.exmail.qq.com
username: sysadministor@iformall.com # 登陆密码sysAdmin1231
password: SWqPekCEmhUYuYCd # 授权密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
# RABBITMQ
rabbitmq:
host: localhost
port: 5672
username: ENC(lRmLd6EzgeY1RT5ktcHv9g==)
password: ENC(gBI8mCjr3OC0v57jcnSb660Ux7mW03K2oePgvohhg7w=)
publisher-confirms: true
publisher-returns: false
virtual-host: /
aliyunRocketmq:
accessKeyId: "LTAI4G7ixY4AhvM35F8o3W3V"
accessKeySecret: "VfWqGb83qIQrS9us45utskl8itd7ry"
groupId: "GID_P_1"
namesrvAddr: "http://MQ_INST_1796289517488555_Bcqaq2is.cn-beijing.mq-internal.aliyuncs.com:8080"
aws:
clientRegion: cn-northwest-1
bucketName: iformall-net
access: ENC(a6SN1sZ1enNL49ypiOXkg/pPPAnZD8H4buQFTTKN08s=)
secret: ENC(5P5ff4bTMJUbXVR4ZsM03UHzOKZ4+Zg5Iutcdkyp/Quny/oXg+A4KpfwEyGarlLu3vQMJahGP5M=)

wechat:
open:
componentAppId: ENC(b3JG0MUZgQfz5Zj+DC2ZM1zDeLOiGTmmeokfe2O8kaM=)
componentSecret: ENC(QVyc4BPGdnSjXGs2ivgpDBE1v8wPWHLLRMYI7Vv8uYwC0SiZHQz0QpyyQV/b48Pb)
componentToken: ENC(rkxj0733WxFFDLgA9x01m2s5Fi2L+0PC)
componentAesKey: ENC(EIbJUBpbYOrLb4YQ/HXLQmxlxgAqIp2ZmpnGICC8pu5xiTz3Cqfkbwd2S8raCcK/IvYcX2GmedI=)
redis:
host: r-2zeaglwf13qqmnllj5.redis.rds.aliyuncs.com
port: 6379
password: mallone:iF0rm@2l2ol9
timeout: 3600
expire: 1800 #30分钟
database: 2
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 100
max-wait: -1
min-idle: 10

fm:
exception: true
exception_emails: houtaikaifa@iformall.com
deploy: 3
open: true
upload_dir: /root/uploads/

logging:
level:
com.iformall: debug
path: ./logs/c

+ 145
- 0
mallinkPublicApi/src/main/resources/application-prodDetry.yml Wyświetl plik

@@ -0,0 +1,145 @@
spring:
profiles:
include: aliyunRocketMQ
# JDBC
datasource:
url: jdbc:mysql://rm-2zel9i9t555zy7lftmo.mysql.rds.aliyuncs.com:3306/mallink?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true&allowMultiQueries=true
username: mallone
password: m@l9oNEl20#@
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 28000
minEvictableIdleTimeMillis: 28000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
connectionProperties: "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=60000"
# REDIS
redis:
host: r-2zeaglwf13qqmnllj5pd.redis.rds.aliyuncs.com
port: 6379
password: mallone:iF0rm@2l2ol9
timeout: 3600
expire: 1800 #30分钟
database: 1
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 20
max-wait: -1
min-idle: 0
# SMS
aliyun:
sms:
accessKeyId: LTAI4G7ixY4AhvM35F8o3W3V
accessKeySecret: VfWqGb83qIQrS9us45utskl8itd7ry
product: Dysmsapi
domain: dysmsapi.aliyuncs.com
regionId: cn-hangzhou
dateFormat: yyyyMMdd
endpointName: cn-hangzhou
oss:
endpoint: oss-cn-beijing.aliyuncs.com
keyid: LTAI4G7ixY4AhvM35F8o3W3V
keysecret: VfWqGb83qIQrS9us45utskl8itd7ry
bucketname: formall
filehost: malinkadmin
filedomain: https://formall.oss-accelerate.aliyuncs.com
# EMAIL
mail:
host: smtp.exmail.qq.com
username: zhengfangyuan@iformall.com
password: xnydCeUzofB2h8qp # 授权密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
# RABBITMQ
rabbitmq:
host: localhost
port: 5672
username: admin
password: ibh2D9R3v2DEN3gk
#username: ENC(lRmLd6EzgeY1RT5ktcHv9g==)
#password: ENC(gBI8mCjr3OC0v57jcnSb660Ux7mW03K2oePgvohhg7w=)
publisher-confirms: true
publisher-returns: false
virtual-host: /
#
aliyunRocketmq:
accessKeyId: "LTAI4G7ixY4AhvM35F8o3W3V"
accessKeySecret: "VfWqGb83qIQrS9us45utskl8itd7ry"
groupId: "GID_P_1"
namesrvAddr: "http://MQ_INST_1796289517488555_Bcqaq2is.cn-beijing.mq-internal.aliyuncs.com:8080"
flyway:
enabled: false

aws:
clientRegion: cn-northwest-1
bucketName: iformall-net
access: AKIAOEHX2MJVBURWTB3Q
secret: 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
#access: ENC(a6SN1sZ1enNL49ypiOXkg/pPPAnZD8H4buQFTTKN08s=)
#secret: ENC(5P5ff4bTMJUbXVR4ZsM03UHzOKZ4+Zg5Iutcdkyp/Quny/oXg+A4KpfwEyGarlLu3vQMJahGP5M=)

wechat:
web:
appId: "wx9cc4ca09eb20fe03"
secret: "af1d7f7a1268022a73cb4ce0b9cf0985"
url: "https://admin.malls.iformall.com"
open:
componentAppId: wx7f58f461ec1e2b4f
componentSecret: 7eb9b795606739b5526dd7f61d923f5a
componentToken: formall2018
componentAesKey: htKq8EjBMPNndfZQK9JiFojFaqFwFpw42VfeWFtx7HN
#componentAppId: ENC(b3JG0MUZgQfz5Zj+DC2ZM1zDeLOiGTmmeokfe2O8kaM=)
#componentSecret: ENC(QVyc4BPGdnSjXGs2ivgpDBE1v8wPWHLLRMYI7Vv8uYwC0SiZHQz0QpyyQV/b48Pb)
#componentToken: ENC(rkxj0733WxFFDLgA9x01m2s5Fi2L+0PC)
#componentAesKey: ENC(EIbJUBpbYOrLb4YQ/HXLQmxlxgAqIp2ZmpnGICC8pu5xiTz3Cqfkbwd2S8raCcK/IvYcX2GmedI=)
redis:
host: r-2zeaglwf13qqmnllj5pd.redis.rds.aliyuncs.com
port: 6379
password: mallone:iF0rm@2l2ol9
timeout: 3600
expire: 1800 #30分钟
database: 2
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 100
max-wait: -1
min-idle: 10

fm:
exception: true
exception_emails: houtaikaifa@iformall.com
deploy: 3
open: true
upload_dir: /root/uploads/

ueditor:
config: config.json
unified: true
upload-path: ./upload/
url-prefix: ""

logging:
level:
com.iformall.mapper: debug
path: ./logs/admin

+ 100
- 0
mallinkPublicApi/src/main/resources/application-test.yml-bak Wyświetl plik

@@ -0,0 +1,100 @@
spring:
profiles:
include: rabbitMQ
# JDBC
datasource:
url: jdbc:mysql://formalldb.cfqyqflkdlit.rds.cn-northwest-1.amazonaws.com.cn:3306/mallinkTest?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=UTF-8&useSSL=false&useAffectedRows=true
username: ENC(Uc0AjgkytxHHCwZrmDASWg==)
password: ENC(nV4Mi3bEbBx0Fj7uUyYH55eTaqsFMjKvmNzagicH4pc=)
type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
filters: stat
maxActive: 20
initialSize: 1
maxWait: 60000
minIdle: 1
timeBetweenEvictionRunsMillis: 28000
minEvictableIdleTimeMillis: 28000
validationQuery: select 'x'
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
maxOpenPreparedStatements: 20
# REDIS
redis:
host: 127.0.0.1
port: 6379
password: ENC(QFwqv3NshvvGhFPiP8rwhvbnxk+rFSqhJi8Pw6TogSg=)
timeout: 3600
expire: 1800 #30分钟
database: 1
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 8
max-idle: 8
max-wait: -1
min-idle: 0
# EMAIL
mail:
host: smtp.exmail.qq.com
username: ENC(TtJQE2C4cWo8CpVGMMl5hiy5eykepd96J5XjsW3Kj5fgP+6+5ctDNQ==)
password: ENC(Zh6A6kRtA2ABtH6nzdvsqQSO1/8p3mparJr8neI2BLU=) # 授权密码
properties:
mail:
smtp:
auth: true
starttls:
enable: true
socketFactory:
port: 465
class: javax.net.ssl.SSLSocketFactory
# RABBITMQ
rabbitmq:
host: 127.0.0.1
port: 5672
username: ENC(aSRr6mnSryEqzHHz1hJf1g==)
password: ENC(GnjF/mdqKdvmDYC0tIIso7+20/jBALPw39tiWCYJ4iw=)
publisher-confirms: true
publisher-returns: false
virtual-host: /

aws:
clientRegion: cn-northwest-1
bucketName: iformall-net
access: ENC(NCLcmjwKpAWdn/abD17OKIY7yKepVLWzEpqRYUlURCw=)
secret: ENC(TRcZqql0Rq5PExlMeH/4WiZ/i02b8FXKmLTBChJmbluTa1uoLS9LrHyNEMrqe1DK+QgOAdvqGBo=)

wechat:
open:
componentAppId: ENC(hnH31XdNzArfMfikKgBFpqQuJUl6rVOPFFcAVyb595o=)
componentSecret: ENC(t/GUVX5L+U7LCwSvZ5WmxAnmTMrc/Uy1nljsrokuzzsBL2j6BEVnrS/n7DCdGc/G)
componentToken: ENC(gUF1m0YgCCI2IY54fX6sGLZVlCswA8tG)
componentAesKey: ENC(TYHcrIkICtfrCfGq4HW6s1b/pHf7OD2uyPN11SzJNB0acqJ/4JVX1nuljo/cAtgMG4O05TImLQc=)
redis:
host: 127.0.0.1
port: 6379
password: ENC(QFwqv3NshvvGhFPiP8rwhvbnxk+rFSqhJi8Pw6TogSg=)
timeout: 3600
expire: 1800 #30分钟
database: 2
defaultExpiration: 2592000 # 默认生命周期30天
jedis:
pool:
max-active: 100
max-idle: 100
max-wait: -1
min-idle: 10

fm:
exception: true
exception_emails: houtaikaifa@iformall.com
deploy: 2
open: true
upload_dir: /home/ec2-user/server/uploads/

logging:
level:
com.iformall: debug
path: ./logs/c

+ 54
- 0
mallinkPublicApi/src/main/resources/application.yml Wyświetl plik

@@ -0,0 +1,54 @@
server:
port: 7000
servlet:
context-path: /C

spring:
application:
name: mallink
profiles:
active: dev
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
default-property-inclusion: non_null
# rocketmq:
# nameServer: 127.0.0.1:9876
# producer:
# retry-times-when-send-async-failed: 0
# send-msg-timeout: 300000
# compress-msg-body-over-howmuch: 4096
# max-message-size: 4194304
# retry-another-broker-when-not-store-ok: false
# retry-times-when-send-failed: 2

# MybatisPlus
mybatis-plus:
mapper-locations: classpath:mapper/*Mapper.xml
global-config:
db-config:
id-type: id_worker
field-strategy: not_null
db-type: mysql
configuration:
jdbc-type-for-null: 'null'
cache-enabled: false
call-setters-on-nulls: true
type-aliases-package: com.iformall.domain.po
type-enums-package: com.iformall.enums

# PageHelper
pagehelper:
helperDialect: mysql
reasonable: false
supportMethodsArguments: true
params: count=countSql
offset-as-page-num: true
page-size-zero: true
row-bounds-with-count: true

mapper:
mappers:
- com.iformall.common.CommonMapper

version: @project.version@

BIN
mallinkPublicApi/src/main/resources/imgTemp/gertificate.jpg Wyświetl plik

Przed Po
Szerokość: 3301  |  Wysokość: 2551  |  Rozmiar: 7.0 MiB

+ 100
- 0
mallinkPublicApi/src/main/resources/logback-spring.xml Wyświetl plik

@@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 seconds">
<!-- 外部指定路径 -->
<springProperty scop="context" name="logPath" source="logging.path" />

<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<Pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] --%mdc{client}%msg%n</Pattern>
</encoder>
</appender>

<appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/trace.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/trace.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>30</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
</appender>

<appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/info.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>30</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>INFO</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/debug.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/debug.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>30</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>


<appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/warn.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/warn.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>30</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>WARN</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>



<appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>${logPath}/error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<FileNamePattern>${logPath}/daily/error.%d{yyyy-MM-dd}.log</FileNamePattern>
<maxHistory>30</maxHistory> <!-- 保留180天 -->
</rollingPolicy>
<layout>
<pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}] [%-5level] [%logger:%line]--%mdc{client} %msg%n</pattern>
</layout>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>ERROR</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>DENY</onMismatch>
</filter>
</appender>

<root level="TRACE">
<appender-ref ref="TRACE_FILE" />
<appender-ref ref="INFO_FILE" />
<!-- <appender-ref ref="DEBUG_FILE" /> -->
<!-- <appender-ref ref="WARN_FILE" /> -->
<appender-ref ref="ERROR_FILE" />
</root>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

BIN
mallinkPublicApi/src/main/resources/opt/HWLS.TTF Wyświetl plik


+ 1
- 0
pom.xml Wyświetl plik

@@ -22,6 +22,7 @@
<module>mallinkSchedule</module> <module>mallinkSchedule</module>
<module>mallinkMQConsumer</module> <module>mallinkMQConsumer</module>
<module>mallinkWebSocketServer</module> <module>mallinkWebSocketServer</module>
<module>mallinkPublicApi</module>
</modules> </modules>


<parent> <parent>


Ładowanie…
Anuluj
Zapisz