diff --git a/mallinkService/src/main/java/com/iformall/domain/po/WxAuthorizerInfo.java b/mallinkService/src/main/java/com/iformall/domain/po/WxAuthorizerInfo.java index 28fa154..145d8e0 100644 --- a/mallinkService/src/main/java/com/iformall/domain/po/WxAuthorizerInfo.java +++ b/mallinkService/src/main/java/com/iformall/domain/po/WxAuthorizerInfo.java @@ -54,6 +54,8 @@ public class WxAuthorizerInfo extends BaseEntity { private Integer templateStatus; @io.swagger.annotations.ApiModelProperty(value="微信小程序模板设置时间",name="templateTime") private Date templateTime; + @io.swagger.annotations.ApiModelProperty(value="微信小程序用户隐私指引,0为已设置,1为设置失败",name="privacySettingStatus") + private Integer privacySettingStatus; @io.swagger.annotations.ApiModelProperty(value="小程序每月审核撤回次数",name="auditBackNum") private Integer auditBackNum; @io.swagger.annotations.ApiModelProperty(value="微信小程序审核最后撤回时间",name="auditBackTime") diff --git a/mallinkService/src/main/java/com/iformall/domain/po/WxWeappBasicSet.java b/mallinkService/src/main/java/com/iformall/domain/po/WxWeappBasicSet.java index ee8b442..19ec396 100644 --- a/mallinkService/src/main/java/com/iformall/domain/po/WxWeappBasicSet.java +++ b/mallinkService/src/main/java/com/iformall/domain/po/WxWeappBasicSet.java @@ -25,6 +25,8 @@ public class WxWeappBasicSet extends BaseEntity { private String version; @io.swagger.annotations.ApiModelProperty(value="模板库信息",name="templateInfo") private String templateInfo; + @io.swagger.annotations.ApiModelProperty(value="小程序用户隐私保护指引",name="privacySetting") + private String privacySetting; @io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate") private Date createDate; @io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate") diff --git a/mallinkService/src/main/java/com/iformall/service/WxAuthorizerInfoService.java b/mallinkService/src/main/java/com/iformall/service/WxAuthorizerInfoService.java index d060c54..f096230 100644 --- a/mallinkService/src/main/java/com/iformall/service/WxAuthorizerInfoService.java +++ b/mallinkService/src/main/java/com/iformall/service/WxAuthorizerInfoService.java @@ -84,4 +84,5 @@ public interface WxAuthorizerInfoService { int updateAuthBackInfo(WxAuthorizerInfo record); + int updatePrivacySetting(WxAuthorizerInfo authorizerInfo); } diff --git a/mallinkService/src/main/java/com/iformall/service/impl/WxAuthorizerInfoServiceImpl.java b/mallinkService/src/main/java/com/iformall/service/impl/WxAuthorizerInfoServiceImpl.java index 199429d..ef98284 100644 --- a/mallinkService/src/main/java/com/iformall/service/impl/WxAuthorizerInfoServiceImpl.java +++ b/mallinkService/src/main/java/com/iformall/service/impl/WxAuthorizerInfoServiceImpl.java @@ -229,9 +229,16 @@ public class WxAuthorizerInfoServiceImpl implements WxAuthorizerInfoService { } return 0; } - - - - - + + @Override + public int updatePrivacySetting(WxAuthorizerInfo record) { + Date curDate = new Date(); + WxAuthorizerInfo info = new WxAuthorizerInfo(); + info.setId(record.getId()); + info.setPrivacySettingStatus(record.getPrivacySettingStatus()); + info.setUpdateTime(curDate); + return authorizerInfoMapper.updateById(info); + } + + } diff --git a/mallinkService/src/main/resources/mapper/WxAuthorizerInfoMapper.xml b/mallinkService/src/main/resources/mapper/WxAuthorizerInfoMapper.xml index 8304129..a745220 100644 --- a/mallinkService/src/main/resources/mapper/WxAuthorizerInfoMapper.xml +++ b/mallinkService/src/main/resources/mapper/WxAuthorizerInfoMapper.xml @@ -21,6 +21,8 @@ + + @@ -34,6 +36,7 @@ `id`,`tenant_id`,`type`,`authorizer_appid`,`head_img`,`alias`,`qrcode_url`,`create_time`,`authorization_status`,`auth_time`, `base_status`, `base_time`, `domain_status`, `domain_time`, `webdomain_status`, `webdomain_time`, `template_status`, `template_time`, + `privacy_setting_status`, `current_version`,`current_desc`,`release_time`, `open_appid`,`bind_open_time`,`refresh_token`, `access_token`,`access_token_expire` @@ -98,6 +101,9 @@ and `template_time` = #{templateTime} + + and `privacy_setting_status` = #{privacySettingStatus} + and `current_version` = #{currentVersion} @@ -201,6 +207,8 @@ + + @@ -216,6 +224,7 @@ ai.`domain_status`,ai.`domain_time`, ai.`webdomain_status`,ai.`webdomain_time`, ai.`template_status`,ai.`template_time`, + ai.`privacy_setting_status`, ai.`current_version` as `current_version`,ai.`current_desc`,ai.`release_time`, ai.`open_appid`,ai.`bind_open_time`, a.`name` as `name` @@ -268,6 +277,9 @@ and ai.`template_time` = #{templateTime} + + and ai.`privacy_setting_status` = #{privacySettingStatus} + and ai.`current_version` = #{currentVersion} diff --git a/mallinkService/src/main/resources/mapper/WxWeappBasicSetMapper.xml b/mallinkService/src/main/resources/mapper/WxWeappBasicSetMapper.xml index fdaf5d3..087f24a 100644 --- a/mallinkService/src/main/resources/mapper/WxWeappBasicSetMapper.xml +++ b/mallinkService/src/main/resources/mapper/WxWeappBasicSetMapper.xml @@ -8,12 +8,13 @@ + - `id`,`type`,`domain_url`,`version`,`template_info`,`create_date`,`update_date` + `id`,`type`,`domain_url`,`version`,`template_info`,`privacy_setting`,`create_date`,`update_date` diff --git a/mlToutiaoOpen/.gitignore b/mlToutiaoOpen/.gitignore new file mode 100644 index 0000000..b83d222 --- /dev/null +++ b/mlToutiaoOpen/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/mlToutiaoOpen/pom.xml b/mlToutiaoOpen/pom.xml new file mode 100644 index 0000000..266017e --- /dev/null +++ b/mlToutiaoOpen/pom.xml @@ -0,0 +1,179 @@ + + + 4.0.0 + + + mallink + com.iformall + 1.0 + + + mlToutiaoOpen + + + + + + + com.iformall + mallinkService + 1.0 + + + com.fasterxml.jackson.core + jackson-core + + + + + + com.google.zxing + core + 3.3.3 + + + + com.github.axet + kaptcha + 0.0.9 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + true + ZIP + + 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.sun.xml.messaging.saaj, + 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 + + + + + + + \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/WechatOpenApplication.java b/mlToutiaoOpen/src/main/java/com/iformall/WechatOpenApplication.java new file mode 100644 index 0000000..e371a1e --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/WechatOpenApplication.java @@ -0,0 +1,62 @@ +package com.iformall; + +import com.ulisesbocchio.jasyptspringboot.annotation.EnableEncryptableProperties; +import org.mybatis.spring.annotation.MapperScan; +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 springfox.documentation.swagger2.annotations.EnableSwagger2; + +/** + * @author stormeye + * @date 2019-01-14 + */ +@SpringBootApplication +@MapperScan("com.iformall.mapper") +@EnableSwagger2 +@EnableEncryptableProperties +public class WechatOpenApplication { + + @Value("${fm.exception}") + private boolean fmException; + + @Value("${fm.exception_emails}") + private String fmExceptionEmails; + + @Value("${fm.audit_emails}") + private String fmAuditEmails; + + @Value("${fm.deploy}") + private Integer fmDeploy; + + @Value("${fm.upload_dir}") + private String uploadDir; + + @Bean + public boolean isFmException() { + return fmException; + } + + @Bean + public String fmExceptionEmails() { + return fmExceptionEmails; + } + + @Bean + public String fmAuditEmails() { + return fmAuditEmails; + } + + @Bean + public Integer getFmDeploy() { return fmDeploy; } + + @Bean + public String fmUploadDir() { + return uploadDir; + } + + public static void main(String[] args) { + SpringApplication.run(WechatOpenApplication.class, args); + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/AsyncConfig.java b/mlToutiaoOpen/src/main/java/com/iformall/config/AsyncConfig.java new file mode 100644 index 0000000..f41fec6 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/AsyncConfig.java @@ -0,0 +1,59 @@ +package com.iformall.config; + + +import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.AsyncConfigurer; +import org.springframework.scheduling.annotation.EnableAsync; +import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.lang.reflect.Method; +import java.util.concurrent.Executor; +import java.util.concurrent.ThreadPoolExecutor; + +@Configuration +@EnableAsync +public class AsyncConfig implements AsyncConfigurer { + private Logger logger = LoggerFactory.getLogger(getClass()); + + @Value("${thread.pool.corePoolSize:10}") + private int corePoolSize; + + @Value("${thread.pool.maxPoolSize:20}") + private int maxPoolSize; + + @Value("${thread.pool.keepAliveSeconds:4}") + private int keepAliveSeconds; + + @Value("${thread.pool.queueCapacity:512}") + private int queueCapacity; + + @Override + public Executor getAsyncExecutor() { + ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); + executor.setCorePoolSize(corePoolSize); + executor.setMaxPoolSize(maxPoolSize); + executor.setKeepAliveSeconds(keepAliveSeconds); + executor.setQueueCapacity(queueCapacity); + executor.setRejectedExecutionHandler((Runnable r, ThreadPoolExecutor exe) -> { + logger.warn("当前任务线程池队列已满."); + }); + executor.initialize(); + logger.info("限定线程池大小"); + return executor; + } + + @Override + public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() { + return new AsyncUncaughtExceptionHandler() { + @Override + public void handleUncaughtException(Throwable ex, Method method, Object... params) { + logger.error("线程池执行任务发生未知异常.", ex); + } + }; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/AwsProperty.java b/mlToutiaoOpen/src/main/java/com/iformall/config/AwsProperty.java new file mode 100644 index 0000000..0329f1d --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/AwsProperty.java @@ -0,0 +1,52 @@ +package com.iformall.config; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * @author Stormeye + */ +@Component +@ConfigurationProperties(prefix = "aws") +public class AwsProperty { + // AWS ACCESS KEY + private String access; + + private String secret; + + private String clientRegion; + + private String bucketName; + + public String getAccess() { + return access; + } + + public void setAccess(String access) { + this.access = access; + } + + public String getSecret() { + return secret; + } + + public void setSecret(String secret) { + this.secret = secret; + } + + public String getClientRegion() { + return clientRegion; + } + + public void setClientRegion(String clientRegion) { + this.clientRegion = clientRegion; + } + + public String getBucketName() { + return bucketName; + } + + public void setBucketName(String bucketName) { + this.bucketName = bucketName; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/KaptchaConfig.java b/mlToutiaoOpen/src/main/java/com/iformall/config/KaptchaConfig.java new file mode 100644 index 0000000..8d20c08 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/KaptchaConfig.java @@ -0,0 +1,32 @@ +package com.iformall.config; + +import com.google.code.kaptcha.impl.DefaultKaptcha; +import com.google.code.kaptcha.util.Config; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Properties; + + +/** + * 生成验证码配置 + * + * @author stormeye.wu + * @email wugq@mippoint.com + * @date 2017-04-20 19:22 + */ +@Configuration +public class KaptchaConfig { + + @Bean + public DefaultKaptcha producer() { + Properties properties = new Properties(); + properties.put("kaptcha.border", "no"); + properties.put("kaptcha.textproducer.font.color", "black"); + properties.put("kaptcha.textproducer.char.space", "5"); + Config config = new Config(properties); + DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); + defaultKaptcha.setConfig(config); + return defaultKaptcha; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/RedisConfig.java b/mlToutiaoOpen/src/main/java/com/iformall/config/RedisConfig.java new file mode 100644 index 0000000..bc9721f --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/RedisConfig.java @@ -0,0 +1,72 @@ +package com.iformall.config; + +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.connection.RedisConnectionFactory; + +import java.time.Duration; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + * 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 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; + */ + RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 生成一个默认配置,通过config对象即可对缓存进行自定义配置 + config = config.entryTtl(Duration.ofMinutes(1)) // 设置缓存的默认过期时间,也是使用Duration设置 + .disableCachingNullValues(); // 不缓存空值 + + // 设置一个初始化的缓存空间set集合 + Set cacheNames = new HashSet<>(); + cacheNames.add("my-redis-cache1"); + cacheNames.add("my-redis-cache2"); + + // 对每个缓存空间应用不同的配置 + Map configMap = new HashMap<>(); + configMap.put("my-redis-cache1", config); + configMap.put("my-redis-cache2", config.entryTtl(Duration.ofSeconds(120))); + + RedisCacheManager cacheManager = RedisCacheManager.builder(connectionFactory) // 使用自定义的缓存配置初始化一个cacheManager + .initialCacheNames(cacheNames) // 注意这两句的调用顺序,一定要先调用该方法设置初始化的缓存名,再初始化相关的配置 + .withInitialCacheConfigurations(configMap) + .build(); + return cacheManager; + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/RestFilter.java b/mlToutiaoOpen/src/main/java/com/iformall/config/RestFilter.java new file mode 100644 index 0000000..4f92984 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/RestFilter.java @@ -0,0 +1,58 @@ +package com.iformall.config; + +import java.io.IOException; +import java.util.Optional; + +import javax.servlet.Filter; +import javax.servlet.FilterChain; +import javax.servlet.FilterConfig; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** + * 前后端分离RESTful接口过滤器 + * + * @author xuguoqin + * + */ +public class RestFilter implements Filter { + + @Override + public void init(FilterConfig filterConfig) throws ServletException { + + } + + @Override + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { + HttpServletRequest req = null; + if (request instanceof HttpServletRequest) { + req = (HttpServletRequest) request; + } + HttpServletResponse res = null; + if (response instanceof HttpServletResponse) { + res = (HttpServletResponse) response; + } + if (req != null && res != null) { + //设置允许传递的参数 + res.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization"); + //设置允许带上cookie + res.setHeader("Access-Control-Allow-Credentials", "true"); + String origin = Optional.ofNullable(req.getHeader("Origin")).orElse(req.getHeader("Referer")); + //设置允许的请求来源 + res.setHeader("Access-Control-Allow-Origin", origin); + //设置允许的请求方法 + res.setHeader("Access-Control-Allow-Methods", "GET, POST, PATCH, PUT, DELETE, OPTIONS"); + } + chain.doFilter(request, response); + } + + @Override + public void destroy() { + + } + +} \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/RestTemplateConfig.java b/mlToutiaoOpen/src/main/java/com/iformall/config/RestTemplateConfig.java new file mode 100644 index 0000000..560a77c --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/RestTemplateConfig.java @@ -0,0 +1,24 @@ +package com.iformall.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.client.ClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +@Configuration +public class RestTemplateConfig { + + @Bean + public RestTemplate restTemplate(ClientHttpRequestFactory factory) { + return new RestTemplate(factory); + } + + @Bean + public ClientHttpRequestFactory simpleClientHttpRequestFactory() { + SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory(); + factory.setReadTimeout(5000);//ms + factory.setConnectTimeout(10000);//ms + return factory; + } +} \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/ShiroConfig.java b/mlToutiaoOpen/src/main/java/com/iformall/config/ShiroConfig.java new file mode 100644 index 0000000..7e5d2f3 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/ShiroConfig.java @@ -0,0 +1,305 @@ +package com.iformall.config; + +import com.iformall.service.MallPermissionService; +import com.iformall.shiro.MyRetryLimitCredentialsMatcher; +import com.iformall.shiro.MyShiroRealm; +import org.apache.shiro.mgt.SecurityManager; +import org.apache.shiro.spring.LifecycleBeanPostProcessor; +import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.mgt.DefaultWebSecurityManager; +import org.apache.shiro.web.servlet.SimpleCookie; +import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; +import org.crazycake.shiro.RedisCacheManager; +import org.crazycake.shiro.RedisManager; +import org.crazycake.shiro.RedisSessionDAO; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.servlet.Filter; +import javax.servlet.ServletRequest; +import javax.servlet.http.HttpServletRequest; +import java.util.LinkedHashMap; +import java.util.Map; + + +/** + * Created by yangqj on 2017/4/23. + */ +@Configuration +public class ShiroConfig { + @Autowired(required = false) + private MallPermissionService resourcesService; + + @Value("${spring.redis.host}") + private String host; + + @Value("${spring.redis.port}") + private int port; + + @Value("${spring.redis.timeout}") + private int timeout; + + @Value("${spring.redis.expire}") + private int expire; + + @Value("${spring.redis.password}") + private String password; + + @Bean + public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { + return new LifecycleBeanPostProcessor(); + } + + /** + * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean + * @return + */ +// @Bean +// public ShiroDialect shiroDialect() { +// return new ShiroDialect(); +// } + + /** + * ShiroFilterFactoryBean 处理拦截资源文件问题。 + * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在 + * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager + *

+ * Filter Chain定义说明 + * 1、一个URL可以配置多个Filter,使用逗号分隔 + * 2、当设置多个过滤器时,全部验证通过,才视为通过 + * 3、部分过滤器可指定参数,如perms,roles + */ + @Bean + public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { + System.out.println("ShiroConfiguration.shirFilter()"); + ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); + // 必须设置 SecurityManager + shiroFilterFactoryBean.setSecurityManager(securityManager); + Map filters = new LinkedHashMap(); + filters.put("token", new ShiroLoginFilter()); + filters.put("corsFilter", new RestFilter()); + //filters.put("authc", new MyFormAuthenticationFilter()); + shiroFilterFactoryBean.setFilters(filters); + // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 + shiroFilterFactoryBean.setLoginUrl("/#/"); + // 登录成功后要跳转的链接 + + shiroFilterFactoryBean.setSuccessUrl("/usersPage"); + //未授权界面; + shiroFilterFactoryBean.setUnauthorizedUrl("/403"); + //拦截器. + Map filterChainDefinitionMap = new LinkedHashMap(); + + //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 + + //filterChainDefinitionMap.put("/ue/**", "anon"); + //filterChainDefinitionMap.put("/config.json", "anon"); + + // 静态文件 + filterChainDefinitionMap.put("/css/**", "anon"); + filterChainDefinitionMap.put("/js/**", "anon"); + filterChainDefinitionMap.put("/img/**", "anon"); + filterChainDefinitionMap.put("/font-awesome/**", "anon"); + //:这是一个坑呢,一不小心代码就不好使了; + // + //自定义加载权限资源关系 +// Map map = new HashMap<>(); +// List resourcesList = resourcesService.list(map); +// for(SysPermission resources:resourcesList){ +// +// if (StringUtil.isNotEmpty(resources.getUrl())) { +// String permission = "perms[" + resources.getUrl()+ "]"; +// filterChainDefinitionMap.put(resources.getUrl(),permission); +// } +// } + + // 登录 + filterChainDefinitionMap.put("/captcha.jpg", "anon"); + filterChainDefinitionMap.put("/doLogin/**", "anon"); + filterChainDefinitionMap.put("/version", "anon"); + + /// swagger-ui.html + filterChainDefinitionMap.put("/swagger-ui.html", "anon"); + filterChainDefinitionMap.put("/v2/**", "anon"); + filterChainDefinitionMap.put("/swagger-resources/**", "anon"); + filterChainDefinitionMap.put("/webjars/**", "anon"); + + // 第三方平台 + filterChainDefinitionMap.put("/wxOpen/**", "anon"); + filterChainDefinitionMap.put("/wx/**", "anon"); + filterChainDefinitionMap.put("/wxCardIO/**", "anon"); + + +// filterChainDefinitionMap.put("/role/**", "corsFilter,token"); + filterChainDefinitionMap.put("/**", "corsFilter,token,authc"); +// filterChainDefinitionMap.put("/**", "anon"); + + + shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); + return shiroFilterFactoryBean; + } + + + public static boolean isAjax(ServletRequest request) { + String header = ((HttpServletRequest) request).getHeader("X-Requested-With"); + if ("XMLHttpRequest".equalsIgnoreCase(header)) { + System.out.println("当前请求为Ajax请求"); + return Boolean.TRUE; + } + System.out.println("当前请求非Ajax请求"); + return Boolean.FALSE; + } + + @Bean + public SecurityManager securityManager(@Qualifier("retryLimitCredentialsMatcher") MyRetryLimitCredentialsMatcher matcher) { + DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); + //设置realm. + securityManager.setRealm(myShiroRealm(matcher)); + // 自定义缓存实现 使用redis + //securityManager.setCacheManager(cacheManager()); + // 自定义session管理 使用redis + securityManager.setSessionManager(sessionManager()); + return securityManager; + } + + @Bean + public MyShiroRealm myShiroRealm(MyRetryLimitCredentialsMatcher matcher) { + MyShiroRealm myShiroRealm = new MyShiroRealm(); + myShiroRealm.setCredentialsMatcher(matcher); + return myShiroRealm; + } + + + /** + * 密码匹配凭证管理器 凭证匹配器 + * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 + * 所以我们需要修改下doGetAuthenticationInfo中的代码; + * ) + * + * @return + */ + @Bean(name = "retryLimitCredentialsMatcher") + public MyRetryLimitCredentialsMatcher hashedCredentialsMatcher() { + MyRetryLimitCredentialsMatcher hashedCredentialsMatcher = new MyRetryLimitCredentialsMatcher(); + + hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法; + hashedCredentialsMatcher.setHashIterations(2);//散列的次数,比如散列两次,相当于 md5(md5("")); + + return hashedCredentialsMatcher; + } + + + /** + * 开启shiro aop注解支持. + * 使用代理方式;所以需要开启代码支持; + * + * @param securityManager + * @return + */ + @Bean + public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { + AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); + authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); + return authorizationAttributeSourceAdvisor; + } + + /** + * 配置shiro redisManager + * 使用的是shiro-redis开源插件 + * + * @return + */ + public RedisManager redisManager() { + RedisManager redisManager = new RedisManager(); + redisManager.setHost(host); + redisManager.setPort(port); + //redisManager.setExpire(expire);// 配置缓存过期时间 + redisManager.setTimeout(timeout); + redisManager.setPassword(password); + return redisManager; + } + + /** + * cacheManager 缓存 redis实现 + * 使用的是shiro-redis开源插件 + * + * @return + */ + public RedisCacheManager cacheManager() { + RedisCacheManager redisCacheManager = new RedisCacheManager(); + redisCacheManager.setRedisManager(redisManager()); + return redisCacheManager; + } + + + /** + * RedisSessionDAO shiro sessionDao层的实现 通过redis + * 使用的是shiro-redis开源插件 + */ + @Bean + public RedisSessionDAO redisSessionDAO() { + RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); + redisSessionDAO.setRedisManager(redisManager()); + return redisSessionDAO; + } + + /** + * shiro session的管理 + */ + @Bean + public DefaultWebSessionManager sessionManager() { + DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); + //设置session过期时间为1小时(单位:毫秒),默认为30分钟 + sessionManager.setGlobalSessionTimeout(60 * 60 * 1000); + sessionManager.setSessionValidationSchedulerEnabled(true); + sessionManager.setSessionIdUrlRewritingEnabled(false); + + sessionManager.setSessionDAO(redisSessionDAO()); + sessionManager.setSessionIdCookie(simpleCookie()); + return sessionManager; + } + + @Bean + public SimpleCookie simpleCookie() { + SimpleCookie simpleCookie = new SimpleCookie("SSID"); + simpleCookie.setDomain(""); + return simpleCookie; + } + +// @Bean +// public SimpleCookie rememberMeCookie(){ +// //System.out.println("ShiroConfiguration.rememberMeCookie()"); +// //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe +// SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); +// // +// simpleCookie.setMaxAge(60*30); +// return simpleCookie; +// } + +// @Bean +// public CookieRememberMeManager rememberMeManager(){ +// //System.out.println("ShiroConfiguration.rememberMeManager()"); +// CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); +// cookieRememberMeManager.setCookie(rememberMeCookie()); +// //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位) +// cookieRememberMeManager.setCipherKey(Base64.decodeBytes("2AvVhdsgUs0FSA3SDFAdag==")); +// return cookieRememberMeManager; +// } + +// @Bean(name = "securityManager") +// public DefaultWebSecurityManager defaultWebSecurityManager(MyShiroRealm realm){ +// DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); +// //设置realm +// securityManager.setRealm(realm); +// //用户授权/认证信息Cache, 采用EhCache缓存 +// securityManager.setCacheManager(cacheManager()); +// //注入记住我管理器 +// securityManager.setRememberMeManager(rememberMeManager()); +// return securityManager; +// } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/ShiroLoginFilter.java b/mlToutiaoOpen/src/main/java/com/iformall/config/ShiroLoginFilter.java new file mode 100644 index 0000000..30d8fe4 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/ShiroLoginFilter.java @@ -0,0 +1,31 @@ +package com.iformall.config; + +import com.alibaba.fastjson.JSON; +import com.iformall.common.ResultData; +import org.apache.shiro.web.filter.authc.FormAuthenticationFilter; + +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; + +public class ShiroLoginFilter extends FormAuthenticationFilter { + + @Override + protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { + response.setCharacterEncoding("UTF-8"); + response.setContentType("application/json"); + ResultData resultData = new ResultData(ResultData.UNLOGIN,"用户未登录"); + response.getWriter().write(JSON.toJSONString(resultData)); + return false; + } + + /** + * 判断ajax请求 + * @param request + * @return + */ + boolean isAjax(HttpServletRequest request){ + return (request.getHeader("X-Requested-With") != null && "XMLHttpRequest".equals( request.getHeader("X-Requested-With").toString()) ) ; + } + +} \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/config/WebConfig.java b/mlToutiaoOpen/src/main/java/com/iformall/config/WebConfig.java new file mode 100644 index 0000000..dab30ed --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/config/WebConfig.java @@ -0,0 +1,89 @@ +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.HttpServletRequestWrapperFilter; +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.servlet.config.annotation.CorsRegistry; +import org.springframework.web.servlet.config.annotation.EnableWebMvc; +import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.text.SimpleDateFormat; +import java.util.List; + +@Configuration +@EnableWebMvc +public class WebConfig implements WebMvcConfigurer { + + @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("/**") + .allowedOrigins("*") + .allowCredentials(true) + .allowedMethods("GET", "POST", "DELETE", "PUT") + .maxAge(3600); + } + + @Override + public void configureMessageConverters(List> 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 Filters() { + FilterRegistrationBean registrationBean = new FilterRegistrationBean(); + registrationBean.setFilter(new HttpServletRequestWrapperFilter()); + registrationBean.addUrlPatterns("/*"); + registrationBean.setName("koalaSignFilter"); + return registrationBean; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/HomeController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/HomeController.java new file mode 100644 index 0000000..b370a68 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/HomeController.java @@ -0,0 +1,124 @@ +package com.iformall.controller; + +import com.google.code.kaptcha.Constants; +import com.google.code.kaptcha.Producer; +import com.iformall.common.ErrorCode; +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.domain.po.MallUserInfo; +import com.iformall.exception.MallinkException; +import com.iformall.shiro.UserSession; +import com.iformall.utils.ShiroUtils; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.authc.UsernamePasswordToken; +import org.apache.shiro.subject.Subject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.imageio.ImageIO; +import javax.servlet.ServletException; +import javax.servlet.ServletOutputStream; +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletResponse; +import java.awt.image.BufferedImage; +import java.io.IOException; + + +@RestController +@Api(description = "登录相关接口") +public class HomeController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Value("${version}") + private String version; + + @Autowired + private Producer producer; + + + @GetMapping("/captcha.jpg") + public void captcha(HttpServletResponse response)throws ServletException, IOException { + logger.debug("[" + getIpAddr() + "] HomeController::captcha"); + response.setHeader("Cache-Control", "no-store, no-cache"); + response.setContentType("image/jpeg"); + + //生成文字验证码 + String text = producer.createText(); + //生成图片验证码 + BufferedImage image = producer.createImage(text); + //保存到shiro session + ShiroUtils.setSessionAttribute(Constants.KAPTCHA_SESSION_KEY, text); + + ServletOutputStream out = response.getOutputStream(); + ImageIO.write(image, "jpg", out); + IOUtils.closeQuietly(out); + } + + @ApiOperation("登录") + @PostMapping("/doLogin") + public ResultData login(@RequestBody MallUserInfo user, HttpServletResponse response) { + logger.debug("[" + getIpAddr() + "] HomeController::login"); + + try { + String kaptcha = ShiroUtils.getKaptcha(Constants.KAPTCHA_SESSION_KEY); + if(!user.getCaptcha().equalsIgnoreCase(kaptcha)){ + return new ResultData(ErrorCode.KAPCHA_NOT_EQUAL); + } + } catch (MallinkException e) { + logger.error("验证码" + e.getMessage()); + return new ResultData(ErrorCode.KAPCHA_NOT_VALID.getCode(), e.getMessage()); + } + + + ResultData data = new ResultData(); + if (StringUtils.isBlank(user.getUsername()) || StringUtils.isBlank(user.getPassword())) { +// throw new SystemException(ErrorCode.LOGIN_USER_OR_PWD_ERROR); + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + try { + Subject subject = SecurityUtils.getSubject(); + UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword()); + subject.login(token); + MallUserInfo info = (MallUserInfo) SecurityUtils.getSubject().getSession().getAttribute(UserSession.userInfo); + info.setPassword("保密"); + info.setBopenId("保密"); + if(StringUtils.isNotBlank(info.getWebOpenId())) { + info.setWebOpenId("保密"); + } + + Cookie unameCookie = new Cookie("uname", info.getUsername()); + unameCookie.setMaxAge(60); + response.addCookie(unameCookie); + + data.data = info; + } catch (Exception e) { + return new ResultData(ErrorCode.USER_PASSWD_ERR); + } + return data; + } + + @ApiOperation("登出") + @GetMapping("/logout") + public ResultData logout() { + logger.debug("[" + getIpAddr() + "] HomeController::logout"); + ResultData data = new ResultData(); + SecurityUtils.getSubject().logout(); + return data; + } + + @ApiOperation("获取后端版本号") + @GetMapping("/version") + public ResultData version() { + return new ResultData(version); + } +} \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatAuthController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatAuthController.java new file mode 100644 index 0000000..e3da84e --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatAuthController.java @@ -0,0 +1,106 @@ +package com.iformall.controller; + +import com.iformall.domain.po.WxAuthorizerInfo; +import com.iformall.enums.EnumWxAuthorizationStatus; +import com.iformall.service.WxAuthorizerInfoService; +import com.iformall.service.wechat.FmOpenService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.bean.result.WxOpenAuthorizerInfoResult; +import me.chanjar.weixin.open.bean.result.WxOpenQueryAuthResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.Date; + +/** + * Stormeye Wu + */ +@Controller +@RequestMapping("/wt_auth") +@Api(description = "微信第三方开放平台授权相关接口") +public class WechatAuthController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + @Autowired + private FmOpenService openService; + + @Autowired + private WxAuthorizerInfoService authorizerInfoService; + + @ApiOperation(value = "获取授权跳转页", notes = "") + @GetMapping("/goto_auth_url_show") + @ResponseBody + public String gotoPreAuthUrlShow() { + return "" + + "" + + "go" + + "" + + ""; + } + + @ApiOperation(value = "授权跳转页", notes = "") + @GetMapping("/goto_auth_url") + public void gotoPreAuthUrl(HttpServletRequest request, HttpServletResponse response) { + String host = request.getHeader("host"); + String url = "https://" + host + "/O/wt_auth/jump"; + try { + url = openService.getWxOpenComponentService().getPreAuthUrl(url); + response.sendRedirect(url); + } catch (WxErrorException | IOException e) { + logger.error("gotoPreAuthUrl", e); + throw new RuntimeException(e); + } + } + + @ApiOperation(value = "授权", notes = "") + @GetMapping("/jump") + @ResponseBody + public void jump(@RequestParam("auth_code") String authorizationCode) { + try { + WxOpenQueryAuthResult queryAuthResult = openService.getWxOpenComponentService().getQueryAuth(authorizationCode); + logger.info("getQueryAuth", queryAuthResult); + WxOpenAuthorizerInfoResult openAuthorizerInfoResult = openService.getWxOpenComponentService().getAuthorizerInfo( + queryAuthResult.getAuthorizationInfo().getAuthorizerAppid()); + logger.info(openAuthorizerInfoResult.toString()); + // save auth info + authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo(){ + { + setAuthorizerAppid(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAppid()); + setAlias(openAuthorizerInfoResult.getAuthorizerInfo().getAlias()); + setHeadImg(openAuthorizerInfoResult.getAuthorizerInfo().getHeadImg()); + setQrcodeUrl(openAuthorizerInfoResult.getAuthorizerInfo().getQrcodeUrl()); + setRefreshToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerRefreshToken()); + setAccessToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAccessToken()); + setAccessTokenExpire(new Date(Long.valueOf(System.currentTimeMillis() + openAuthorizerInfoResult.getAuthorizationInfo().getExpiresIn()*1000))); + setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode()); + setAuthTime(new Date()); + } + }); + } catch (WxErrorException e) { + logger.error("gotoPreAuthUrl", e); + throw new RuntimeException(e); + } + } + + @ApiOperation(value = "手机跳转链接url", notes = "") + @GetMapping("/getMobilePreAuthUrl") + @ResponseBody + public String getMobilePreAuthUrl(HttpServletRequest request, HttpServletResponse response) { + String host = request.getHeader("host"); + String url = "https://" + host + "/O/wt_auth/jump"; + try { + url = openService.getWxOpenComponentService().getMobilePreAuthUrl(url); + return url; + } catch (WxErrorException e) { + logger.error("getMobilePreAuthUrl", e); + throw new RuntimeException(e); + } + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java new file mode 100644 index 0000000..484e14c --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatCalllbackController.java @@ -0,0 +1,415 @@ +package com.iformall.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.domain.po.*; +import com.iformall.enums.*; +import com.iformall.service.*; +import com.iformall.service.wechat.FmOpenService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.kefu.WxMpKefuMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.open.bean.WxOpenCreateResult; +import me.chanjar.weixin.open.bean.WxOpenGetResult; +import me.chanjar.weixin.open.bean.message.WxOpenXmlMessage; +import me.chanjar.weixin.open.bean.result.*; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.charset.Charset; +import java.util.Date; +import java.util.Map; + +@Controller +@RequestMapping("/wxOpen") +@Api(description = "微信第三方开放平台回调相关接口") +public class WechatCalllbackController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + protected FmOpenService openService; + + @Autowired + private WxComponentVerifyTicketService componentVerifyTicketService; + + @Autowired + private WxAuthorizerInfoService authorizerInfoService; + + @PostMapping(value = "/notify") + @ApiOperation("接收ticket回调") + @ResponseBody + public String receiveTicket(HttpServletRequest request) throws IOException { + logger.info("[" + getIpAddr() + "]接收微信回调 /wxOpen/notify"); + + String timestamp = request.getParameter("timestamp"); + String nonce = request.getParameter("nonce"); + String signature = request.getParameter("signature"); + String encType = request.getParameter("encrypt_type"); + String msgSignature = request.getParameter("msg_signature"); + + if (!StringUtils.equalsIgnoreCase("aes", encType) + || !openService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) { + throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); + } + + String resultxml = getRequestXML(request); + + logger.info("\n接收微信回调:[signature=[{}], encType=[{}], msgSignature=[{}]," + + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", + signature, encType, msgSignature, timestamp, nonce, resultxml); + + // aes加密的消息, 解密 + WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(resultxml, + openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature); + this.logger.info("接收微信回调,消息解密后内容为:{} ", inMessage.toString()); + + // 处理 + handleTicket(inMessage); + return "success"; + } + + /** + * 处理ticket消息 + * @param inMessage + * @return + */ + private void handleTicket(WxOpenXmlMessage inMessage) { + try { + String out = openService.getWxOpenComponentService().route(inMessage); + this.logger.info("组装回复信息:{}", out); + } catch (WxErrorException e) { + this.logger.error("notify", e); + } + if (inMessage.getInfoType().equalsIgnoreCase(EnumWxAuthorizationInfoType.COMPONENT_VERIFY_TICKET.getMessage())) { + // 保存component_verify_ticket + componentVerifyTicketService.saveOrUpdate(new WxComponentVerifyTicket() { + { + setComponentVerifyTicket(inMessage.getComponentVerifyTicket()); + setCreateTime(new Date(Long.valueOf(inMessage.getCreateTime() * 1000))); + setComponentAppid(inMessage.getAppId()); + setDeadline(new Date(Long.valueOf(System.currentTimeMillis() + (60 * 60 * 1000)))); + } + }); + } else if (inMessage.getInfoType().equalsIgnoreCase(EnumWxAuthorizationInfoType.AUTHORIZED.getMessage()) || + inMessage.getInfoType().equalsIgnoreCase(EnumWxAuthorizationInfoType.UPDATEAUTHORIZED.getMessage())) { + // 审核通过 + handleWeappAuditedMessage(inMessage); + } else if (inMessage.getInfoType().equals(EnumWxAuthorizationInfoType.UNAUTHORIZED.getMessage())) { + // 授权取消 + authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() { + { + setAuthorizerAppid(inMessage.getAuthorizerAppid()); + setAuthorizationStatus(EnumWxAuthorizationStatus.UNAUTHORIZED.getCode()); + setAuthTime(new Date()); + } + }); + } + } + + /** + * 处理小程序审核消息 + * @param inMessage + * @return + */ + private boolean handleWeappAuditedMessage(WxOpenXmlMessage inMessage) { + // 审核通过 + try { + WxOpenQueryAuthResult queryAuthResult = openService.getWxOpenComponentService().getQueryAuth(inMessage.getAuthorizationCode()); + logger.info("getQueryAuth", queryAuthResult); + + WxOpenAuthorizerInfoResult openAuthorizerInfoResult = openService.getWxOpenComponentService().getAuthorizerInfo( + queryAuthResult.getAuthorizationInfo().getAuthorizerAppid()); + logger.info(openAuthorizerInfoResult.toString()); + // save auth info + authorizerInfoService.saveOrUpdate(new WxAuthorizerInfo() { + { + setAuthorizerAppid(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAppid()); + setAlias(openAuthorizerInfoResult.getAuthorizerInfo().getAlias()); + setHeadImg(openAuthorizerInfoResult.getAuthorizerInfo().getHeadImg()); + setQrcodeUrl(openAuthorizerInfoResult.getAuthorizerInfo().getQrcodeUrl()); + setRefreshToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerRefreshToken()); + setAccessToken(openAuthorizerInfoResult.getAuthorizationInfo().getAuthorizerAccessToken()); + setAccessTokenExpire(new Date(Long.valueOf(System.currentTimeMillis() + openAuthorizerInfoResult.getAuthorizationInfo().getExpiresIn()*1000))); + setAuthorizationStatus(EnumWxAuthorizationStatus.AUTHORIZED.getCode()); + setAuthTime(new Date()); + } + }); + return true; + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + return false; + } + + @RequestMapping(value = "/{appId}/callback") + @ApiOperation("消息回调") + public void callback(@PathVariable("appId") String appId, HttpServletRequest request, HttpServletResponse response) throws IOException { + logger.info("[" + getIpAddr() + "]接收微信APP回调 /{appId}/callback"); + String timestamp = request.getParameter("timestamp"); + String nonce = request.getParameter("nonce"); + String signature = request.getParameter("signature"); + String encType = request.getParameter("encrypt_type"); + String openid = request.getParameter("openid"); + String msgSignature = request.getParameter("msg_signature"); + + // 第三方平台一定接收的是加密的消息 + if (!StringUtils.equalsIgnoreCase("aes", encType) + || !openService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) { + throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); + } + + String resultxml = getRequestXML(request); + + logger.info("接收微信APP回调:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}]," + + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", + appId, openid, signature, encType, msgSignature, timestamp, nonce, resultxml); + + + String out = ""; + // aes加密的消息, 解密 + WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(resultxml, + openService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature); + logger.info("接收微信APP回调,消息解密后内容为:\n{}", inMessage.toString()); + + // 全网发布测试用例 + if (StringUtils.equalsAnyIgnoreCase(appId, "wx570bc396a51b8ff8", "wxd101a85aa106f53e")) { + handleWechatTest(appId, response, inMessage); + PrintWriter printWriter = response.getWriter(); + wechatWriteSuccess(printWriter); + return; + } + + // 实际 消息 处理 + //handleCallbackMessage(appId, response, inMessage); + WxMpXmlOutMessage outMessage = openService.getWxOpenMessageRouter().route(inMessage, appId); + if(outMessage == null) { + PrintWriter printWriter = response.getWriter(); + wechatWriteSuccess(printWriter); + } + PrintWriter printWriter = response.getWriter(); + wechatWriteSuccess(printWriter); + } + + private void wechatWriteSuccess(PrintWriter printWriter) { + printWriter.print("success"); + printWriter.flush(); + printWriter.close(); + } + + /** + * 测试账号特殊处理 + * @param appId + * @param response + * @param inMessage + * @throws IOException + */ + private void handleWechatTest(@PathVariable("appId") String appId, HttpServletResponse response, WxMpXmlMessage inMessage) throws IOException { + String out; + try { + if (StringUtils.equals(inMessage.getMsgType(), "text")) { + if (StringUtils.equals(inMessage.getContent(), "TESTCOMPONENT_MSG_TYPE_TEXT")) { + out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml( + WxMpXmlOutMessage.TEXT().content("TESTCOMPONENT_MSG_TYPE_TEXT_callback") + .fromUser(inMessage.getToUser()) + .toUser(inMessage.getFromUser()) + .build(), + openService.getWxOpenConfigStorage() + ); + } else if (StringUtils.startsWith(inMessage.getContent(), "QUERY_AUTH_CODE:")) { + String msg = inMessage.getContent().replace("QUERY_AUTH_CODE:", "") + "_from_api"; + WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(msg).toUser(inMessage.getFromUser()).build(); + openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage); + } + } else if (StringUtils.equals(inMessage.getMsgType(), "event")) { + WxMpKefuMessage kefuMessage = WxMpKefuMessage.TEXT().content(inMessage.getEvent() + "from_callback").toUser(inMessage.getFromUser()).build(); + openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage); + } + } catch (WxErrorException e) { + logger.error("callback", e); + } + } + + private String getRequestXML(HttpServletRequest request) throws IOException { + 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 resultxml = new String(outSteam.toByteArray(), Charset.forName("UTF-8")); + logger.info(resultxml); + + outSteam.close(); + inStream.close(); + return resultxml; + } + + private void getThreadCount( int i) { + ThreadGroup group = Thread.currentThread().getThreadGroup(); + ThreadGroup topGroup = group; + // 遍历线程组树,获取根线程组 + while (group != null) { + topGroup = group; + group = group.getParent(); + } + // 激活的线程数加倍 + int activeCount = topGroup.activeCount(); + // copy into a list that is the exact size + logger.info("Thread list size == " + i + " : " + activeCount); + + } + + + @GetMapping(value = "/createOpenPlatform") + @ApiOperation("创建微信开放平台") + public ResultData createOpenPlatform(@RequestParam(value = "appId") String appId) { + Gson gson = new GsonBuilder().create(); + try { + WxOpenCreateResult ret = openService.getWxOpenComponentService().createOpenAccount(appId); + logger.info(ret.toString()); + if (ret.isSuccess()) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if (authorizerInfo != null) { + authorizerInfo.setId(authorizerInfo.getId()); + authorizerInfo.setOpenAppid(ret.getOpenAppid()); + authorizerInfoService.updateOpenAppid(authorizerInfo); + } + } + return new ResultData(ret.toString()); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @GetMapping(value = "/bindOpenPlatform") + @ApiOperation("绑定微信开放平台") + public ResultData bindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) { + Gson gson = new GsonBuilder().create(); + try { + Boolean ret = openService.getWxOpenComponentService().bindOpenAccount(appId, openAppId); + if (ret) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if (authorizerInfo != null) { + authorizerInfo.setId(authorizerInfo.getId()); + authorizerInfo.setOpenAppid(openAppId); + authorizerInfoService.updateOpenAppid(authorizerInfo); + } + return new ResultData(); + } + return new ResultData(Result.ERROR, ret.toString()); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @GetMapping(value = "/unbindOpenPlatform") + @ApiOperation("解绑微信开放平台") + public ResultData unbindOpenPlatform(@RequestParam(value = "appId") String appId, @RequestParam(value = "openAppId") String openAppId) { + Gson gson = new GsonBuilder().create(); + try { + Boolean ret = openService.getWxOpenComponentService().unbindOpenAccount(appId, openAppId); + if (ret) { + WxAuthorizerInfo authorizerInfo = new WxAuthorizerInfo(); + authorizerInfo.setAuthorizerAppid(appId); + authorizerInfoService.removeOpenAppid(authorizerInfo); + return new ResultData(); + } + return new ResultData(Result.ERROR, ret.toString()); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @GetMapping(value = "/getOpenPlatform") + @ApiOperation("获取微信开放平台appId") + public ResultData getOpenPlatform(@RequestParam(value = "appId") String appId) { + Gson gson = new GsonBuilder().create(); + try { + WxOpenGetResult ret = openService.getWxOpenComponentService().getOpenAccount(appId); + logger.info(ret.toString()); + if (ret.isSuccess()) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if (authorizerInfo != null) { + if(StringUtils.isBlank(authorizerInfo.getOpenAppid()) && StringUtils.isNotBlank(ret.getOpenAppid())) { + authorizerInfo.setId(authorizerInfo.getId()); + authorizerInfo.setOpenAppid(ret.getOpenAppid()); + authorizerInfoService.updateOpenAppid(authorizerInfo); + } + } + return new ResultData(ret.getOpenAppid()); + } + return new ResultData(Result.ERROR, ret.toString()); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @GetMapping(value = "/clearQuota") + @ApiOperation("代公众号清零quota,每个公众号每个月有10次清零机会,包括在微信公众平台上的清零以及调用API进行清零") + public ResultData clearQuota(@RequestParam(value = "appId") String appId) { + try { + openService.getWxOpenComponentService().getWxMpServiceByAppid(appId).clearQuota(appId); + return new ResultData(); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @GetMapping(value = "/getAuthorizerList") + @ApiOperation("拉取当前所有已授权的帐号基本信息") + public ResultData getAuthorizerList() { + try { + WxOpenAuthorizerListResult authorizerListResult = openService.getWxOpenComponentService().getAuthorizerList(0, 100); + logger.info("getAuthorizerList: " + authorizerListResult); + if(authorizerListResult.getTotalCount() > 0) { + for (Map data : authorizerListResult.getList()) { + String appId = data.get("authorizer_appid"); + String refreshToken = data.get("refresh_token"); + Long authTime = Long.valueOf(data.get("auth_time")); + Date authDate = new Date(authTime*1000); + + if(StringUtils.isBlank(refreshToken)) { + continue; + } + + WxAuthorizerInfo authorizerInfo = new WxAuthorizerInfo(); + authorizerInfo.setAuthorizerAppid(appId); + authorizerInfo.setRefreshToken(refreshToken); + authorizerInfo.setAuthTime(authDate); + authorizerInfoService.updateAuthAppidInfo(authorizerInfo); + + openService.getWxOpenComponentService().getWxOpenConfigStorage().setAuthorizerRefreshToken(appId, refreshToken); + } + } + return new ResultData(authorizerListResult.toString()); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatMediaController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatMediaController.java new file mode 100644 index 0000000..db61792 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatMediaController.java @@ -0,0 +1,133 @@ +package com.iformall.controller; + +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.service.WxAuthorizerInfoService; +import com.iformall.service.wechat.FmOpenService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.material.WxMediaImgUploadResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.BufferedInputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; + +/** + * Stormeye Wu + */ +@Controller +@RequestMapping("/material") +@Api(description = "微信第三方开放平台素材文件") +public class WechatMediaController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + @Autowired + private String fmUploadDir; + @Autowired + private FmOpenService openService; + + @Autowired + private WxAuthorizerInfoService authorizerInfoService; + + @ApiOperation(value = "获取永久素材", notes = "") + @GetMapping("/getMedia") + @ApiImplicitParams({ + @ApiImplicitParam(name = "appId", value = "appId", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "mediaId", value = "mediaId", dataType = "String", paramType = "query", required = true)}) + public void getMediaInfo(String appId, String mediaId, HttpServletRequest req, HttpServletResponse response) { + InputStream inputStream = null; + String filename = mediaId; + try { + WxMpService mpService = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId); + inputStream = mpService.getMaterialService().materialImageOrVoiceDownload(mediaId); + } catch (WxErrorException e) { + logger.error("获取永久素材失败", e); + throw new RuntimeException(e); + } + + try { + response.reset(); + response.setContentType("application/octet-stream"); + String agent = req.getHeader("user-agent"); + if (agent.contains("Firefox")) { + response.setHeader("Content-disposition", + "attachment; filename=" + + new String(filename.getBytes("GB2312"), "ISO-8859-1")); + } else { + response.setHeader("Content-disposition", + "attachment; filename=" + + java.net.URLEncoder.encode(filename, "UTF-8")); + } + // 循环取出流中的数据 + byte[] b = new byte[1024]; + int len; + while ((len = inputStream.read(b)) > 0) + response.getOutputStream().write(b, 0, len); + inputStream.close(); + } catch (Exception e) { + logger.error(e.getMessage()); + } + } + + /** + * 图片上传 + * + * @param multiReq + * @return + * @throws Exception + */ + @PostMapping(value = "/imgUpload/{appId}", consumes = "multipart/*", headers = "content-type=multipart/form-data") + @ApiOperation("上传图片") + public ResultData imgUpload( + @PathVariable("appId") String appId, + @RequestParam("file") MultipartFile multiReq) throws Exception { + logger.info("[" + getIpAddr() + "] WechatMediaController::imgUpload"); + + String fileName = multiReq.getOriginalFilename(); + System.out.println(fileName); + + // 本地保存 + FileOutputStream fos = null; + String localImgFileName = fmUploadDir + fileName; + BufferedInputStream fs = null; + File localFile = new File(localImgFileName); + fos = new FileOutputStream(localFile); + fs = (BufferedInputStream) multiReq.getInputStream(); + byte[] buffer = new byte[1024]; + int len = 0; + while ((len = fs.read(buffer)) != -1) { + fos.write(buffer, 0, len); + } + fos.close(); + fs.close(); + + // 上传 微信 + try { + WxMpService mpService = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId); + WxMediaImgUploadResult openResult = mpService.getMaterialService().mediaImgUpload(localFile); + if(openResult != null) { + return new ResultData(openResult.getUrl()); + } + } catch (WxErrorException e) { + logger.error("获取永久素材失败", e); + throw new RuntimeException(e); + } + + // 删除本地缓存 + localFile.delete(); + + return new ResultData(); + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappCodeController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappCodeController.java new file mode 100644 index 0000000..8d97ccc --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappCodeController.java @@ -0,0 +1,703 @@ +package com.iformall.controller; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.domain.dto.WxWeappCodeAuditDto; +import com.iformall.domain.po.*; +import com.iformall.domain.vo.WxWeappCodeStatusVo; +import com.iformall.enums.*; +import com.iformall.service.*; +import com.iformall.service.wechat.FmOpenService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.api.WxOpenMaService; +import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo; +import me.chanjar.weixin.open.bean.message.WxOpenMaSubmitAuditMessage; +import me.chanjar.weixin.open.bean.result.*; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.ServletOutputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.URLEncoder; +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * Stormeye Wu + */ +@RestController +@RequestMapping("/weappCode") +@Api(description = "微信第三方开发平台-小程序-代码管理") +public class WechatWeappCodeController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + @Autowired + private FmOpenService openService; + + @Autowired + private WxWeappCodeStatusService weappCodeStatusService; + + @Autowired + private WxWeappAuditStatusService weappAuditStatusService; + + @Autowired + private WxWeappReleaseStatusService weappReleaseStatusService; + + @Autowired + private WxAppinfoService appinfoService; + + @Autowired + private WxAuthorizerInfoService authorizerInfoService; + + @Autowired + private WxWeappExtSetService weappExtSetService; + + + @ApiOperation(value = "为授权的小程序帐号上传小程序代码", notes = "extInfo参考https://mp.weixin.qq.com/debug/wxadoc/dev/framework/config.html") + @PostMapping("/codeCommit") + public ResultData codeCommit(Long templateId, String userVersion, String userDesc, String extInfoStr) { + Gson gson = new GsonBuilder().create(); + WxMaOpenCommitExtInfo extInfo = gson.fromJson(extInfoStr, new TypeToken() {}.getType()); + String appId = extInfo.getExtAppid(); + + // 检查appId是否已授权 + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + + WxWeappCodeStatus codeStatus = weappCodeStatusService.getByAppId(appId); + + WxAppinfo appinfo = appinfoService.getByAppId(appId); + + int iAppType = 0; + String appTypeStr = userVersion.substring(0, 1); + if(appTypeStr.equalsIgnoreCase("C")) + iAppType = EnumAppType.C.getCode(); + else if(appTypeStr.equalsIgnoreCase("B")) + iAppType = EnumAppType.B.getCode(); + + try { + // code提交 + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + logger.info(extInfo.toString()); + WxOpenResult openRet = openMaService.codeCommit(templateId, userVersion, userDesc, extInfo); + logger.info(openRet.toString()); + boolean codeCommitStatus = false; + if (openRet.isSuccess()) { + codeCommitStatus = true; + } + if (codeStatus == null) { + codeStatus = new WxWeappCodeStatus(); + codeStatus.setAppId(appId); + if (appinfo != null) { + codeStatus.setTenantId(appinfo.getTenantId()); + codeStatus.setType(appinfo.getType()); + } + codeStatus.setUserVersion(userVersion); + codeStatus.setVersionDesc(userDesc); + if(codeCommitStatus) { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.SUCCESS.getCode()); + } else { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.FAIL.getCode()); + codeStatus.setCodeErrCode(gson.toJson(openRet)); + } + codeStatus.setCodeTime(new Date()); + weappCodeStatusService.saveStatus(codeStatus); + } else { + codeStatus.setUserVersion(userVersion); + codeStatus.setVersionDesc(userDesc); + if(codeCommitStatus) { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.SUCCESS.getCode()); + } else { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.FAIL.getCode()); + codeStatus.setCodeErrCode(gson.toJson(openRet)); + } + codeStatus.setCodeTime(new Date()); + weappCodeStatusService.updateStatus(codeStatus); + } + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + if (codeStatus == null) { + codeStatus = new WxWeappCodeStatus(); + codeStatus.setAppId(appId); + if (appinfo != null) { + codeStatus.setTenantId(appinfo.getTenantId()); + codeStatus.setType(appinfo.getType()); + } + codeStatus.setUserVersion(userVersion); + codeStatus.setVersionDesc(userDesc); + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.FAIL.getCode()); + codeStatus.setCodeErrCode(e.getMessage()); + codeStatus.setCodeTime(new Date()); + weappCodeStatusService.saveStatus(codeStatus); + } else { + codeStatus.setUserVersion(userVersion); + codeStatus.setVersionDesc(userDesc); + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.FAIL.getCode()); + codeStatus.setCodeErrCode(e.getMessage()); + codeStatus.setCodeTime(new Date()); + weappCodeStatusService.updateStatus(codeStatus); + } + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation("获取体验小程序的体验二维码") + @GetMapping("/getQrcode") + public void getQrcode(@RequestParam(value = "appId") String appId, @RequestParam(value = "pagePath") String pagePath, + @RequestParam(value = "params", required = false) Map params, + HttpServletResponse response, HttpServletRequest req) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + File file = openMaService.getTestQrcode(pagePath, params); + ServletOutputStream out = response.getOutputStream(); + + response.reset(); + response.setContentType("image/jpeg"); + String agent = req.getHeader("user-agent"); + String filename = "QRCode.jpg"; + if (agent.contains("Firefox")) { + response.setHeader("Content-disposition", + "attachment; filename=" + new String(filename.getBytes("GB2312"),"ISO-8859-1")); + } else { + response.setHeader("Content-disposition", + "attachment; filename=" + URLEncoder.encode(filename,"UTF-8")); + } + // 循环取出流中的数据 + byte[] b = new byte[1024]; + int len; + InputStream inStream = new FileInputStream(file); + while ((len = inStream.read(b)) > 0) + response.getOutputStream().write(b, 0, len); + inStream.close(); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } catch (IOException e) { + logger.error(e.getMessage()); + } + } + + @ApiOperation("获取授权小程序帐号已设置的类目") + @GetMapping("/getCategory") + public ResultData getCategory(String appId) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenMaCategoryListResult openRet = openMaService.getCategoryList(); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation("获取小程序的第三方提交代码的页面配置") + @GetMapping("/getPage") + public ResultData getPage(String appId) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenMaPageListResult openRet = openMaService.getPageList(); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation("将第三方提交的代码包提交审核 -- 即将废弃") + @GetMapping("/submitAudit") + @ApiImplicitParams({ + @ApiImplicitParam(name = "appId", value = "appId", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "version", value = "version", dataType = "String", paramType = "query")}) + public ResultData submitAudit(String appId, String version) { + Gson gson = new GsonBuilder().create(); + WxWeappExtSet extSetQ = new WxWeappExtSet(); + extSetQ.setAppId(appId); + WxWeappExtSet extSet = weappExtSetService.getByObj(extSetQ); + if(StringUtils.isBlank(extSet.getReleaseJson())) { + logger.error("Release JSON is null"); + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + + WxWeappCodeStatusVo codeQ = new WxWeappCodeStatusVo(); + codeQ.setAppId(appId); + if(StringUtils.isNotBlank(version)) { + codeQ.setUserVersion(version); + } + List codeStatusList = weappCodeStatusService.getList(codeQ); + if(codeStatusList.size() == 1) { + WxWeappCodeStatusVo codeStatus = codeStatusList.get(0); + WxOpenMaSubmitAuditMessage subMessage = gson.fromJson(extSet.getReleaseJson(), new TypeToken() {}.getType()); + if(codeStatus != null && codeStatus.getCodeStatus().equals(EnumWeappCodeCommitStatus.SUCCESS.getCode())) { + WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId); + boolean submitStatus = false; + String codeErrCode = ""; + Long auditId = null; + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenMaSubmitAuditResult openRet = openMaService.submitAudit(subMessage); + logger.info(openRet.toString()); + if(openRet.isSuccess()) { + submitStatus = true; + codeErrCode = gson.toJson(openRet); + auditId = openRet.getAuditId(); + } else { + submitStatus = false; + codeErrCode = gson.toJson(openRet); + } + } catch (WxErrorException e) { + logger.error(e.getMessage()); + submitStatus = false; + codeErrCode = e.getMessage(); + } + + if (auditStatus == null) { + auditStatus = new WxWeappAuditStatus(); + auditStatus.setId(codeStatus.getId()); + auditStatus.setTenantId(codeStatus.getTenantId()); + auditStatus.setAppId(codeStatus.getAppId()); + auditStatus.setType(codeStatus.getType()); + auditStatus.setUserVersion(codeStatus.getUserVersion()); + auditStatus.setVersionDesc(codeStatus.getVersionDesc()); + if(submitStatus) { + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + } else { + auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); + } + auditStatus.setAuditErrCode(codeErrCode); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.saveStatus(auditStatus); + } else { + if(!submitStatus) { + if(!auditStatus.getUserVersion().equals(codeStatus.getUserVersion()) + && auditStatus.getAuditStatus().equals(EnumWeappAuditStatus.AUDITING.getCode())) { + // 提交审核失败不替换当前审核中的数据 + return new ResultData(ErrorCode.WEAPP_HAD_AUDITING); + } + codeStatus.setCodeStatus(EnumWeappAuditStatus.FAIL.getCode()); + codeStatus.setCodeErrCode(codeErrCode); + } else { + codeStatus.setCodeStatus(EnumWeappAuditStatus.AUDITING.getCode()); + } + auditStatus.setUserVersion(codeStatus.getUserVersion()); + auditStatus.setVersionDesc(codeStatus.getVersionDesc()); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.updateStatus(auditStatus); + } + if(submitStatus) { + return new ResultData(codeErrCode); + } else { + return new ResultData(ErrorCode.WEAPP_AUDIT_ERR); + } + } else { + logger.error(ErrorCode.WEAPP_CODE_COMMIT_ERR.getMessage()); + return new ResultData(ErrorCode.WEAPP_CODE_COMMIT_ERR); + } + } + return new ResultData(ErrorCode.WEAPP_CODE_COMMIT_ERR); + } + + @ApiOperation("查询服务商的当月提审限额(quota)和加急次数") + @GetMapping("/queryQuota") + @ApiImplicitParams({ + @ApiImplicitParam(name = "appId", value = "appId", dataType = "String", paramType = "query", required = true)}) + public ResultData queryQuota(String appId) { + logger.debug("[" + getIpAddr() + "] WechatWeappCodeController::queryQuota"); + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenMaQueryQuotaResult openRet = openMaService.queryQuota(); + logger.info(openRet.toString()); + return new ResultData(openRet.toString()); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(e.getMessage()); + } + } + + @ApiOperation("将第三方提交的代码包提交审核") + @PostMapping("/submitAuditWithFeedBack") + public ResultData submitAudit(@RequestBody WxWeappCodeAuditDto codeAuditDto) { + Gson gson = new GsonBuilder().create(); + WxWeappExtSet extSetQ = new WxWeappExtSet(); + extSetQ.setAppId(codeAuditDto.getAppId()); + WxWeappExtSet extSet = weappExtSetService.getByObj(extSetQ); + if(StringUtils.isBlank(extSet.getReleaseJson())) { + logger.error("Release JSON is null"); + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + + WxWeappCodeStatusVo codeQ = new WxWeappCodeStatusVo(); + codeQ.setAppId(codeAuditDto.getAppId()); + if(StringUtils.isNotBlank(codeAuditDto.getVersion())) { + codeQ.setUserVersion(codeAuditDto.getVersion()); + } + List codeStatusList = weappCodeStatusService.getList(codeQ); + if(codeStatusList.size() == 1) { + WxWeappCodeStatusVo codeStatus = codeStatusList.get(0); + WxOpenMaSubmitAuditMessage subMessage = gson.fromJson(extSet.getReleaseJson(), new TypeToken() {}.getType()); + if(StringUtils.isNotBlank(codeAuditDto.getFeedbackInfo())) { + subMessage.setFeedbackInfo(codeAuditDto.getFeedbackInfo()); + } + if(StringUtils.isNotBlank(codeAuditDto.getFeedbackStuff())) { + subMessage.setFeedbackStuff(codeAuditDto.getFeedbackStuff()); + } + if(codeStatus != null && codeStatus.getCodeStatus().equals(EnumWeappCodeCommitStatus.SUCCESS.getCode())) { + WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(codeAuditDto.getAppId()); + boolean submitStatus = false; + String codeErrCode = ""; + Long auditId = null; + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(codeAuditDto.getAppId()); + WxOpenMaSubmitAuditResult openRet = openMaService.submitAudit(subMessage); + logger.info(openRet.toString()); + if(openRet.isSuccess()) { + submitStatus = true; + codeErrCode = gson.toJson(openRet); + auditId = openRet.getAuditId(); + } else { + submitStatus = false; + codeErrCode = gson.toJson(openRet); + } + } catch (WxErrorException e) { + logger.error(e.getMessage()); + submitStatus = false; + codeErrCode = e.getMessage(); + } + + if (auditStatus == null) { + auditStatus = new WxWeappAuditStatus(); + auditStatus.setId(codeStatus.getId()); + auditStatus.setTenantId(codeStatus.getTenantId()); + auditStatus.setAppId(codeStatus.getAppId()); + auditStatus.setType(codeStatus.getType()); + auditStatus.setUserVersion(codeStatus.getUserVersion()); + auditStatus.setVersionDesc(codeStatus.getVersionDesc()); + auditStatus.setAuditid(auditId); + if(submitStatus) { + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + } else { + auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); + } + auditStatus.setAuditErrCode(codeErrCode); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.saveStatus(auditStatus); + } else { + if(!submitStatus) { + if(!auditStatus.getUserVersion().equals(codeStatus.getUserVersion()) + && auditStatus.getAuditStatus().equals(EnumWeappAuditStatus.AUDITING.getCode())) { + // 提交审核失败不替换当前审核中的数据 + return new ResultData(ErrorCode.WEAPP_HAD_AUDITING); + } + codeStatus.setCodeStatus(EnumWeappAuditStatus.FAIL.getCode()); + codeStatus.setCodeErrCode(codeErrCode); + } else { + codeStatus.setCodeStatus(EnumWeappAuditStatus.AUDITING.getCode()); + } + auditStatus.setUserVersion(codeStatus.getUserVersion()); + auditStatus.setVersionDesc(codeStatus.getVersionDesc()); + auditStatus.setAuditid(auditId); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.updateStatus(auditStatus); + } + if(submitStatus) { + return new ResultData(codeErrCode); + } else { + return new ResultData(ErrorCode.WEAPP_AUDIT_ERR); + } + } else { + logger.error(ErrorCode.WEAPP_CODE_COMMIT_ERR.getMessage()); + return new ResultData(ErrorCode.WEAPP_CODE_COMMIT_ERR); + } + } + return new ResultData(ErrorCode.WEAPP_CODE_COMMIT_ERR); + } + + @ApiOperation("加速某个指定版本的审核状态") + @GetMapping("/speedAudit") + @ApiImplicitParams({ + @ApiImplicitParam(name = "appId", value = "appId", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "auditid", value = "auditid", dataType = "Long", paramType = "query", required = true)}) + public ResultData speedAudit(String appId, Long auditid) { + logger.debug("[" + getIpAddr() + "] WechatWeappCodeController::speedAudit"); + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + Boolean ret = openMaService.speedAudit(Long.valueOf(auditid)); + return new ResultData(ret.toString()); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(e.getMessage()); + } + } + + @ApiOperation("查询某个指定版本的审核状态") + @PostMapping("/getAuditstatus") + public ResultData getAuditstatus(String appId, String auditidStr) { + Gson gson = new GsonBuilder().create(); + Long auditId = Long.valueOf(auditidStr); + WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId); + if(auditStatus != null && auditStatus.getAuditid().equals(auditId)) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenMaQueryAuditResult openRet = openMaService.getAuditStatus(auditId); + logger.info(openRet.toString()); + if (openRet.isSuccess()) { + auditStatus.setAuditid(openRet.getAuditId()); + // 审核状态,其中0为审核成功,1为审核失败,2为审核中,3已撤回 + switch (openRet.getStatus().intValue()) { + case 0: + auditStatus.setAuditStatus(EnumWeappAuditStatus.SUCCESS.getCode()); + break; + case 1: + auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); + break; + case 2: + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + break; + case 3: + auditStatus.setAuditStatus(EnumWeappAuditStatus.UNDO.getCode()); + break; + default: + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + break; + } + auditStatus.setAuditErrCode(gson.toJson(openRet)); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.updateStatus(auditStatus); + } + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + return new ResultData(Result.ERROR, "auditid不对应"); + } + + @ApiOperation("查询最新一次提交的审核状态") + @GetMapping("/getLatestAuditstatus") + public ResultData get_latest_auditstatus(String appId) { + Gson gson = new GsonBuilder().create(); + WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId); + if(auditStatus != null + && auditStatus.getAuditStatus().equals(EnumWeappAuditStatus.AUDITING.getCode())) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenMaQueryAuditResult openRet = openMaService.getLatestAuditStatus(); + logger.info(openRet.toString()); + if (openRet.isSuccess()) { + auditStatus.setAuditid(openRet.getAuditId()); + // 审核状态,其中0为审核成功,1为审核失败,2为审核中,3已撤回 + switch (openRet.getStatus().intValue()) { + case 0: + auditStatus.setAuditStatus(EnumWeappAuditStatus.SUCCESS.getCode()); + break; + case 1: + auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); + break; + case 2: + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + break; + case 3: + auditStatus.setAuditStatus(EnumWeappAuditStatus.UNDO.getCode()); + break; + default: + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + break; + } + auditStatus.setAuditErrCode(gson.toJson(openRet)); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.updateStatus(auditStatus); + } + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } else { + return new ResultData(Result.ERROR, "审核状态不是审核中"); + } + } + + @ApiOperation("发布已通过审核的小程序") + @GetMapping("/releaseAudited") + public ResultData releaesAudited(String appId) { + if(StringUtils.isBlank(appId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + Gson gson = new GsonBuilder().create(); + WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId); + if(auditStatus.getAuditStatus().equals(EnumWeappAuditStatus.SUCCESS.getCode())) { + boolean isUpdate = false; + WxWeappReleaseStatus releaseStatus = weappReleaseStatusService.getByAppId(appId); + if(releaseStatus != null) { + // 版本已发布成功,跳过 + if(releaseStatus.getUserVersion().equals(auditStatus.getUserVersion()) + && releaseStatus.getReleaseStatus().equals(EnumWeappReleaseStatus.SUCCESS.getCode())) { + return new ResultData(ErrorCode.WEAPP_APP_RELEASEED); + } + releaseStatus.setUserVersion(auditStatus.getUserVersion()); + releaseStatus.setVersionDesc(auditStatus.getVersionDesc()); + isUpdate = true; + } else { + releaseStatus = new WxWeappReleaseStatus(); + releaseStatus.setId(auditStatus.getId()); + releaseStatus.setTenantId(auditStatus.getTenantId()); + releaseStatus.setAppId(auditStatus.getAppId()); + releaseStatus.setType(auditStatus.getType()); + releaseStatus.setUserVersion(auditStatus.getUserVersion()); + releaseStatus.setVersionDesc(auditStatus.getVersionDesc()); + } + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenResult openRet = openMaService.releaesAudited(); + logger.info(openRet.toString()); + boolean releaseSuccess = false; + if(openRet.isSuccess()) { + releaseSuccess = true; + } + if(releaseSuccess) { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.SUCCESS.getCode()); + } else { + if(openRet.getErrcode().equals("85052")) { // app is already released + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.SUCCESS.getCode()); + } else { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.FAIL.getCode()); + } + } + releaseStatus.setReleaseErrCode(gson.toJson(openRet)); + releaseStatus.setReleaseTime(new Date()); + if(isUpdate) { + weappReleaseStatusService.updateStatus(releaseStatus); + } else { + weappReleaseStatusService.saveStatus(releaseStatus); + } + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + if(e.getError().getErrorCode() == 85052) { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.SUCCESS.getCode()); + } else { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.FAIL.getCode()); + } + releaseStatus.setReleaseErrCode(e.getMessage()); + releaseStatus.setReleaseTime(new Date()); + if(isUpdate) { + weappReleaseStatusService.updateStatus(releaseStatus); + } else { + weappReleaseStatusService.saveStatus(releaseStatus); + } + return new ResultData(Result.ERROR, e.getMessage()); + } + } else { + return new ResultData(ErrorCode.WEAPP_NOT_AUDITED); + } + } + + @ApiOperation("小程序版本回退") + @GetMapping("/revertCodeRelease") + public ResultData revertCodeRelease(String appId) { + Gson gson = new GsonBuilder().create(); + WxWeappReleaseStatus releaseStatus = weappReleaseStatusService.getByAppId(appId); + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenResult openRet = openMaService.revertCodeReleaes(); + logger.info(openRet.toString()); + if(openRet.isSuccess()) { + if(releaseStatus != null) { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.BACK.getCode()); + releaseStatus.setReleaseErrCode(gson.toJson(openRet)); + releaseStatus.setReleaseTime(new Date()); + weappReleaseStatusService.updateStatus(releaseStatus); + } + return new ResultData(); + } + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation("查询当前设置的最低基础库版本及各版本用户占比") + @GetMapping("/getSupportVersion") + public ResultData getSupportVersion(String appId) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + String openRet = openMaService.getSupportVersion(); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation("设置最低基础库版本") + @GetMapping("/setSupportVersion") + public ResultData setSupportVersion(String appId, String version) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + String openRet = openMaService.setSupportVersion(version); + logger.info(openRet); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation(value = "小程序审核撤回", notes = "单个帐号每天审核撤回次数最多不超过1次,一个月不超过10次。") + @GetMapping("/undoCodeAudit") + public ResultData undoCodeAudit(String appId) { + Gson gson = new GsonBuilder().create(); + WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId); + if(auditStatus != null) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenResult openResult = openMaService.undoCodeAudit(); + Date curDate = new Date(); + if(openResult.isSuccess()) { + // 审核状态 + auditStatus.setAuditStatus(EnumWeappAuditStatus.UNDO.getCode()); + auditStatus.setAuditErrCode(gson.toJson(openResult)); + auditStatus.setAuditTime(curDate); + weappAuditStatusService.updateStatus(auditStatus); + // 审核次数记入wx_authorizer_info + WxAuthorizerInfo authorizerInfo = new WxAuthorizerInfo(); + authorizerInfo.setAuthorizerAppid(appId); + authorizerInfo.setAuditBackTime(curDate); + authorizerInfoService.updateAuthBackInfo(authorizerInfo); + return new ResultData("审核撤回成功"); + } + return new ResultData(Result.ERROR, "审核撤回失败"); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + return new ResultData(Result.ERROR, "没有审核记录,不能撤回"); + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappDraftTemplateController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappDraftTemplateController.java new file mode 100644 index 0000000..2173ddf --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappDraftTemplateController.java @@ -0,0 +1,79 @@ +package com.iformall.controller; + +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.service.wechat.FmOpenService; +import io.swagger.annotations.Api; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.bean.WxOpenMaCodeTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Stormeye Wu + */ +@RestController +@RequestMapping("/weappDraftTemplate") +@Api(description = "微信第三方开发平台-小程序-代码模版库管理") +public class WechatWeappDraftTemplateController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private FmOpenService openService; + + + @GetMapping("/tempDraftList") + public ResultData getTempDraftList() { + try { + List list = openService.getWxOpenComponentService().getTemplateDraftList(); + return new ResultData(list); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + + } + + @GetMapping("/tempList") + public ResultData getTempList() { + try { + List list = openService.getWxOpenComponentService().getTemplateList(); + return new ResultData(list); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @PostMapping("/addToTemplate") + public ResultData addToTemplate(@RequestBody WxOpenMaCodeTemplate template) { + if(template == null || template.getDraftId() == null) { + return new ResultData(Result.ERROR, "draftId is null"); + } + try { + openService.getWxOpenComponentService().addToTemplate(template.getDraftId()); + return new ResultData(); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @PostMapping("/deleteTemplate") + public ResultData deleteTemplate(@RequestBody WxOpenMaCodeTemplate template) { + if(template == null || template.getTemplateId() == null) { + return new ResultData(Result.ERROR, "templateId is null"); + } + try { + openService.getWxOpenComponentService().deleteTemplate(template.getTemplateId()); + return new ResultData(); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappMsgTemplateController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappMsgTemplateController.java new file mode 100644 index 0000000..7b0ac2f --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappMsgTemplateController.java @@ -0,0 +1,175 @@ +package com.iformall.controller; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult; +import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryGetResult; +import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateLibraryListResult; +import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateListResult; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxAuthorizerInfo; +import com.iformall.domain.po.WxTemplateMsg; +import com.iformall.enums.EnumWxAuthorizationStatus; +import com.iformall.service.WxAppinfoService; +import com.iformall.service.WxAuthorizerInfoService; +import com.iformall.service.WxTemplateMsgService; +import com.iformall.service.wechat.FmOpenService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * Stormeye Wu + */ +@RestController +@RequestMapping("/weappMsgTemplate") +@Api(description = "微信第三方开发平台-小程序-消息模板设置") +public class WechatWeappMsgTemplateController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + @Autowired + private FmOpenService openService; + + @Autowired + private WxAuthorizerInfoService authorizerInfoService; + + @Autowired + private WxAppinfoService appinfoService; + + @Autowired + private WxTemplateMsgService templateMsgService; + + @ApiOperation("获取小程序模板库标题列表") + @GetMapping("getTmpLibList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "appId", value = "appId", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData getTmpLibList(String appId, Integer pageNum, Integer pageSize) { + try { + WxMaService maService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxMaTemplateLibraryListResult ret = maService.getTemplateService().findTemplateLibraryList(pageNum, pageSize); + return new ResultData(ret); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation("获取模板库某个模板标题下关键词库") + @GetMapping("getTemplateLibraryKeywordList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "appId", value = "appId", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "id", value = "模板标题id", dataType = "String", paramType = "query", required = true)}) + public ResultData findTemplateLibraryKeywordList(String appId, String id) { + try { + WxMaService maService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxMaTemplateLibraryGetResult ret = maService.getTemplateService().findTemplateLibraryKeywordList(id); + return new ResultData(ret); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + + } + + @ApiOperation("组合模板并添加至帐号下的个人模板库") + @PostMapping("addTemplate") + public ResultData addTemplate(String appId, String id, List keywordIdList) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + try { + WxMaService maService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxMaTemplateAddResult ret = maService.getTemplateService().addTemplate(id, keywordIdList); + authorizerInfo.setTemplateStatus(0); + authorizerInfo.setTemplateTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + authorizerInfoService.updateTemplate(authorizerInfo); + return new ResultData(ret); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + authorizerInfo.setTemplateStatus(1); + authorizerInfo.setTemplateTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + authorizerInfoService.updateTemplate(authorizerInfo); + return new ResultData(Result.ERROR, e.getMessage()); + } + + } + + @ApiOperation("获取帐号下已存在的模板列表") + @GetMapping("getTemplateList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "appId", value = "appId", dataType = "String", paramType = "query", required = true), + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData findTemplateList(String appId, Integer pageNum, Integer pageSize) { + try { + WxMaService maService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + if(pageNum > 0) { + pageNum = pageNum - 1; + } + WxMaTemplateListResult ret = maService.getTemplateService().findTemplateList(pageNum, pageSize); + logger.info(ret.toString()); + return new ResultData(ret); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + + } + + @ApiOperation("删除帐号下的某个模板") + @PostMapping("delTemplate") + public ResultData delTemplate(@RequestBody Map params) { + String appId = params.get("appId"); + String templateId = params.get("templateId"); + if(StringUtils.isBlank(appId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + if(StringUtils.isBlank(templateId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + // check app + WxAppinfo appinfo = appinfoService.getByAppId(appId); + if(appinfo == null) { + String msg = "此appId未纳入管理,请联系管理员"; + logger.error(msg); + return new ResultData(Result.ERROR, msg); + } + WxTemplateMsg msgQ = new WxTemplateMsg(); + msgQ.setTemplateId(templateId); + msgQ.setTenantId(appinfo.getTenantId()); + WxTemplateMsg msg = templateMsgService.getByObj(msgQ); + if(msg != null) { + String msgStr = "此模板正被使用,请不要删除"; + logger.error(msgStr); + return new ResultData(Result.ERROR, msgStr); + } + try { + WxMaService maService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + maService.getTemplateService().delTemplate(templateId); + return new ResultData(); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappSetController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappSetController.java new file mode 100644 index 0000000..5df98e3 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WechatWeappSetController.java @@ -0,0 +1,231 @@ +package com.iformall.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.domain.po.WxAuthorizerInfo; +import com.iformall.enums.EnumEnableType; +import com.iformall.enums.EnumWxAuthorizationStatus; +import com.iformall.service.WxAuthorizerInfoService; +import com.iformall.service.wechat.FmOpenService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.api.WxOpenMaService; +import me.chanjar.weixin.open.bean.result.*; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import java.util.Date; +import java.util.List; +import java.util.Map; + +/** + * Stormeye Wu + */ +@RestController +@RequestMapping("/weappSet") +@Api(description = "微信第三方开发平台-小程序设置") +public class WechatWeappSetController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + @Autowired + private FmOpenService openService; + + @Autowired + private WxAuthorizerInfoService authorizerInfoService; + + @ApiOperation("获取小程序的信息") + @GetMapping("/getInfo") + public ResultData getAccountBasicInfo(String appId) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + String openRet = openMaService.getAccountBasicInfo(); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + return new ResultData(Result.ERROR); + } + + @ApiOperation("获取小程序服务器域名") + @GetMapping("/getDomain") + public ResultData getDomain(String appId) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenResult openRet = openMaService.getDomain(); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + + } + + @ApiOperation("获取小程序服务器域名") + @GetMapping("/getWebDomain") + public ResultData getWebDomain(String appId) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + String openRet = openMaService.getWebViewDomain(); + logger.info(openRet); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + + @ApiOperation(value = "设置小程序服务器域名", notes = "{\n" + + " \"action\":\"add/set/delete/get\",\n" + + " \"requestdomain\":[\"https://www.qq.com\",\"https://www.qq.com\"],\n" + + " \"wsrequestdomain\":[\"wss://www.qq.com\",\"wss://www.qq.com\"],\n" + + " \"uploaddomain\":[\"https://www.qq.com\",\"https://www.qq.com\"],\n" + + " \"downloaddomain\":[\"https://www.qq.com\",\"https://www.qq.com\"],\n" + + " }") + @PostMapping("/modifyDomain") + public ResultData modifyDomain(String appId, String action, + List requestDomain, List wsrequestdomain, + List uploaddomain, List downloaddomain) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenMaDomainResult openRet = openMaService.modifyDomain(action, + requestDomain, wsrequestdomain, + uploaddomain, downloaddomain); + logger.info(openRet.toString()); + if(openRet.isSuccess()) { + logger.info("设置服务器域名成功"); + authorizerInfo.setDomainStatus(EnumEnableType.SUCC.getCode()); + authorizerInfo.setDomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + + } else { + logger.info("设置服务器域名成功"); + authorizerInfo.setDomainStatus(EnumEnableType.FAIL.getCode()); + authorizerInfo.setDomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + } + authorizerInfoService.updateDomainUrl(authorizerInfo); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + return new ResultData(Result.ERROR); + } + + @ApiOperation(value = "设置小程序业务域名", notes = "{\n" + + " \"action\":\"add/set/delete/get\",\n" + + " \"webviewdomain\":[\"https://www.qq.com\",\"https://m.qq.com\"]\n" + + " }") + @PostMapping("/modifyWebViewDomain") + public ResultData modifyWebViewDomain(String appId, String action, + List urlList) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + String openRet = openMaService.setWebViewDomain(action, urlList); + logger.info(openRet); + JSONObject webRetObj = JSON.parseObject(openRet); + if(webRetObj.getInteger("errcode").equals(0)) { + logger.info("设置服务器业务域名成功"); + authorizerInfo.setWebdomainStatus(EnumEnableType.SUCC.getCode()); + authorizerInfo.setWebdomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + } else { + logger.info("设置服务器业务域名失败"); + authorizerInfo.setWebdomainStatus(EnumEnableType.FAIL.getCode()); + authorizerInfo.setWebdomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + } + authorizerInfoService.updateWebDomainUrl(authorizerInfo); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + return new ResultData(Result.ERROR); + } + + @ApiOperation(value = "绑定微信用户为小程序体验者", notes = "{\"appId\":\"string\", \"wechatId\":\"string\"}") + @PostMapping("/bindTester") + public ResultData bindTester(@RequestBody Map params) { + String appId = params.get("appId"); + String wechatId = params.get("wechatId"); + if(StringUtils.isBlank(appId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "appId不能为空"); + } + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(StringUtils.isBlank(wechatId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "wechatId不能为空"); + } + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenResult openRet = openMaService.bindTester(wechatId); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(e.getMessage()); + } + } + + @ApiOperation(value = "解除绑定小程序的体验者", notes = "") + @PostMapping("/unbindTester") + public ResultData unbindTester(@RequestBody Map params) { + String appId = params.get("appId"); + String wechatId = params.get("wechatId"); + if(StringUtils.isBlank(appId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "appId不能为空"); + } + if(StringUtils.isBlank(wechatId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "wechatId不能为空"); + } + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenResult openRet = openMaService.unbindTester(wechatId); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(e.getMessage()); + } + } + + @ApiOperation(value = "获取体验者列表", notes = "") + @GetMapping("/getTesterList") + public ResultData getTesterList(@RequestParam(value = "appId") String appId) { + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + WxOpenResult openRet = openMaService.getTesterList(); + logger.info(openRet.toString()); + return new ResultData(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + return new ResultData(Result.ERROR); + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappBasicSetController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappBasicSetController.java new file mode 100644 index 0000000..cf05151 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappBasicSetController.java @@ -0,0 +1,63 @@ +package com.iformall.controller; + +import com.github.pagehelper.PageInfo; +import com.iformall.common.ErrorCode; +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.domain.po.WxWeappBasicSet; +import com.iformall.service.WxWeappBasicSetService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +/** + * Stormeye Wu + */ +@Controller +@RequestMapping("/weappBasicSet") +@Api(description = "小程序基础设置接口") +public class WxWeappBasicSetController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private Integer getFmDeploy; + + @Autowired + private WxWeappBasicSetService weappBasicSetService; + + @ApiOperation("分页列表接口") + @GetMapping("list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData list(@ModelAttribute WxWeappBasicSet weappBasicSet, Integer pageNum, Integer pageSize) { + logger.debug("[" + getIpAddr() + "] WxWeappBasicSetController::list"); + if (null == weappBasicSet) weappBasicSet = new WxWeappBasicSet(); + weappBasicSet.setDeploy(getFmDeploy); + final PageInfo page = weappBasicSetService.listAsPage(weappBasicSet, pageNum, pageSize); + return new ResultData(page); + } + + @PostMapping("add") + public ResultData add(WxWeappBasicSet weappBasicSet) { + logger.debug("[" + getIpAddr() + "] WxWeappBasicSetController::add"); + if (null == weappBasicSet) return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + weappBasicSetService.saveOrUpdate(weappBasicSet); + return new ResultData(); + } + + @PostMapping("update") + public ResultData update(WxWeappBasicSet weappBasicSet) { + logger.debug("[" + getIpAddr() + "] WxWeappBasicSetController::update"); + if (null == weappBasicSet) return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + weappBasicSetService.saveOrUpdate(weappBasicSet); + return new ResultData(); + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappExtSetController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappExtSetController.java new file mode 100644 index 0000000..4fac15e --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappExtSetController.java @@ -0,0 +1,138 @@ +package com.iformall.controller; + +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.iformall.common.ErrorCode; +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.domain.po.WxAppinfo; +import com.iformall.domain.po.WxWeappExtSet; +import com.iformall.enums.EnumAppType; +import com.iformall.service.WxAppinfoService; +import com.iformall.service.WxWeappExtSetService; +import com.iformall.utils.OpenConstant; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * Stormeye Wu + */ +@Controller +@RequestMapping("/weappExtSet") +@Api(description = "小程序扩展设置接口") +public class WxWeappExtSetController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private WxAppinfoService appinfoService; + + @Autowired + private WxWeappExtSetService weappExtSetService; + + @ApiOperation("分页列表接口") + @GetMapping("list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData list(@ModelAttribute WxWeappExtSet weappExtSet, Integer pageNum, Integer pageSize) { + logger.debug("[" + getIpAddr() + "] WxWeappExtSetController::list"); + if (null == weappExtSet) weappExtSet = new WxWeappExtSet(); + final PageInfo page = weappExtSetService.listAsPage(weappExtSet, pageNum, pageSize); + return new ResultData(page); + } + + @PostMapping("add") + public ResultData add(@RequestBody WxWeappExtSet weappExtSet) { + logger.debug("[" + getIpAddr() + "] WxWeappExtSetController::add"); + if (null == weappExtSet) return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + weappExtSetService.saveOrUpdate(weappExtSet); + return new ResultData(); + } + + @PostMapping("update") + public ResultData update(@RequestBody WxWeappExtSet weappExtSet) { + logger.debug("[" + getIpAddr() + "] WxWeappBasicSetController::update"); + if (null == weappExtSet) return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + if (StringUtils.isBlank(weappExtSet.getExtJson())) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + if (StringUtils.isBlank(weappExtSet.getReleaseJson())) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + weappExtSetService.saveOrUpdate(weappExtSet); + return new ResultData(); + } + + @ApiOperation("扩展模板-批量模板更新") + @PostMapping("batchUpdate") + public ResultData batchAdd(@RequestBody WxWeappExtSet weappExtSet) { + logger.debug("[" + getIpAddr() + "] WxWeappExtSetController::batchUpdate"); + if (null == weappExtSet) return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + if(StringUtils.isBlank(weappExtSet.getExtJson())) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + if(weappExtSet.getType() == null) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + String extJson = weappExtSet.getExtJson(); + JSONObject obj = JSON.parseObject(extJson); + if(obj == null) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + JSONObject extObj = obj.getJSONObject(OpenConstant.EXT); + if(extObj == null) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + JSONObject attrObj = extObj.getJSONObject(OpenConstant.ATTR); + if(attrObj == null) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + WxWeappExtSet extSetQ = new WxWeappExtSet(); + extSetQ.setType(weappExtSet.getType()); + List weappExtSetList = weappExtSetService.getList(extSetQ); + for(WxWeappExtSet info: weappExtSetList) { + WxAppinfo appinfo = appinfoService.getByAppId(info.getAppId()); + if(appinfo == null) { + continue; + } + obj.put(OpenConstant.EXT_APPID, info.getAppId()); + if(weappExtSet.getType().equals(EnumAppType.C.getCode())) { + if (attrObj != null) { + attrObj.put(OpenConstant.IF_HAVE_CAR_MODULE, String.valueOf(info.getCarSupport())); + attrObj.put(OpenConstant.IF_STORE_APP, String.valueOf(info.getStoreApp())); + } + } + if(extObj != null) { + extObj.put(OpenConstant.WE_APPID, info.getAppId()); + extObj.put(OpenConstant.NAME, appinfo.getName()); + if(weappExtSet.getType().equals(EnumAppType.C.getCode())) { + extObj.put(OpenConstant.ATTR, attrObj); + } + obj.put(OpenConstant.EXT, extObj); + } + + WxWeappExtSet newInfo = new WxWeappExtSet(); + newInfo.setExtJson(JSON.toJSONString(obj)); + newInfo.setId(info.getId()); + + try { + weappExtSetService.saveOrUpdate(newInfo); + } catch (Exception e) { + logger.error("APPID " + info.getAppId() + ", 保存失败 " + e.getMessage()); + } + } + return new ResultData(); + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappInfoController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappInfoController.java new file mode 100644 index 0000000..1bd88f8 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/WxWeappInfoController.java @@ -0,0 +1,1047 @@ +package com.iformall.controller; + +import cn.binarywang.wx.miniapp.api.WxMaService; +import cn.binarywang.wx.miniapp.bean.template.WxMaTemplateAddResult; +import com.alibaba.fastjson.JSON; +import com.alibaba.fastjson.JSONArray; +import com.alibaba.fastjson.JSONObject; +import com.github.pagehelper.PageInfo; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; +import com.iformall.common.ErrorCode; +import com.iformall.common.Result; +import com.iformall.common.ResultData; +import com.iformall.controller.base.BaseController; +import com.iformall.domain.po.*; +import com.iformall.domain.vo.WxWeappAuditStatusVo; +import com.iformall.domain.vo.WxWeappCodeStatusVo; +import com.iformall.domain.vo.WxWeappInfo; +import com.iformall.domain.vo.WxWeappReleaseStatusVo; +import com.iformall.enums.*; +import com.iformall.service.*; +import com.iformall.service.wechat.FmOpenService; +import com.iformall.utils.Constant; +import com.iformall.utils.OpenConstant; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiImplicitParam; +import io.swagger.annotations.ApiImplicitParams; +import io.swagger.annotations.ApiOperation; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.open.api.WxOpenMaService; +import me.chanjar.weixin.open.bean.ma.WxMaOpenCommitExtInfo; +import me.chanjar.weixin.open.bean.message.WxOpenMaSubmitAuditMessage; +import me.chanjar.weixin.open.bean.result.WxOpenMaDomainResult; +import me.chanjar.weixin.open.bean.result.WxOpenMaQueryAuditResult; +import me.chanjar.weixin.open.bean.result.WxOpenMaSubmitAuditResult; +import me.chanjar.weixin.open.bean.result.WxOpenResult; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import java.util.*; + +/** + * Stormeye Wu + */ +@Controller +@RequestMapping("/weapp") +@Api(description = "小程序") +public class WxWeappInfoController extends BaseController { + private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private Integer getFmDeploy; + + @Autowired + private WxAuthorizerInfoService authorizerInfoService; + + @Autowired + private WxWeappBasicSetService weappBasicSetService; + + @Autowired + private WxWeappExtSetService weappExtSetService; + + @Autowired + private WxWeappCodeStatusService weappCodeStatusService; + + @Autowired + private WxWeappAuditStatusService weappAuditStatusService; + + @Autowired + private WxWeappReleaseStatusService weappReleaseStatusService; + + @Autowired + private FmOpenService openService; + + @Autowired + private WxAppinfoService appinfoService; + + @Autowired + private WxTemplateMsgService templateMsgService; + + + @ApiOperation(value = "小程序分页列表接口", notes = "查询支持小程序类型,名称,appid,version") + @GetMapping("list") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData list(@ModelAttribute WxWeappInfo weappInfo, Integer pageNum, Integer pageSize) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::list"); + if (null == weappInfo) { + weappInfo = new WxWeappInfo(); + } else { + if(StringUtils.isBlank(weappInfo.getName())) { + weappInfo.setName(null); + } + } + weappInfo.setSortColumns(BaseEntity.SortField.TenantId_ASC,BaseEntity.SortField.Type_ASC,BaseEntity.SortField.Name_ASC); + final PageInfo page = authorizerInfoService.listVoAsPage(weappInfo, pageNum, pageSize); + return new ResultData(page); + } + + @ApiOperation("小程序列表接口") + @GetMapping("allist") + public ResultData getList(@ModelAttribute WxWeappInfo weappInfo) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::list"); + if (null == weappInfo) { + weappInfo = new WxWeappInfo(); + } else { + if(StringUtils.isBlank(weappInfo.getName())) { + weappInfo.setName(null); + } + } + weappInfo.setSortColumns(BaseEntity.SortField.CurrentVersion_DESC); + final List list = authorizerInfoService.getList(weappInfo); + return new ResultData(list); + } + + @ApiOperation(value = "APPs基础设置(服务器域名、业务域名、基础版本、微信模板)", notes = "{\"apps\":\"appid,appid\",\"type\":\"String\"}") + @PostMapping("batchBasicSet") + public ResultData batchSet(@RequestBody Map params) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::batchBasicSet"); + String appsStr = params.get(OpenConstant.APPS); + String typeStr = params.get(OpenConstant.TYPE); + + if(StringUtils.isBlank(typeStr)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "type参数不能为空"); + } + + Integer type = 0; + try { + type = Integer.parseInt(typeStr); + } catch (Exception e) { + return new ResultData(ErrorCode.SYS_PARAMETER_ERROR); + } + // 检查基础配置参数 + WxWeappBasicSet weappBasicSetQ = new WxWeappBasicSet(); + weappBasicSetQ.setType(type); + weappBasicSetQ.setDeploy(getFmDeploy); + WxWeappBasicSet weappBasicSet = weappBasicSetService.getByTypeAndDeploy(weappBasicSetQ); + if(weappBasicSet == null) { + logger.error("未找到相关的基础设置参数"); + return new ResultData(ErrorCode.WEAPP_BASIC_SET_ERR); + } + + JSONObject domainObj = JSON.parseObject(weappBasicSet.getDomainUrl()); + if(domainObj == null) { + logger.error("未找到相关的基础设置参数"); + return new ResultData(ErrorCode.WEAPP_BASIC_SET_DOMAIN_ERR); + } + JSONObject templeObj = JSON.parseObject(weappBasicSet.getTemplateInfo()); + logger.info(templeObj.toJSONString()); + + if(StringUtils.isBlank(appsStr)) { + WxWeappInfo weappInfoQ = new WxWeappInfo(); + weappInfoQ.setType(type); + List list = authorizerInfoService.getList(weappInfoQ); + for(WxWeappInfo info: list) { + appsStr += info.getAuthorizerAppid() + ","; + } + appsStr = appsStr.substring(0, appsStr.length() - 1); + } + + // 逐一设置app配置 + String [] apps = appsStr.split(","); + for(String appId: apps) { + // 检查appId是否已授权 + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + ResultData openRet = setBasicForAppId(appId, weappBasicSet, domainObj, templeObj); + if (openRet != null) return openRet; + } + return new ResultData(); + } + + @ApiOperation(value = "APP清除域名", notes = "{\"weappId\":\"weappId\",\"type\":\"String\"}") + @PostMapping("cleanDomain") + public ResultData cleanDomain(@RequestBody Map params) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::cleanDomain"); + String appId = params.get(OpenConstant.WE_APPID); + String typeStr = params.get(OpenConstant.TYPE); + + if(StringUtils.isBlank(typeStr)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "type参数不能为空"); + } + if(StringUtils.isBlank(appId)) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL.getCode(), "weappId参数不能为空"); + } + + Integer type = 0; + try { + type = Integer.parseInt(typeStr); + } catch (Exception e) { + return new ResultData(ErrorCode.SYS_PARAMETER_ERROR); + } + // 检查基础配置参数 + WxWeappBasicSet weappBasicSetQ = new WxWeappBasicSet(); + weappBasicSetQ.setType(type); + weappBasicSetQ.setDeploy(getFmDeploy); + WxWeappBasicSet weappBasicSet = weappBasicSetService.getByTypeAndDeploy(weappBasicSetQ); + if(weappBasicSet == null) { + logger.error("未找到相关的基础设置参数"); + return new ResultData(ErrorCode.WEAPP_BASIC_SET_ERR); + } + + JSONObject domainObj = JSON.parseObject(weappBasicSet.getDomainUrl()); + if(domainObj == null) { + logger.error("未找到相关的基础设置参数"); + return new ResultData(ErrorCode.WEAPP_BASIC_SET_DOMAIN_ERR); + } + + // 检查appId是否已授权 + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + try { + modifyDomainUrl(OpenConstant.DEL, domainObj, authorizerInfo, openMaService); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + return new ResultData(); + } + + private ResultData setBasicForAppId(String appId, WxWeappBasicSet weappBasicSet, JSONObject domainObj, JSONObject templeObj) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + try { + setBasicVersion(weappBasicSet, authorizerInfo, openMaService); + modifyDomainUrl(OpenConstant.SET, domainObj, authorizerInfo, openMaService); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + return new ResultData(Result.ERROR, e.getMessage()); + } + // 设置微信模板 + if(weappBasicSet.getType().equals(EnumAppType.C.getCode())) { + if(authorizerInfo.getTemplateStatus() == null || + !authorizerInfo.getTemplateStatus().equals(EnumWxAuthotizationTemplateStatus.SUCCESS.getCode())) { + // 模板未设置或者设置失败 + // 获取模板 + WxAppinfo appinfo = appinfoService.getByAppId(appId); + WxMaService maService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + + try { + setBasicTemplateMsgVerifySuccess(templeObj, appinfo, maService); + setBasicTemplateMsgVerifyFail(templeObj, appinfo, maService); + setBasicTemplateMsgPressSuccess(templeObj, appinfo, maService); + + // 更新状态 + authorizerInfo.setTemplateStatus(EnumWxAuthotizationTemplateStatus.SUCCESS.getCode()); + authorizerInfo.setTemplateTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + authorizerInfoService.updateTemplate(authorizerInfo); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + // 更新状态 + authorizerInfo.setTemplateStatus(EnumWxAuthotizationTemplateStatus.Fail.getCode()); + authorizerInfo.setTemplateTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + authorizerInfoService.updateTemplate(authorizerInfo); + return new ResultData(Result.ERROR, e.getMessage()); + } + } + } + // 设置成功返回null + return null; + } + + private void setBasicTemplateMsg(JSONObject templeObj, WxAppinfo appinfo, WxMaService maService, Integer msgCode, String msgTypeStr) throws WxErrorException { + JSONObject msgObj; + try { + msgObj = templeObj.getJSONObject(msgTypeStr); + } catch (Exception e) { + logger.error(e.getMessage()); + return; + } + logger.info(msgObj.toJSONString()); + String id = msgObj.getString(OpenConstant.ID); + JSONArray keyidlist = msgObj.getJSONArray(OpenConstant.KEY_ID_LIST); + String customParam = msgObj.getString(OpenConstant.CUSTOM_PARAM); + logger.info(customParam); + JSONObject customParamObj = JSON.parseObject(customParam); + List keyArr1 = getIdList(keyidlist); + if (appinfo != null) { + // wx_template_msg + WxTemplateMsg templateMsgQ = new WxTemplateMsg(); + templateMsgQ.setTenantId(appinfo.getTenantId()); + logger.info(msgCode.toString()); + templateMsgQ.setType(msgCode); + WxTemplateMsg templateMsg = templateMsgService.getByObj(templateMsgQ); + if (templateMsg != null) { + templateMsg.setCustomParam(customParamObj.toJSONString()); + templateMsgService.saveOrUpdate(templateMsg); + } else { + WxMaTemplateAddResult ret = maService.getTemplateService().addTemplate(id, keyArr1); + logger.info(ret.toString()); + templateMsgQ.setTemplateId(ret.getTemplateId()); + templateMsgQ.setCustomParam(customParamObj.toJSONString()); + templateMsgService.saveOrUpdate(templateMsgQ); + } + } + } + + private void setBasicTemplateMsgVerifySuccess(JSONObject templeObj, WxAppinfo appinfo, WxMaService maService) throws WxErrorException { + // 核销成功消息 + setBasicTemplateMsg(templeObj, appinfo, maService, EnumTemplateType.VERIFY_SUCCESS.getCode(), OpenConstant.VERIFY_SUCC); + } + + private void setBasicTemplateMsgVerifyFail(JSONObject templeObj, WxAppinfo appinfo, WxMaService maService) throws WxErrorException { + // 核销失败消息 + setBasicTemplateMsg(templeObj, appinfo, maService, EnumTemplateType.VERIFY_FAIL.getCode(), OpenConstant.VERIFY_FAIL); + } + + private void setBasicTemplateMsgPressSuccess(JSONObject templeObj, WxAppinfo appinfo, WxMaService maService) throws WxErrorException { + // 砍价成功消息 + logger.info("setBasicTemplateMsgPressSuccess begin.."); + /// EnumTemplateType.PRESS_PRICE_SUCCESS.getCode() + setBasicTemplateMsg(templeObj, appinfo, maService, 3, "press_success"); + logger.info("setBasicTemplateMsgPressSuccess end."); + } + + private void modifyDomainUrl(String action, JSONObject domainObj, WxAuthorizerInfo authorizerInfo, WxOpenMaService openMaService) throws WxErrorException { + // 服务器域名 + JSONObject urlObj = domainObj.getJSONObject(OpenConstant.URL); + List requestDomain = getUrlList(urlObj.getJSONArray(OpenConstant.REQ_DOMAIN)); + List wsrequestDomain = getUrlList(urlObj.getJSONArray(OpenConstant.WS_DOMAIN)); + List uploadDomain = getUrlList(urlObj.getJSONArray(OpenConstant.UPLOAD_DOMAIN)); + List downloadDomain = getUrlList(urlObj.getJSONArray(OpenConstant.DOWNLOAD_DOMAIN)); + logger.info(downloadDomain.toString()); + WxOpenMaDomainResult openRet = openMaService.modifyDomain(action, + requestDomain, wsrequestDomain, + uploadDomain, downloadDomain); + logger.info(openRet.toString()); + if(openRet.isSuccess()) { + logger.info("设置服务器域名成功"); + authorizerInfo.setDomainStatus(EnumEnableType.SUCC.getCode()); + authorizerInfo.setDomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + + } else { + logger.info("设置服务器域名成功"); + authorizerInfo.setDomainStatus(EnumEnableType.FAIL.getCode()); + authorizerInfo.setDomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + } + authorizerInfoService.updateDomainUrl(authorizerInfo); + // 业务域名 + JSONObject webObj = domainObj.getJSONObject(OpenConstant.WEB); + List urlList = getUrlList(webObj.getJSONArray(OpenConstant.WEB_DOMAIN)); + String openRet1 = openMaService.setWebViewDomain(action, urlList); + logger.info(openRet1); + JSONObject webRetObj = JSON.parseObject(openRet1); + if(webRetObj.getInteger(OpenConstant.ERRCODE).equals(0)) { + logger.info("设置服务器业务域名成功"); + authorizerInfo.setWebdomainStatus(EnumEnableType.SUCC.getCode()); + authorizerInfo.setWebdomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + } else { + logger.info("设置服务器业务域名失败"); + authorizerInfo.setWebdomainStatus(EnumEnableType.FAIL.getCode()); + authorizerInfo.setWebdomainTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + } + authorizerInfoService.updateWebDomainUrl(authorizerInfo); + } + + private void setBasicVersion(WxWeappBasicSet weappBasicSet, WxAuthorizerInfo authorizerInfo, WxOpenMaService openMaService) throws WxErrorException { + // 设置基础版本 + String versionRet = openMaService.setSupportVersion(weappBasicSet.getVersion()); + logger.info(versionRet); + JSONObject verObj = JSON.parseObject(versionRet); + if(verObj.getInteger(OpenConstant.ERRCODE).equals(OpenConstant.SUCC)) { + authorizerInfo.setBaseStatus(EnumEnableType.SUCC.getCode()); + } else { + authorizerInfo.setBaseStatus(EnumEnableType.FAIL.getCode()); + } + authorizerInfo.setBaseTime(new Date()); + authorizerInfo.setUpdateTime(new Date()); + authorizerInfoService.updateBaseVersion(authorizerInfo); + } + + private List getIdList(JSONArray keyidlist) { + List keyArr = new ArrayList(); + for (int i = 0; i < keyidlist.size(); i++) { + keyArr.add(keyidlist.getIntValue(i)); + } + return keyArr; + } + + private List getUrlList(JSONArray urlList) { + List keyArr = new ArrayList(); + for (int i = 0; i < urlList.size(); i++) { + keyArr.add(urlList.getString(i)); + } + return keyArr; + } + + @ApiOperation(value = "批量授权的小程序code提交", notes = "{\"apps\":\"appid,appid\",\"templateId\":\"String\",\"type\":\"String\",\"userVersion\":\"String\",\"userDesc\":\"String\"}") + @PostMapping("batchCodeCommit") + public ResultData batchCodeCommit(@RequestBody Map params) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::batchExtSet"); + String appsStr = params.get(OpenConstant.APPS); + String templateIdStr = params.get(OpenConstant.TEMPLATE_ID); + String typeStr = params.get(OpenConstant.TYPE); + String userVersion = params.get(OpenConstant.USER_VERSION); + String userDesc = params.get(OpenConstant.USER_DESC); + + Integer type = null; + Long templateId = null; + try { + templateId = Long.parseLong(templateIdStr); + } catch (Exception e) { + return new ResultData(ErrorCode.SYS_PARAMETER_ERROR); + } + + try { + type = Integer.parseInt(typeStr); + } catch (Exception e) { + logger.error("type为null"); + } + if(StringUtils.isBlank(appsStr)) { + if(type == null) { + logger.error("type为null"); + return new ResultData(ErrorCode.SYS_PARAMETER_ERROR); + } + WxWeappInfo authQ = new WxWeappInfo(); + authQ.setType(type); + List appList = authorizerInfoService.getList(authQ); + appsStr = ""; + StringBuilder sb = new StringBuilder(); + boolean bfirst = true; + for(WxWeappInfo app: appList) { + if(bfirst) { + sb.append(app.getAuthorizerAppid()); + bfirst = false; + } else { + sb.append(app.getAuthorizerAppid()).append(","); + } + } + } + String [] apps = appsStr.split(","); + // 逐一检查app的设置 + for(String appId: apps) { + WxWeappExtSet extSetQ = new WxWeappExtSet(); + extSetQ.setAppId(appId); + WxWeappExtSet extSet = weappExtSetService.getByObj(extSetQ); + if(extSet == null) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + if(StringUtils.isBlank(extSet.getExtJson())) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + if(StringUtils.isBlank(extSet.getReleaseJson())) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + } + // 逐一设置app配置 + for(String appId: apps) { + // 检查appId是否已授权 + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + codeCommit(appId, userVersion, userDesc, templateId); + } + return new ResultData(); + } + + private void codeCommit(String appId, String userVersion, String userDesc, Long templateId) { + WxAppinfo appinfo = appinfoService.getByAppId(appId); + + int iAppType = 0; + String appTypeStr = userVersion.substring(0, 1); + if(appTypeStr.equalsIgnoreCase(Constant.C)) + iAppType = EnumAppType.C.getCode(); + else if(appTypeStr.equalsIgnoreCase(Constant.B)) + iAppType = EnumAppType.B.getCode(); + + if(!appinfo.getType().equals(iAppType)) { + // 如果版本号与小程序的类型不一致,不提交版本 + return; + } + + // get ext json + WxWeappExtSet extSetQ = new WxWeappExtSet(); + extSetQ.setAppId(appId); + WxWeappExtSet extSet = weappExtSetService.getByObj(extSetQ); + WxWeappCodeStatus codeStatus = weappCodeStatusService.getByAppId(appId); + if(extSet != null) { + boolean codeCommitStatus = false; + if(codeStatus != null && codeStatus.getCodeStatus().equals(0) && codeStatus.getUserVersion().equals(userVersion)) { + codeCommitStatus = true; + } + if(!codeCommitStatus) { + codeCommitStatus = doCodeCommit(userVersion, userDesc, templateId, appinfo, extSet, codeStatus); + } + } + } + + @ApiOperation(value = "小程序批量提交审核", notes = "{\"type\":\"String\",\"userVersion\":\"String\",\"apps\":\"appid,appid\"}") + @PostMapping("batchCodeAudit") + public ResultData batchCodeAudit(@RequestBody Map params) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::batchExtSet"); + String appsStr = params.get(OpenConstant.APPS); + String typeStr = params.get(OpenConstant.TYPE); + String userVersion = params.get(OpenConstant.USER_VERSION); + Integer type = null; + try { + type = Integer.parseInt(typeStr); + } catch (Exception e) { + logger.error("小程序类型"); + } + if(StringUtils.isBlank(appsStr)) { + if(type == null) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + WxWeappInfo authQ = new WxWeappInfo(); + authQ.setType(type); + List appList = authorizerInfoService.getList(authQ); + appsStr = ""; + StringBuilder sb = new StringBuilder(); + boolean bfirst = true; + for(WxWeappInfo app: appList) { + if(bfirst) { + sb.append(app.getAuthorizerAppid()); + bfirst = false; + } else { + sb.append(app.getAuthorizerAppid()).append(","); + } + } + } + String [] apps = appsStr.split(","); + // 逐一检查app的设置 + for(String appId: apps) { + WxWeappExtSet extSetQ = new WxWeappExtSet(); + extSetQ.setAppId(appId); + WxWeappExtSet extSet = weappExtSetService.getByObj(extSetQ); + if(extSet == null) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + if(StringUtils.isBlank(extSet.getExtJson())) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + if(StringUtils.isBlank(extSet.getReleaseJson())) { + return new ResultData(ErrorCode.SYS_PARAMETER_NOT_NULL); + } + } + // 逐一设置app配置 + for(String appId: apps) { + // 检查appId是否已授权 + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + codeAudit(appId, userVersion); + } + return new ResultData(); + } + + private void codeAudit(String appId, String userVersion) { + // get ext json + WxWeappExtSet extSetQ = new WxWeappExtSet(); + extSetQ.setAppId(appId); + WxWeappExtSet extSet = weappExtSetService.getByObj(extSetQ); + WxWeappCodeStatus codeStatus = weappCodeStatusService.getByAppId(appId); + if(extSet != null) { + boolean codeCommitStatus = false; + if(codeStatus != null + && codeStatus.getCodeStatus().equals(EnumWeappCodeCommitStatus.SUCCESS.getCode()) + && codeStatus.getUserVersion().equals(userVersion)) { + codeCommitStatus = true; + } + if(codeCommitStatus) { + WxWeappAuditStatus auditStatus = weappAuditStatusService.getByAppId(appId); + if(auditStatus != null && auditStatus.getAuditStatus().equals(EnumWeappAuditStatus.AUDITING.getCode())) { + logger.error("审核中不能再提交审核"); + return; + } + doCodeAudit(codeStatus, auditStatus, extSet); + } else { + logger.error("CODE提交失败"); + } + } + } + + private boolean doCodeCommit(String userVersion, String userDesc, Long templateId, WxAppinfo appinfo, WxWeappExtSet extSet, WxWeappCodeStatus codeStatus) { + Gson gson = new GsonBuilder().create(); + // code提交 + boolean codeCommitStatus = false; + String codeErrCode = ""; + try { + WxMaOpenCommitExtInfo extInfo = gson.fromJson(extSet.getExtJson(), new TypeToken() {}.getType()); + logger.info("OLD: " + extInfo.toString()); + // 自动修改提交的版本 + if(extInfo.getExtMap().containsKey(OpenConstant.APP_VERSION)) { + extInfo.getExtMap().put(OpenConstant.APP_VERSION, userVersion); + } + logger.info("NEW: " + extInfo.toString()); + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appinfo.getAppId()); + WxOpenResult openRet = openMaService.codeCommit(templateId, userVersion, userDesc, extInfo); + logger.info(openRet.toString()); + if (openRet.isSuccess()) { + codeCommitStatus = true; + } + codeErrCode = gson.toJson(openRet); + } catch (WxErrorException e) { + codeCommitStatus = false; + codeErrCode = e.getMessage(); + logger.error(codeErrCode); + } + + if (codeStatus == null) { + codeStatus = new WxWeappCodeStatus(); + codeStatus.setId(appinfo.getId()); + codeStatus.setTenantId(appinfo.getTenantId()); + codeStatus.setAppId(appinfo.getAppId()); + if (appinfo != null) { + codeStatus.setType(appinfo.getType()); + } + codeStatus.setUserVersion(userVersion); + codeStatus.setVersionDesc(userDesc); + if(codeCommitStatus) { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.SUCCESS.getCode()); + } else { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.FAIL.getCode()); + } + codeStatus.setCodeErrCode(codeErrCode); + codeStatus.setCodeTime(new Date()); + weappCodeStatusService.saveStatus(codeStatus); + } else { + codeStatus.setUserVersion(userVersion); + codeStatus.setVersionDesc(userDesc); + if(codeCommitStatus) { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.SUCCESS.getCode()); + } else { + codeStatus.setCodeStatus(EnumWeappCodeCommitStatus.FAIL.getCode()); + } + codeStatus.setCodeErrCode(codeErrCode); + codeStatus.setCodeTime(new Date()); + weappCodeStatusService.updateStatus(codeStatus); + } + return codeCommitStatus; + } + + private void doCodeAudit(WxWeappCodeStatus codeStatus, WxWeappAuditStatus auditStatus, WxWeappExtSet extSet) { + Gson gson = new GsonBuilder().create(); + boolean submitStatus = false; + Long auditid = null; + String codeErrCode = ""; + try { + WxOpenMaSubmitAuditMessage subMessage = gson.fromJson(extSet.getReleaseJson(), new TypeToken() {}.getType()); + logger.info(subMessage.toString()); + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(codeStatus.getAppId()); + WxOpenMaSubmitAuditResult openRet = openMaService.submitAudit(subMessage); + logger.info(openRet.toString()); + if(openRet.isSuccess()) { + submitStatus = true; + auditid = openRet.getAuditId(); + } else { + submitStatus = false; + } + codeErrCode = gson.toJson(openRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + submitStatus = false; + codeErrCode = e.getMessage(); + } + + if (auditStatus == null) { + auditStatus = new WxWeappAuditStatus(); + auditStatus.setId(codeStatus.getId()); + auditStatus.setTenantId(codeStatus.getTenantId()); + auditStatus.setAppId(codeStatus.getAppId()); + auditStatus.setType(codeStatus.getType()); + auditStatus.setUserVersion(codeStatus.getUserVersion()); + auditStatus.setVersionDesc(codeStatus.getVersionDesc()); + auditStatus.setAuditid(auditid); + if(submitStatus) { + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + } else { + auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); + } + auditStatus.setAuditErrCode(codeErrCode); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.saveStatus(auditStatus); + } else { + auditStatus.setAuditid(auditid); + if(!submitStatus) { + if(!auditStatus.getUserVersion().equals(codeStatus.getUserVersion()) + && auditStatus.getAuditStatus().equals(EnumWeappAuditStatus.AUDITING.getCode())) { + // 当前审核中的数据不能替换 + return; + } + auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); + } else { + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + } + auditStatus.setUserVersion(codeStatus.getUserVersion()); + auditStatus.setVersionDesc(codeStatus.getVersionDesc()); + auditStatus.setAuditErrCode(codeErrCode); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.updateStatus(auditStatus); + } + } + + + @ApiOperation(value = "批量审核查询", notes = "{\"type\":\"string\",\"version\":\"string\"}") + @PostMapping("batchAuditQuery") + public ResultData batchAuditQuery(@RequestBody Map params) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::batchAuditQuery"); + Gson gson = new GsonBuilder().create(); + String typeStr = params.get(OpenConstant.TYPE); + String version = params.get(OpenConstant.VERSION); + Integer type = null; + try { + type = Integer.parseInt(typeStr); + } catch (Exception e) { + logger.error(e.getMessage()); + } + WxWeappAuditStatusVo queryVo = new WxWeappAuditStatusVo(); + if(StringUtils.isNotBlank(typeStr)) { + queryVo.setType(type); + } + if(StringUtils.isNotBlank(version)) { + queryVo.setUserVersion(version); + } + queryVo.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + List apps = weappAuditStatusService.getList(queryVo); + apps.stream().forEach( auditStatus -> { + // 审核中,可以发起审核查询 + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(auditStatus.getAppId()); + WxOpenMaQueryAuditResult openResult = openMaService.getLatestAuditStatus(); + logger.info(openResult.toString()); + if (openResult.isSuccess()) { + // 审核状态,其中0为审核成功,1为审核失败,2为审核中,3已撤回 + switch (openResult.getStatus().intValue()) { + case 0: + auditStatus.setAuditStatus(EnumWeappAuditStatus.SUCCESS.getCode()); + break; + case 1: + auditStatus.setAuditStatus(EnumWeappAuditStatus.FAIL.getCode()); + break; + case 2: + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + break; + case 3: + auditStatus.setAuditStatus(EnumWeappAuditStatus.UNDO.getCode()); + break; + default: + auditStatus.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + break; + } + auditStatus.setAuditErrCode(gson.toJson(openResult)); + auditStatus.setAuditid(openResult.getAuditId()); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.updateStatus(auditStatus); + } + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + }); + return new ResultData(); + } + + @ApiOperation(value = "批量审核撤回", notes = "{\"type\":\"string\",\"version\":\"string\"}") + @PostMapping("batchAuditCancel") + public ResultData batchAuditCancel(@RequestBody Map params) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::batchAuditCancel"); + Gson gson = new GsonBuilder().create(); + String typeStr = params.get(OpenConstant.TYPE); + String version = params.get(OpenConstant.VERSION); + Integer type = null; + try { + type = Integer.parseInt(typeStr); + } catch (Exception e) { + logger.error(e.getMessage()); + } + WxWeappAuditStatusVo queryVo = new WxWeappAuditStatusVo(); + if(StringUtils.isNotBlank(typeStr)) { + queryVo.setType(type); + } + if(StringUtils.isNotBlank(version)) { + queryVo.setUserVersion(version); + } + queryVo.setAuditStatus(EnumWeappAuditStatus.AUDITING.getCode()); + List apps = weappAuditStatusService.getList(queryVo); + apps.stream().forEach( auditStatus -> { + // 审核通过,已发布不可撤回 + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(auditStatus.getAppId()); + WxOpenResult openResult = openMaService.undoCodeAudit(); + logger.info(openResult.toString()); + if(openResult.isSuccess()) { + auditStatus.setAuditStatus(EnumWeappAuditStatus.UNDO.getCode()); + auditStatus.setAuditErrCode(gson.toJson(openResult)); + auditStatus.setAuditTime(new Date()); + weappAuditStatusService.updateStatus(auditStatus); + } + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + }); + return new ResultData(); + } + + @ApiOperation(value = "批量发布", notes = "{\"type\":\"string\", \"version\":\"string\"}") + @PostMapping("batchRelease") + public ResultData batchRelease(@RequestBody Map params) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::batchRelease"); + Gson gson = new GsonBuilder().create(); + String typeStr = params.get(OpenConstant.TYPE); + String version = params.get(OpenConstant.VERSION); + Integer type = null; + try { + type = Integer.parseInt(typeStr); + } catch (Exception e) { + logger.error(e.getMessage()); + } + WxWeappAuditStatusVo queryVo = new WxWeappAuditStatusVo(); + if(StringUtils.isNotBlank(typeStr)) { + queryVo.setType(type); + } + if(StringUtils.isNotBlank(version)) { + queryVo.setUserVersion(version); + } + queryVo.setAuditStatus(EnumWeappAuditStatus.SUCCESS.getCode()); + List apps = weappAuditStatusService.getList(queryVo); + apps.stream().forEach( auditStatus -> { + boolean isUpdate = false; + WxWeappReleaseStatus releaseStatus = weappReleaseStatusService.getByAppId(auditStatus.getAppId()); + if(releaseStatus != null) { + // 当前版本已发布成功,跳过 + if(releaseStatus.getUserVersion().equals(version) + && releaseStatus.getReleaseStatus().equals(EnumWeappReleaseStatus.SUCCESS.getCode())) { + return; + } + releaseStatus.setUserVersion(auditStatus.getUserVersion()); + releaseStatus.setVersionDesc(auditStatus.getVersionDesc()); + isUpdate = true; + } else { + releaseStatus = new WxWeappReleaseStatus(); + releaseStatus.setId(auditStatus.getId()); + releaseStatus.setTenantId(auditStatus.getTenantId()); + releaseStatus.setAppId(auditStatus.getAppId()); + releaseStatus.setType(auditStatus.getType()); + releaseStatus.setUserVersion(auditStatus.getUserVersion()); + releaseStatus.setVersionDesc(auditStatus.getVersionDesc()); + } + + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(auditStatus.getAppId()); + WxOpenResult openRet = openMaService.releaesAudited(); + logger.info(openRet.toString()); + boolean releaseSuccess = false; + if(openRet.isSuccess()) { + releaseSuccess = true; + } + if(releaseSuccess) { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.SUCCESS.getCode()); + } else { + if(openRet.getErrcode().equals(OpenConstant.ERR_CODE_APP_IS_RELEASED)) { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.SUCCESS.getCode()); + } else { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.FAIL.getCode()); + } + } + releaseStatus.setReleaseErrCode(gson.toJson(openRet)); + releaseStatus.setReleaseTime(new Date()); + if(isUpdate) { + weappReleaseStatusService.updateStatus(releaseStatus); + } else { + weappReleaseStatusService.saveStatus(releaseStatus); + } + } catch (WxErrorException e) { + logger.error(e.getMessage()); + if(e.getError().getErrorCode() == OpenConstant.ERR_APP_IS_RELEASED) { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.SUCCESS.getCode()); + } else { + releaseStatus.setReleaseStatus(EnumWeappReleaseStatus.FAIL.getCode()); + } + releaseStatus.setReleaseErrCode(e.getMessage()); + releaseStatus.setReleaseTime(new Date()); + if(isUpdate) { + weappReleaseStatusService.updateStatus(releaseStatus); + } else { + weappReleaseStatusService.saveStatus(releaseStatus); + } + } + }); + return new ResultData(); + } + + @ApiOperation(value = "小程序code提交状态分页列表接口", notes = "查询支持小程序类型,名称,appid,version") + @GetMapping("codeStatusList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData codeStatusList(@ModelAttribute WxWeappCodeStatusVo weappCodeStatusVo, Integer pageNum, Integer pageSize) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::codeStatusList"); + if (null == weappCodeStatusVo) { + weappCodeStatusVo = new WxWeappCodeStatusVo(); + } else { + if(StringUtils.isBlank(weappCodeStatusVo.getAppId())) { + weappCodeStatusVo.setAppId(null); + } + if(StringUtils.isBlank(weappCodeStatusVo.getName())) { + weappCodeStatusVo.setName(null); + } + } + weappCodeStatusVo.setSortColumns(BaseEntity.SortField.CodeTime_DESC, BaseEntity.SortField.TenantId_ASC, BaseEntity.SortField.Type_ASC, BaseEntity.SortField.UserVersion_DESC); + final PageInfo page = weappCodeStatusService.listAsPage(weappCodeStatusVo, pageNum, pageSize); + return new ResultData(page); + } + + @ApiOperation(value = "小程序审核状态分页列表接口", notes = "查询支持小程序类型,名称,appid,version") + @GetMapping("auditStatusList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData auditStatusList(@ModelAttribute WxWeappAuditStatusVo weappAuditStatusVo, Integer pageNum, Integer pageSize) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::auditStatusList"); + if (null == weappAuditStatusVo) { + weappAuditStatusVo = new WxWeappAuditStatusVo(); + } else { + if(StringUtils.isBlank(weappAuditStatusVo.getAppId())) { + weappAuditStatusVo.setAppId(null); + } + if(StringUtils.isBlank(weappAuditStatusVo.getName())) { + weappAuditStatusVo.setName(null); + } + } + weappAuditStatusVo.setSortColumns(BaseEntity.SortField.AuditTime_DESC, BaseEntity.SortField.TenantId_ASC, BaseEntity.SortField.Type_ASC, BaseEntity.SortField.UserVersion_DESC); + final PageInfo page = weappAuditStatusService.listAsPage(weappAuditStatusVo, pageNum, pageSize); + return new ResultData(page); + } + + @ApiOperation(value = "小程序发布状态分页列表接口", notes = "查询支持小程序类型,名称,appid,version") + @GetMapping("releaseStatusList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "pageNum", value = "页数", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "pageSize", value = "每页条数", dataType = "int", paramType = "query", required = true)}) + public ResultData releaseStatusList(@ModelAttribute WxWeappReleaseStatusVo weappReleaseStatusVo, Integer pageNum, Integer pageSize) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::releaseStatusList"); + if (null == weappReleaseStatusVo) { + weappReleaseStatusVo = new WxWeappReleaseStatusVo(); + } else { + if(StringUtils.isBlank(weappReleaseStatusVo.getAppId())) { + weappReleaseStatusVo.setAppId(null); + } + if(StringUtils.isBlank(weappReleaseStatusVo.getName())) { + weappReleaseStatusVo.setName(null); + } + } + weappReleaseStatusVo.setSortColumns(BaseEntity.SortField.ReleaseTime_DESC, BaseEntity.SortField.TenantId_ASC, BaseEntity.SortField.Type_ASC,BaseEntity.SortField.UserVersion_DESC); + final PageInfo page = weappReleaseStatusService.listAsPage(weappReleaseStatusVo, pageNum, pageSize); + return new ResultData(page); + } + + @ApiOperation("小程序code提交版本列表") + @GetMapping("codeVersionList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "type", value = "小程序类型", dataType = "int", paramType = "query", required = true)}) + public ResultData getCodeVersionList(Integer type) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::getCodeVersionList"); + final List list = weappCodeStatusService.getVersionList(type); + return new ResultData(list); + } + + @ApiOperation("小程序审核版本列表") + @GetMapping("auditVersionList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "type", value = "小程序类型", dataType = "int", paramType = "query", required = true), + @ApiImplicitParam(name = "status", value = "审核状态", dataType = "int", paramType = "query")}) + public ResultData getAuditVersionList(Integer type, Integer status) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::getAuditVersionList"); + final List list = weappAuditStatusService.getVersionList(type, status); + return new ResultData(list); + } + + @ApiOperation("小程序发布版本列表") + @GetMapping("releaseVersionList") + @ApiImplicitParams({ + @ApiImplicitParam(name = "type", value = "小程序类型", dataType = "int", paramType = "query", required = true)}) + public ResultData getReleaseVersionList(Integer type) { + logger.debug("[" + getIpAddr() + "] WxWeappInfoController::getReleaseVersionList"); + final List list = weappReleaseStatusService.getVersionList(type); + return new ResultData(list); + } + + /* + * 0. 回调搭建好 + * 1. wx_appinfo配置好 + * + * 10. 授权 + * 11. 设置服务器域名及业务域名 - B/C 配置表 + * C 服务器域名 c.malls.iformall.com + * 业务域名 c.malls.iformall.com,game.malls.iformall.com + * B 服务器域名 b.malls.iformall.com + * 业务域名 mobile.malls.iformall.com,admin.malls.iformall.com + * C 服务器域名 ciformall.youlane.cn + * 业务域名 ciformall.youlane.cn,game.youlane.cn + * B 服务器域名 biformall.youlane.cn + * 业务域名 mobile.youlane.cn,mall.youlane.cn + * C 服务器域名 ctest.malls.iformall.com + * 业务域名 ctest.malls.iformall.com,gametest.malls.iformall.com + * B 服务器域名 btest.malls.iformall.com + * 业务域名 mobiletest.malls.iformall.com,admintest.malls.iformall.com + * 12. 设置微信基础版本 - 配置 + * 2.0.9 + * 13. 设置微信模板 - 配置 + * 核销成功模板 AT0423 14,15,16,7,10,3,9 + * 核销失败模板 AT1824 1,3,4,5 + * 14. 草稿提交 + * 15. 模板 + * 16. 上传小程序代码 - 配置 ext.json + * 17. 体验二维码 + * 18. 提交审核 - json --- 获取审核ID + * 19. 获取审核结果 - 基于审核ID查询 -- event 回调 + * 20. 审核撤回 + * 21. 发布已通过审核的小程序 + * 22. oauth2refreshAccessToken + */ + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/controller/base/BaseController.java b/mlToutiaoOpen/src/main/java/com/iformall/controller/base/BaseController.java new file mode 100644 index 0000000..cca8d3e --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/controller/base/BaseController.java @@ -0,0 +1,45 @@ +package com.iformall.controller.base; + +import com.iformall.utils.IPUtil; +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 { + @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; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/interceptor/BodyReaderHttpServletRequestWrapper.java b/mlToutiaoOpen/src/main/java/com/iformall/interceptor/BodyReaderHttpServletRequestWrapper.java new file mode 100644 index 0000000..7be788b --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/interceptor/BodyReaderHttpServletRequestWrapper.java @@ -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); + StringBuffer stringBuilder = new StringBuffer(); + 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; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/interceptor/HttpServletRequestWrapperFilter.java b/mlToutiaoOpen/src/main/java/com/iformall/interceptor/HttpServletRequestWrapperFilter.java new file mode 100644 index 0000000..a042741 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/interceptor/HttpServletRequestWrapperFilter.java @@ -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 static final Logger logger = LoggerFactory.getLogger(HttpServletRequestWrapperFilter.class); + // 多个跨域域名设置 + // 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 { + + 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); + + if (request instanceof HttpServletRequest) { + String 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); + } + + } + + + @Override + public void destroy() { + + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/interceptor/XssHttpServletRequestWrapper.java b/mlToutiaoOpen/src/main/java/com/iformall/interceptor/XssHttpServletRequestWrapper.java new file mode 100644 index 0000000..1d954d1 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/interceptor/XssHttpServletRequestWrapper.java @@ -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 notAllowedKeyWords = new HashSet(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 getParameterMap(){ + Map values=super.getParameterMap(); + if (values == null) { + return null; + } + Map 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("<", "<").replaceAll(">", ">"); + 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; + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/AbstractBuilder.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/AbstractBuilder.java new file mode 100644 index 0000000..7dabed7 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/AbstractBuilder.java @@ -0,0 +1,17 @@ +package com.iformall.mp.builder; + +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Stormeye + */ +public abstract class AbstractBuilder { + protected final Logger logger = LoggerFactory.getLogger(getClass()); + + public abstract WxMpXmlOutMessage build(String content, + WxMpXmlMessage wxMessage, WxMpService service); +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/ImageBuilder.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/ImageBuilder.java new file mode 100644 index 0000000..54e00de --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/ImageBuilder.java @@ -0,0 +1,24 @@ +package com.iformall.mp.builder; + +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutImageMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +public class ImageBuilder extends AbstractBuilder { + + @Override + public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, + WxMpService service) { + + WxMpXmlOutImageMessage m = WxMpXmlOutMessage.IMAGE().mediaId(content) + .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) + .build(); + + return m; + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/TextBuilder.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/TextBuilder.java new file mode 100644 index 0000000..4253950 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/builder/TextBuilder.java @@ -0,0 +1,25 @@ +package com.iformall.mp.builder; + +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutTextMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Binary Wang(https://github.com/binarywang) + */ +public class TextBuilder extends AbstractBuilder { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public WxMpXmlOutMessage build(String content, WxMpXmlMessage wxMessage, + WxMpService service) { + WxMpXmlOutTextMessage m = WxMpXmlOutMessage.TEXT().content(content) + .fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser()) + .build(); + return m; + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMemController.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMemController.java new file mode 100644 index 0000000..5b0f320 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMemController.java @@ -0,0 +1,114 @@ +package com.iformall.mp.controller; + +import com.iformall.common.ResultData; +import com.iformall.domain.po.WxAuthorizerInfo; +import com.iformall.mapper.WxAuthorizerInfoMapper; +import com.iformall.mp.manager.WxMpManager; +import com.iformall.service.WxCUserService; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import me.chanjar.weixin.mp.bean.result.WxMpUserList; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.List; + +/** + * @author Stormeye + */ +@RestController +@RequestMapping("/wx/{appId}/mem") +public class WxMemController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private WxMpManager wxMpManager; + + @Autowired + private WxAuthorizerInfoMapper wxAuthorizerInfoMapper; + + @Autowired + private WxCUserService userService; + + @GetMapping("/syncAccountFansList") + public ResultData syncAccountFansList(@PathVariable String appId) { + final WxMpService wxService = wxMpManager.getMpService(appId); + + WxAuthorizerInfo authQ = new WxAuthorizerInfo(); + authQ.setAuthorizerAppid(appId); + WxAuthorizerInfo authorizerInfo = wxAuthorizerInfoMapper.findWeChatMp(authQ); + + String nextOpenId = null; + + while (true) { + WxMpUserList mpUserList; + try { + mpUserList = wxService.getUserService().userList(nextOpenId); + } catch (WxErrorException e) { + logger.error("获取粉丝openIds出错: " + e.getMessage()); + break; + } + logger.info(mpUserList.toString()); + getBatchUserInfos(wxService, mpUserList, authorizerInfo); + nextOpenId = mpUserList.getNextOpenid(); + if(StringUtils.isBlank(nextOpenId)) { + break; + } + } + return new ResultData(); + } + + private void getBatchUserInfos(WxMpService wxService, WxMpUserList mpUserList, WxAuthorizerInfo authorizerInfo) { + List openIds = mpUserList.getOpenids(); + + if(openIds.size() > 100) { + int index = 0; + int index_end = index + 100; + while(true) { + if(openIds.size()-1 > index_end) { + getBatchUserInfo(wxService, openIds.subList(index, index_end), authorizerInfo); + } else if(openIds.size()-1 > index) { + getBatchUserInfo(wxService, openIds.subList(index, openIds.size()-1), authorizerInfo); + } else { + break; + } + index += 100; + index_end = index + 100; + } + } else { + getBatchUserInfo(wxService, openIds, authorizerInfo); + } + } + + private void getBatchUserInfo(WxMpService wxService, List openIds, WxAuthorizerInfo authorizerInfo) { + if(openIds.size() <= 0) { + return; + } + List userList = null; + try{ + userList = wxService.getUserService().userInfoList(openIds); + } catch (WxErrorException e) { + logger.error("batchget userinfo list error: " + e.getMessage()); + return; + } + if(userList != null) { + logger.info(userList.toString()); + for(WxMpUser mpUser: userList) { + if(StringUtils.isNotBlank(mpUser.getUnionId())) { + try { + userService.saveOrUpdateMpUser(mpUser, authorizerInfo); + } catch (Exception e) { + logger.error("保存用户出错: " + e.getMessage()); + } + } + } + } + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMenuController.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMenuController.java new file mode 100644 index 0000000..f8016c8 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMenuController.java @@ -0,0 +1,190 @@ +package com.iformall.mp.controller; + +import com.iformall.mp.manager.WxMpManager; +import me.chanjar.weixin.common.api.WxConsts; +import me.chanjar.weixin.common.bean.menu.WxMenu; +import me.chanjar.weixin.common.bean.menu.WxMenuButton; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.bean.menu.WxMpGetSelfMenuInfoResult; +import me.chanjar.weixin.mp.bean.menu.WxMpMenu; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; + +import javax.servlet.http.HttpServletRequest; +import java.net.MalformedURLException; +import java.net.URL; + +import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType; + +/** + * @author Stormeye + */ +@RestController +@RequestMapping("/wx/menu/{appId}") +public class WxMenuController { + + @Autowired + private WxMpManager wxMpManager; + + /** + *

+     * 自定义菜单创建接口
+     * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
+     * 如果要创建个性化菜单,请设置matchrule属性
+     * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+     * 
+ * + * @return 如果是个性化菜单,则返回menuid,否则返回null + */ + @PostMapping("/create") + public String menuCreate(@PathVariable String appId, @RequestBody WxMenu menu) throws WxErrorException { + return wxMpManager.getMpService(appId).getMenuService().menuCreate(menu); + } + + @GetMapping("/create") + public String menuCreateSample(@PathVariable String appId) throws WxErrorException, MalformedURLException { + WxMenu menu = new WxMenu(); + WxMenuButton button1 = new WxMenuButton(); + button1.setType(MenuButtonType.CLICK); + button1.setName("今日歌曲"); + button1.setKey("V1001_TODAY_MUSIC"); + +// WxMenuButton button2 = new WxMenuButton(); +// button2.setType(WxConsts.BUTTON_MINIPROGRAM); +// button2.setName("小程序"); +// button2.setAppId("wx286b93c14bbf93aa"); +// button2.setPagePath("pages/lunar/index.html"); +// button2.setUrl("http://mp.weixin.qq.com"); + + WxMenuButton button3 = new WxMenuButton(); + button3.setName("菜单"); + + menu.getButtons().add(button1); +// menu.getButtons().add(button2); + menu.getButtons().add(button3); + + WxMenuButton button31 = new WxMenuButton(); + button31.setType(MenuButtonType.VIEW); + button31.setName("搜索"); + button31.setUrl("http://www.soso.com/"); + + WxMenuButton button32 = new WxMenuButton(); + button32.setType(MenuButtonType.VIEW); + button32.setName("视频"); + button32.setUrl("http://v.qq.com/"); + + WxMenuButton button33 = new WxMenuButton(); + button33.setType(MenuButtonType.CLICK); + button33.setName("赞一下我们"); + button33.setKey("V1001_GOOD"); + + WxMenuButton button34 = new WxMenuButton(); + button34.setType(MenuButtonType.VIEW); + button34.setName("获取用户信息"); + + ServletRequestAttributes servletRequestAttributes = + (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (servletRequestAttributes != null) { + HttpServletRequest request = servletRequestAttributes.getRequest(); + URL requestURL = new URL(request.getRequestURL().toString()); + String url = wxMpManager.getMpService(appId) + .oauth2buildAuthorizationUrl( + String.format("%s://%s/wx/redirect/%s/greet", requestURL.getProtocol(), requestURL.getHost(), appId), + WxConsts.OAuth2Scope.SNSAPI_USERINFO, null); + button34.setUrl(url); + } + + button3.getSubButtons().add(button31); + button3.getSubButtons().add(button32); + button3.getSubButtons().add(button33); + button3.getSubButtons().add(button34); + + return wxMpManager.getMpService(appId).getMenuService().menuCreate(menu); + } + + /** + *
+     * 自定义菜单创建接口
+     * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141013&token=&lang=zh_CN
+     * 如果要创建个性化菜单,请设置matchrule属性
+     * 详情请见:https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+     * 
+ * + * @param json + * @return 如果是个性化菜单,则返回menuid,否则返回null + */ + @PostMapping("/createByJson") + public String menuCreate(@PathVariable String appId, @RequestBody String json) throws WxErrorException { + return wxMpManager.getMpService(appId).getMenuService().menuCreate(json); + } + + /** + *
+     * 自定义菜单删除接口
+     * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN
+     * 
+ */ + @GetMapping("/delete") + public void menuDelete(@PathVariable String appId) throws WxErrorException { + wxMpManager.getMpService(appId).getMenuService().menuDelete(); + } + + /** + *
+     * 删除个性化菜单接口
+     * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN
+     * 
+ * + * @param menuId 个性化菜单的menuid + */ + @GetMapping("/delete/{menuId}") + public void menuDelete(@PathVariable String appId, @PathVariable String menuId) throws WxErrorException { + wxMpManager.getMpService(appId).getMenuService().menuDelete(menuId); + } + + /** + *
+     * 自定义菜单查询接口
+     * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN
+     * 
+ */ + @GetMapping("/get") + public WxMpMenu menuGet(@PathVariable String appId) throws WxErrorException { + return wxMpManager.getMpService(appId).getMenuService().menuGet(); + } + + /** + *
+     * 测试个性化菜单匹配结果
+     * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html
+     * 
+ * + * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。 + */ + @GetMapping("/menuTryMatch/{userid}") + public WxMenu menuTryMatch(@PathVariable String appId, @PathVariable String userid) throws WxErrorException { + return wxMpManager.getMpService(appId).getMenuService().menuTryMatch(userid); + } + + /** + *
+     * 获取自定义菜单配置接口
+     * 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
+     * 请注意:
+     * 1、第三方平台开发者可以通过本接口,在旗下公众号将业务授权给你后,立即通过本接口检测公众号的自定义菜单配置,并通过接口再次给公众号设置好自动回复规则,以提升公众号运营者的业务体验。
+     * 2、本接口与自定义菜单查询接口的不同之处在于,本接口无论公众号的接口是如何设置的,都能查询到接口,而自定义菜单查询接口则仅能查询到使用API设置的菜单配置。
+     * 3、认证/未认证的服务号/订阅号,以及接口测试号,均拥有该接口权限。
+     * 4、从第三方平台的公众号登录授权机制上来说,该接口从属于消息与菜单权限集。
+     * 5、本接口中返回的图片/语音/视频为临时素材(临时素材每次获取都不同,3天内有效,通过素材管理-获取临时素材接口来获取这些素材),本接口返回的图文消息为永久素材素材(通过素材管理-获取永久素材接口来获取这些素材)。
+     *  接口调用请求说明:
+     * http请求方式: GET(请使用https协议)
+     * https://api.weixin.qq.com/cgi-bin/get_current_selfmenu_info?access_token=ACCESS_TOKEN
+     * 
+ */ + @GetMapping("/getSelfMenuInfo") + public WxMpGetSelfMenuInfoResult getSelfMenuInfo(@PathVariable String appId) throws WxErrorException { + return wxMpManager.getMpService(appId).getMenuService().getSelfMenuInfo(); + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMpCallBackController.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMpCallBackController.java new file mode 100644 index 0000000..698cc09 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMpCallBackController.java @@ -0,0 +1,152 @@ +package com.iformall.mp.controller; + +import com.iformall.mp.manager.WxMpManager; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage; +import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.PrintWriter; +import java.nio.charset.Charset; + +/** + * @author Stormeye + */ +@Controller +@RequestMapping("/wx") +public class WxMpCallBackController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private WxMpManager wxMpManager; + + /** + * GET请求:进行URL、Tocken 认证; + * 1. 将token、timestamp、nonce三个参数进行字典序排序 + * 2. 将三个参数字符串拼接成一个字符串进行sha1加密 + * 3. 开发者获得加密后的字符串可与signature对比,标识该请求来源于微信 + */ + @GetMapping(value = "/{account}/message") + @ResponseBody + public void authGet(@PathVariable String account, HttpServletRequest request, HttpServletResponse response) throws IOException { + String signature = request.getParameter("signature");// 微信加密签名 + String timestamp = request.getParameter("timestamp");// 时间戳 + String nonce = request.getParameter("nonce");// 随机数 + String echostr = request.getParameter("echostr");// 随机字符串 + + if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) { + throw new IllegalArgumentException("请求参数非法,请核实!"); + } + + logger.info("接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", + signature, timestamp, nonce, echostr); + + // 数据库 -> + final WxMpService wxService = wxMpManager.getMpService(account); + if (wxService == null) { + throw new IllegalArgumentException(String.format("未找到对应account=[%s]的配置,请核实!", account)); + } + + if (wxService.checkSignature(timestamp, nonce, signature)) { + logger.info("微信服务验证成功"); + PrintWriter out = response.getWriter(); + out.print(echostr); + out.close(); + } + } + + /** + * POST 请求:进行消息处理; + */ + @PostMapping(value = "/{account}/message") + @ResponseBody + public String post(@PathVariable String account, HttpServletRequest request) throws IOException { + // 处理用户和微信公众账号交互消息 + String signature = request.getParameter("signature");// 微信加密签名 + String timestamp = request.getParameter("timestamp");// 时间戳 + String nonce = request.getParameter("nonce");// 随机数 + String openid = request.getParameter("openid"); + String encType = request.getParameter("encrypt_type"); + String msgSignature = request.getParameter("msg_signature"); + + if (StringUtils.isAnyBlank(signature, timestamp, nonce)) { + throw new IllegalArgumentException("请求参数非法,请核实!"); + } + + final WxMpService wxService = wxMpManager.getMpService(account); + + if (!wxService.checkSignature(timestamp, nonce, signature)) { + throw new IllegalArgumentException("非法请求,可能属于伪造的请求!"); + } + + 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 requestBody = new String(outSteam.toByteArray(), Charset.forName("UTF-8")); + logger.info(requestBody); + + outSteam.close(); + inStream.close(); + + logger.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}]," + + " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ", + openid, signature, encType, msgSignature, timestamp, nonce, requestBody); + + String out = null; + if (encType == null) { + // 明文传输的消息 + WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody); + + WxMpXmlOutMessage outMessage = this.route(inMessage, wxService); + if (outMessage == null) { + logger.info("1 return: success"); + return "success"; + } + + out = outMessage.toXml(); + logger.info(out); + } else if ("aes".equalsIgnoreCase(encType)) { + // aes加密的消息 + WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(), + timestamp, nonce, msgSignature); + this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString()); + WxMpXmlOutMessage outMessage = this.route(inMessage, wxService); + if (outMessage == null) { + logger.info("2 return: success"); + return "success"; + } + logger.info("out: " + outMessage.toXml()); + + out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage()); + } + this.logger.info("\n组装回复信息:{}", out); + return out; + } + + private WxMpXmlOutMessage route(WxMpXmlMessage message, WxMpService wxService) { + String appId = wxService.getWxMpConfigStorage().getAppId(); + logger.info("route appId: " + appId); + try { + return wxMpManager.getRouter(appId).route(message); + } catch (Exception e) { + this.logger.error("路由消息时出现异常!", e); + } + + return null; + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMpTemplateController.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMpTemplateController.java new file mode 100644 index 0000000..a567b95 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxMpTemplateController.java @@ -0,0 +1,70 @@ +package com.iformall.mp.controller; + +import com.google.common.collect.Lists; +import com.iformall.common.ResultData; +import com.iformall.mp.manager.WxMpManager; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; +import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * @author Stormeye + */ +@RestController +@RequestMapping("/wx/{appId}/template") +public class WxMpTemplateController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private WxMpManager wxMpManager; + + @GetMapping("/send") + public ResultData syncAccountFansList(@PathVariable String appId) throws WxErrorException { + final WxMpService wxService = wxMpManager.getMpService(appId); + + // 审核结果通知 SxhGTL6AlcYtbc4nEYxcS4zoGRzTiUr9KEscvpEItQw + // {{first.DATA}} + // 审核状态:{{keyword1.DATA}} + // 活动名称:{{keyword2.DATA}} + // 活动时间:{{keyword3.DATA}} + // 活动地点:{{keyword4.DATA}} + // {{remark.DATA}} + + SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + + String templateId = "SxhGTL6AlcYtbc4nEYxcS4zoGRzTiUr9KEscvpEItQw"; + + WxMpTemplateMessage.MiniProgram miniprogram = new WxMpTemplateMessage.MiniProgram(); + miniprogram.setAppid("wxea71200db93d756b"); + miniprogram.setPagePath("pages/index/index"); + miniprogram.setUsePath(true); + + WxMpTemplateMessage msg = WxMpTemplateMessage.builder() + .toUser("o8iB81ZUK0SOR0ZOp6t9Q1GCMYuM") + .templateId(templateId) + .miniProgram(miniprogram) + .data(Lists.newArrayList( + new WxMpTemplateData("first", "恭喜您,您的小程序\"富茂客官开发\"审核已通过", "#173177"), + new WxMpTemplateData("keyword1", "审核已通过", "#173177"), + new WxMpTemplateData("keyword2", "提交审核已通过", "#173177"), + new WxMpTemplateData("keyword3", dateFormat.format(new Date()), "#173177"), + new WxMpTemplateData("keyword4", "地点", "#173177"), + new WxMpTemplateData("remark", "test", "#173177") + )) + .build(); + String rest = wxService.getTemplateMsgService().sendTemplateMsg(msg); + logger.info(rest); + return new ResultData(); + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxRedirectController.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxRedirectController.java new file mode 100644 index 0000000..8daa55b --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/controller/WxRedirectController.java @@ -0,0 +1,45 @@ +package com.iformall.mp.controller; + +import com.iformall.mp.manager.WxMpManager; +import com.iformall.mp.utils.MpUtil; +import me.chanjar.weixin.common.error.WxErrorException; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.bean.result.WxMpOAuth2AccessToken; +import me.chanjar.weixin.mp.bean.result.WxMpUser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Controller; +import org.springframework.ui.ModelMap; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; + +/** + * @author Stormeye + */ +@Controller +@RequestMapping("/wx/redirect/{appId}") +public class WxRedirectController { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private WxMpManager wxMpManager; + + + @RequestMapping("/greet") + public String greetUser(@PathVariable String appId, @RequestParam String code, ModelMap map) { + + WxMpService mpService = wxMpManager.getMpService(appId); + + try { + WxMpOAuth2AccessToken accessToken = mpService.oauth2getAccessToken(code); + WxMpUser user = mpService.oauth2getUserInfo(accessToken, null); + map.put("user", user); + } catch (WxErrorException e) { + e.printStackTrace(); + } + + return "greet_user"; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/error/ErrorController.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/error/ErrorController.java new file mode 100644 index 0000000..4fd9060 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/error/ErrorController.java @@ -0,0 +1,29 @@ +package com.iformall.mp.error; + +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + *
+ * 出错页面控制器
+ * Created by Binary Wang on 2018/8/25.
+ * 
+ * + * @author Binary Wang + */ +@Controller +@RequestMapping("/error") +public class ErrorController { + + @GetMapping(value = "/404") + public String error404() { + return "error"; + } + + @GetMapping(value = "/500") + public String error500() { + return "error"; + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/error/ErrorPageConfiguration.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/error/ErrorPageConfiguration.java new file mode 100644 index 0000000..3a8807d --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/error/ErrorPageConfiguration.java @@ -0,0 +1,27 @@ +package com.iformall.mp.error; + +import org.springframework.boot.web.server.ErrorPage; +import org.springframework.boot.web.server.ErrorPageRegistrar; +import org.springframework.boot.web.server.ErrorPageRegistry; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + *
+ * 配置错误状态与对应访问路径
+ * Created by Binary Wang on 2018/8/25.
+ * 
+ * + * @author Binary Wang + */ +@Component +public class ErrorPageConfiguration implements ErrorPageRegistrar { + @Override + public void registerErrorPages(ErrorPageRegistry errorPageRegistry) { + errorPageRegistry.addErrorPages( + new ErrorPage(HttpStatus.NOT_FOUND, "/error/404"), + new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500") + ); + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/manager/WxMpManager.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/manager/WxMpManager.java new file mode 100644 index 0000000..7de9728 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/manager/WxMpManager.java @@ -0,0 +1,144 @@ +package com.iformall.mp.manager; + +import com.iformall.service.wechat.FmOpenService; +import com.iformall.service.wechat.handler.*; +import me.chanjar.weixin.mp.api.WxMpMessageRouter; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.constant.WxMpEventConstants; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import static me.chanjar.weixin.common.api.WxConsts.*; + +/** + * wechat mp configuration + * + * @author Stormeye + */ +@Service +public class WxMpManager { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private static Map myRouterMap = new ConcurrentHashMap(); + + + @Autowired + protected FmOpenService openService; + + @Autowired + protected LogHandler logHandler; + @Autowired + protected NullHandler nullHandler; + @Autowired + protected KfSessionHandler kfSessionHandler; + @Autowired + protected StoreCheckNotifyHandler storeCheckNotifyHandler; + @Autowired + protected LocationHandler locationHandler; + @Autowired + protected MenuHandler menuHandler; + @Autowired + protected MsgHandler msgHandler; + @Autowired + protected UnsubscribeHandler unsubscribeHandler; + @Autowired + protected SubscribeHandler subscribeHandler; + + public WxMpService getMpService(String appId) { + return openService.getWxOpenComponentService().getWxMpServiceByAppid(appId); + } + + public WxMpMessageRouter getRouter(String appId) { + if (myRouterMap.containsKey(appId)) { + logger.info("found appId : " + appId); + return myRouterMap.get(appId); + } else { + WxMpService wxMpService = openService.getWxOpenComponentService().getWxMpServiceByAppid(appId); + WxMpMessageRouter newRouter = newRouter(wxMpService); + myRouterMap.put(appId, newRouter); + logger.info("found new appId : " + appId); + return newRouter; + } + } + + private WxMpMessageRouter newRouter(WxMpService wxMpService) { + final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService); + + // 记录所有事件的日志 (异步执行) + newRouter.rule().handler(this.logHandler).next(); + + + // 接收客服会话管理事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_CREATE_SESSION) + .handler(this.kfSessionHandler).end(); + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_CLOSE_SESSION) + .handler(this.kfSessionHandler).end(); + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.CustomerService.KF_SWITCH_SESSION) + .handler(this.kfSessionHandler).end(); + + // 门店审核事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(WxMpEventConstants.POI_CHECK_NOTIFY) + .handler(this.storeCheckNotifyHandler).end(); + + // 自定义菜单事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(MenuButtonType.CLICK) + .handler(this.menuHandler).end(); + + // 点击菜单连接事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(MenuButtonType.VIEW) + .handler(this.nullHandler).end(); + + // 关注事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(EventType.SUBSCRIBE) + .handler(this.subscribeHandler).end(); + + // 取消关注事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(EventType.UNSUBSCRIBE) + .handler(this.unsubscribeHandler).end(); + + // 上报地理位置事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(EventType.LOCATION) + .handler(this.locationHandler).end(); + + // 接收地理位置消息 + newRouter.rule().async(false) + .msgType(XmlMsgType.LOCATION) + .handler(this.locationHandler).end(); + + // 扫码事件 + newRouter.rule().async(false) + .msgType(XmlMsgType.EVENT) + .event(EventType.SCAN) + .handler(this.nullHandler).end(); + + // 默认 + newRouter.rule().async(false).handler(this.msgHandler).end(); + + return newRouter; + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/mp/utils/MpUtil.java b/mlToutiaoOpen/src/main/java/com/iformall/mp/utils/MpUtil.java new file mode 100644 index 0000000..762fa9e --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/mp/utils/MpUtil.java @@ -0,0 +1,22 @@ +package com.iformall.mp.utils; + +import com.iformall.domain.po.WxAppinfo; +import me.chanjar.weixin.mp.api.WxMpService; +import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl; +import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl; + +/** + * @author Stormeye + */ +public class MpUtil { + static public WxMpService getMpService(WxAppinfo appinfo) { + WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl(); + configStorage.setAppId(appinfo.getAppId()); + configStorage.setSecret(appinfo.getSecret()); + configStorage.setToken(appinfo.getToken()); + configStorage.setAesKey(appinfo.getAesKey()); + WxMpService service = new WxMpServiceImpl(); + service.setWxMpConfigStorage(configStorage); + return service; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/schedule/AppAccessTokenSchedule.java b/mlToutiaoOpen/src/main/java/com/iformall/schedule/AppAccessTokenSchedule.java new file mode 100644 index 0000000..eeb51fc --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/schedule/AppAccessTokenSchedule.java @@ -0,0 +1,52 @@ +package com.iformall.schedule; + +import com.iformall.domain.vo.WxWeappInfo; +import com.iformall.mapper.WxAuthorizerInfoMapper; +import com.iformall.service.wechat.FmOpenService; +import me.chanjar.weixin.common.error.WxErrorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.List; + +@Component +public class AppAccessTokenSchedule { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Autowired + private WxAuthorizerInfoMapper authorizerInfoMapper; + + @Autowired + private FmOpenService openService; + + // @Scheduled(cron = "0 40 */1 * * *?") // 每小时更新一次 + //@Scheduled(cron = "*/10 * * * * ?") // 测试10秒中一次 + public void updateAppAccessToken() { + // 暂不启用定时token设置 + /* + // 微信小程序 + List weappList = authorizerInfoMapper.findWeappList(); + weappList.stream().forEach(weappInfo -> { + try { + openService.getWxOpenComponentService().getAuthorizerAccessToken(weappInfo.getAuthorizerAppid(), true); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + }); + + // 微信公众号 + List wxmpList = authorizerInfoMapper.findWxMpList(); + wxmpList.stream().forEach(weappInfo -> { + try { + openService.getWxOpenComponentService().getAuthorizerAccessToken(weappInfo.getAuthorizerAppid(), true); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + }); + */ + + } +} \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/schedule/SchedulingConfig.java b/mlToutiaoOpen/src/main/java/com/iformall/schedule/SchedulingConfig.java new file mode 100644 index 0000000..c347b05 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/schedule/SchedulingConfig.java @@ -0,0 +1,18 @@ +package com.iformall.schedule; + +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.SchedulingConfigurer; +import org.springframework.scheduling.config.ScheduledTaskRegistrar; + +@Configuration +@EnableScheduling +public class SchedulingConfig implements SchedulingConfigurer { + + @Override + public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { + + + } + +} \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/schedule/UserUnionIdSchedule.java b/mlToutiaoOpen/src/main/java/com/iformall/schedule/UserUnionIdSchedule.java new file mode 100644 index 0000000..e2a3401 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/schedule/UserUnionIdSchedule.java @@ -0,0 +1,80 @@ +package com.iformall.schedule; + +import com.iformall.domain.po.WxPayAccount; +import com.iformall.domain.vo.WxPayOrderVo; +import com.iformall.mapper.WxPayAccountMapper; +import com.iformall.mapper.WxPayOrderMapper; +import com.iformall.service.WxAppinfoService; +import com.iformall.service.wechat.FmOpenService; +import me.chanjar.weixin.open.api.WxOpenMaService; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class UserUnionIdSchedule { + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + + private final int TIME_OUT_VALUE = 4 * 60 * 1000; //4分钟 + + @Autowired + WxPayOrderMapper payOrderMapper; + + @Autowired + private FmOpenService openService; + + @Autowired + private WxPayAccountMapper payAccountMapper; + + @Autowired + WxAppinfoService wxAppinfoService; + + //@Scheduled(cron = "0 */4 * * * *?") // 每4分钟检查一次 + //@Scheduled(cron = "*/10 * * * * ?") // 测试10秒中一次 + public void payOrderGetUnionIdSchedule() { + Map dateMap = new HashMap(); + Date curDate = new Date(); + Date expireDate = new Date(curDate.getTime() - TIME_OUT_VALUE ); + + // 券相关订单 + dateMap.put("startDate", expireDate); + List paidList = payOrderMapper.findListOfPaidOrderByDate(dateMap); + paidList.parallelStream().forEach( payOrderVo -> { + getUnionId(payOrderVo); + }); + } + + /** + * 根据payOrder信息获取UnionId + * @param payOrderVo + */ + public void getUnionId(WxPayOrderVo payOrderVo) { + if(StringUtils.isBlank(payOrderVo.getOpenId())) { + return; + } + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(payOrderVo.getAppId()); + if(StringUtils.isNotBlank(payOrderVo.getTransactionId())) { + String openRet = openMaService.getPaidUnionId(payOrderVo.getOpenId(), payOrderVo.getTransactionId(), null, null); + logger.info(openRet); + } else { + WxPayAccount payAccount = payAccountMapper.selectById(payOrderVo.getPayId()); + if(payAccount != null) { + String openRet = openMaService.getPaidUnionId(payOrderVo.getOpenId(), null, payAccount.getMchId(), payOrderVo.getPayOrderNo()); + logger.info(openRet); + } + } + }catch (Exception e) { + logger.error(e.getMessage()); + } + + } +} \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/java/com/iformall/shiro/MyRetryLimitCredentialsMatcher.java b/mlToutiaoOpen/src/main/java/com/iformall/shiro/MyRetryLimitCredentialsMatcher.java new file mode 100644 index 0000000..14630d6 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/shiro/MyRetryLimitCredentialsMatcher.java @@ -0,0 +1,24 @@ +package com.iformall.shiro; + +import com.iformall.enums.EnumLoginType; +import org.apache.shiro.authc.AuthenticationInfo; +import org.apache.shiro.authc.AuthenticationToken; +import org.apache.shiro.authc.credential.HashedCredentialsMatcher; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MyRetryLimitCredentialsMatcher extends HashedCredentialsMatcher { + @Override + public boolean doCredentialsMatch(AuthenticationToken authcToken, AuthenticationInfo info) { + if(authcToken instanceof UseriFormallToken) { + UseriFormallToken tk = (UseriFormallToken) authcToken; + if(tk.getType().equals(EnumLoginType.NOPASSWD)){ + return true; + } + boolean matches = super.doCredentialsMatch(authcToken, info); + return matches; + } + boolean matches =super.doCredentialsMatch(authcToken, info); + return matches; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/shiro/MyShiroRealm.java b/mlToutiaoOpen/src/main/java/com/iformall/shiro/MyShiroRealm.java new file mode 100644 index 0000000..9d6e01b --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/shiro/MyShiroRealm.java @@ -0,0 +1,90 @@ +package com.iformall.shiro; + +import com.iformall.domain.po.MallUserInfo; +import com.iformall.enums.EnumMallUserStatus; +import com.iformall.service.MallPermissionService; +import com.iformall.service.MallUserInfoService; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.authc.*; +import org.apache.shiro.authz.AuthorizationInfo; +import org.apache.shiro.authz.SimpleAuthorizationInfo; +import org.apache.shiro.realm.AuthorizingRealm; +import org.apache.shiro.session.Session; +import org.apache.shiro.subject.PrincipalCollection; +import org.apache.shiro.util.ByteSource; + +import javax.annotation.Resource; + +/** + * Created by yangqj on 2017/4/21. + */ +public class MyShiroRealm extends AuthorizingRealm { + + @Resource + private MallUserInfoService userService; + + @Resource + private MallPermissionService resourcesService; + + //授权 + @Override + protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { + MallUserInfo user= (MallUserInfo) SecurityUtils.getSubject().getPrincipal();//User{id=1, username='admin', password='3ef7164d1f6167cb9f2658c07d3c2f0a', enable=1} +// Map map = new HashMap(); +// map.put("userid",user.getId()); +// List resourcesList = resourcesService.list(map); +// 权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission) + SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); +// for(SysPermission resources: resourcesList){ +// info.addStringPermission(resources.getUrl()); +// } + return info; + } + + //认证 + @Override + protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { + //获取用户的输入的账号. + String username = (String)token.getPrincipal(); + MallUserInfo user = userService.getByUsername(username); + if(user == null) { + throw new UnknownAccountException("用户名不存在"); + } +// if (0==user.getEnable()) { +// throw new LockedAccountException(); // 帐号锁定 +// } + //用户被禁用 + if(user.getStatus()==null || + !EnumMallUserStatus.VALID.getCode().equals(user.getStatus())) { + throw new DisabledAccountException("用户被禁用"); + } + if(!user.getTenantId().equals("1")) { + // 只支持租户为1的用户 + throw new UnknownAccountException("用户名不支持"); + } + SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo( + user, //用户 + user.getPassword(), //密码 + ByteSource.Util.bytes(username), + getName() //realm name + ); + // 当验证都通过后,把用户信息放在session里 + Session session = SecurityUtils.getSubject().getSession(); + session.setAttribute(UserSession.userInfo, user); + session.setAttribute(UserSession.userId, user.getId()); + session.setAttribute(UserSession.tenantId, user.getTenantId()); + return authenticationInfo; + } + + + /** + * 指定principalCollection 清除 + */ + /* public void clearCachedAuthorizationInfo(PrincipalCollection principalCollection) { + + SimplePrincipalCollection principals = new SimplePrincipalCollection( + principalCollection, getName()); + super.clearCachedAuthorizationInfo(principals); + } +*/ +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/shiro/PasswordHelper.java b/mlToutiaoOpen/src/main/java/com/iformall/shiro/PasswordHelper.java new file mode 100644 index 0000000..e3b9dd3 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/shiro/PasswordHelper.java @@ -0,0 +1,32 @@ +package com.iformall.shiro; + + +import com.iformall.domain.po.MallUserInfo; +import org.apache.shiro.crypto.hash.SimpleHash; +import org.apache.shiro.util.ByteSource; + + +public class PasswordHelper { + //private RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator(); + private String algorithmName = "md5"; + private int hashIterations = 2; + + public void encryptPassword(MallUserInfo user) { + //String salt=randomNumberGenerator.nextBytes().toHex(); + String newPassword = new SimpleHash(algorithmName, user.getPassword(), ByteSource.Util.bytes(user.getUsername()), hashIterations).toHex(); + //String newPassword = new SimpleHash(algorithmName, user.getPassword()).toHex(); + user.setPassword(newPassword); + + } + + public static void main(String[] args) { + MallUserInfo user = new MallUserInfo(); + user.setUsername("fmadmin"); + user.setPassword("fm2020open"); + PasswordHelper passwordHelper = new PasswordHelper(); + passwordHelper.encryptPassword(user); + System.out.println(user); + System.out.println(user.getPassword()); + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/shiro/ShiroService.java b/mlToutiaoOpen/src/main/java/com/iformall/shiro/ShiroService.java new file mode 100644 index 0000000..a9621c7 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/shiro/ShiroService.java @@ -0,0 +1,126 @@ +package com.iformall.shiro; + +import com.iformall.service.MallPermissionService; +import org.apache.shiro.spring.web.ShiroFilterFactoryBean; +import org.apache.shiro.web.filter.mgt.DefaultFilterChainManager; +import org.apache.shiro.web.filter.mgt.PathMatchingFilterChainResolver; +import org.apache.shiro.web.servlet.AbstractShiroFilter; +import org.crazycake.shiro.RedisSessionDAO; +import org.springframework.beans.factory.annotation.Autowired; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Created by yangqj on 2017/4/30. + */ +//@Service +public class ShiroService { + @Autowired + private ShiroFilterFactoryBean shiroFilterFactoryBean; + @Autowired + private MallPermissionService resourcesService; + @Autowired + private RedisSessionDAO redisSessionDAO; + /** + * 初始化权限 + */ + public Map loadFilterChainDefinitions() { + // 权限控制map.从数据库获取 + Map filterChainDefinitionMap = new LinkedHashMap(); + filterChainDefinitionMap.put("/logout", "logout"); + filterChainDefinitionMap.put("/css/**","anon"); + filterChainDefinitionMap.put("/js/**","anon"); + filterChainDefinitionMap.put("/img/**","anon"); + filterChainDefinitionMap.put("/user/**","anon"); + filterChainDefinitionMap.put("/font-awesome/**","anon"); +// Map map = new HashMap<>(); +// List resourcesList = resourcesService.list(map); +// for(SysPermission resources:resourcesList){ +// +// if (StringUtil.isNotEmpty(resources.getUrl())) { +// String permission = "perms[" + resources.getUrl()+ "]"; +// filterChainDefinitionMap.put(resources.getUrl(),permission); +// } +// } + filterChainDefinitionMap.put("/**", "authc"); + return filterChainDefinitionMap; + } + + /** + * 重新加载权限 + */ + public void updatePermission() { + + synchronized (shiroFilterFactoryBean) { + + AbstractShiroFilter shiroFilter = null; + try { + shiroFilter = (AbstractShiroFilter) shiroFilterFactoryBean + .getObject(); + } catch (Exception e) { + throw new RuntimeException( + "get ShiroFilter from shiroFilterFactoryBean error!"); + } + + PathMatchingFilterChainResolver filterChainResolver = (PathMatchingFilterChainResolver) shiroFilter + .getFilterChainResolver(); + DefaultFilterChainManager manager = (DefaultFilterChainManager) filterChainResolver + .getFilterChainManager(); + + // 清空老的权限控制 + manager.getFilterChains().clear(); + + shiroFilterFactoryBean.getFilterChainDefinitionMap().clear(); + shiroFilterFactoryBean + .setFilterChainDefinitionMap(loadFilterChainDefinitions()); + // 重新构建生成 + Map chains = shiroFilterFactoryBean + .getFilterChainDefinitionMap(); + for (Map.Entry entry : chains.entrySet()) { + String url = entry.getKey(); + String chainDefinition = entry.getValue().trim() + .replace(" ", ""); + manager.createChain(url, chainDefinition); + } + + System.out.println("更新权限成功!!"); + } + } + + /** + * 根据userId 清除当前session存在的用户的权限缓存 + * @param userIds 已经修改了权限的userId + */ + /* public void clearUserAuthByUserId(List userIds){ + if(null == userIds || userIds.size() == 0) return ; + //获取所有session + Collection sessions = redisSessionDAO.getActiveSessions(); + //定义返回 + List list = new ArrayList(); + for (Session session:sessions){ + //获取session登录信息。 + Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); + if(null != obj && obj instanceof SimplePrincipalCollection){ + //强转 + SimplePrincipalCollection spc = (SimplePrincipalCollection)obj; + //判断用户,匹配用户ID。 + obj = spc.getPrimaryPrincipal(); + if(null != obj && obj instanceof User){ + User user = (User) obj; + System.out.println("user:"+user); + //比较用户ID,符合即加入集合 + if(null != user && userIds.contains(user.getId())){ + list.add(spc); + } + } + } + } + RealmSecurityManager securityManager = + (RealmSecurityManager) SecurityUtils.getSecurityManager(); + MyShiroRealm realm = (MyShiroRealm)securityManager.getRealms().iterator().next(); + for (SimplePrincipalCollection simplePrincipalCollection : list) { + realm.clearCachedAuthorizationInfo(simplePrincipalCollection); + } + }*/ +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/shiro/UserSession.java b/mlToutiaoOpen/src/main/java/com/iformall/shiro/UserSession.java new file mode 100644 index 0000000..02a7aca --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/shiro/UserSession.java @@ -0,0 +1,11 @@ +package com.iformall.shiro; + +public class UserSession { + + public static String userInfo="userSession"; + + public static String userId ="userSessionId"; + + public static String tenantId ="TENANT_ID"; + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/shiro/UseriFormallToken.java b/mlToutiaoOpen/src/main/java/com/iformall/shiro/UseriFormallToken.java new file mode 100644 index 0000000..04f525a --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/shiro/UseriFormallToken.java @@ -0,0 +1,39 @@ +package com.iformall.shiro; + +import com.iformall.enums.EnumLoginType; +import org.apache.shiro.authc.UsernamePasswordToken; + +public class UseriFormallToken extends UsernamePasswordToken { + private static final long serialVersionUID = -2564928913725078138L; + + private EnumLoginType type; + + public UseriFormallToken() { + super(); + } + + public UseriFormallToken(String username, String password, EnumLoginType type, boolean rememberMe, String host) { + super(username, password, rememberMe, host); + this.type = type; + } + + /** 免密登录 */ + public UseriFormallToken(String username) { + super(username, "", false, null); + this.type = EnumLoginType.NOPASSWD; + } + /** 账号密码登录 */ + public UseriFormallToken(String username, String pwd) { + super(username, pwd, false, null); + this.type = EnumLoginType.PASSWORD; + } + + public EnumLoginType getType() { + return type; + } + + + public void setType(EnumLoginType type) { + this.type = type; + } +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/utils/ShiroUtils.java b/mlToutiaoOpen/src/main/java/com/iformall/utils/ShiroUtils.java new file mode 100644 index 0000000..02b66fc --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/utils/ShiroUtils.java @@ -0,0 +1,61 @@ +package com.iformall.utils; + +import com.iformall.common.ErrorCode; +import com.iformall.domain.po.MallUserInfo; +import com.iformall.exception.MallinkException; +import com.iformall.shiro.UserSession; +import org.apache.shiro.SecurityUtils; +import org.apache.shiro.session.Session; +import org.apache.shiro.subject.Subject; + +/** + * Shiro工具类 + * + * @author stormeye.wu + * @email wugq@mippoint.com + * @date 2016年11月12日 上午9:49:19 + */ +public class ShiroUtils { + + public static Session getSession() { + return SecurityUtils.getSubject().getSession(); + } + + public static Subject getSubject() { + return SecurityUtils.getSubject(); + } + + public static MallUserInfo getUserInfo() { + return (MallUserInfo) SecurityUtils.getSubject().getSession().getAttribute(UserSession.userInfo); + } + + public static Long getUserId() { + return getUserInfo().getId(); + } + + public static void setSessionAttribute(Object key, Object value) { + getSession().setAttribute(key, value); + } + + public static Object getSessionAttribute(Object key) { + return getSession().getAttribute(key); + } + + public static boolean isLogin() { + return SecurityUtils.getSubject().getPrincipal() != null; + } + + public static void logout() { + SecurityUtils.getSubject().logout(); + } + + public static String getKaptcha(String key) { + Object kaptcha = getSessionAttribute(key); + if (kaptcha == null) { + throw new MallinkException(ErrorCode.KAPCHA_NOT_VALID); + } + getSession().removeAttribute(key); + return kaptcha.toString(); + } + +} diff --git a/mlToutiaoOpen/src/main/java/com/iformall/utils/UrlCheck.java b/mlToutiaoOpen/src/main/java/com/iformall/utils/UrlCheck.java new file mode 100644 index 0000000..ed36471 --- /dev/null +++ b/mlToutiaoOpen/src/main/java/com/iformall/utils/UrlCheck.java @@ -0,0 +1,15 @@ +package com.iformall.utils; + +/** + * @author gongbiao + */ +public class UrlCheck { + + public static boolean checkUrl(String url) { + return url.contains("awsFileUpload") + || url.contains("awsFilesUpload") + || url.contains("wxMsgCallback") + || url.contains("notify"); + } + +} diff --git a/mlToutiaoOpen/src/main/resources/application-dev.yml b/mlToutiaoOpen/src/main/resources/application-dev.yml new file mode 100644 index 0000000..64725fc --- /dev/null +++ b/mlToutiaoOpen/src/main/resources/application-dev.yml @@ -0,0 +1,125 @@ +spring: + profiles: + 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 + connectionProperties: "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=6000" + #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: 1 + defaultExpiration: 2592000 # 默认生命周期30天 + jedis: + pool: + max-active: 50 + max-idle: 50 + max-wait: -1 + min-idle: 10 + # 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 +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 + audit_emails: xiaochengxufabu@iformall.com + deploy: 1 + upload_dir: /home/test/server/uploads/ + +logging: + level: + tk.mybatis: debug + com.iformall.mapper: debug + me.chanjar.weixin: debug + path: ./logs/o diff --git a/mlToutiaoOpen/src/main/resources/application-prod.yml b/mlToutiaoOpen/src/main/resources/application-prod.yml new file mode 100644 index 0000000..e976a8d --- /dev/null +++ b/mlToutiaoOpen/src/main/resources/application-prod.yml @@ -0,0 +1,110 @@ +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 + connectionProperties: "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=6000" + # 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: 8 + max-idle: 8 + 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: http://formall.oss-accelerate.aliyuncs.com + # EMAIL + mail: + host: smtp.exmail.qq.com + username: sysadministor@iformall.com + password: SWqPekCEmhUYuYCd # 授权密码 + properties: + mail: + smtp: + auth: true + starttls: + enable: true + socketFactory: + port: 465 + class: javax.net.ssl.SSLSocketFactory + +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 + audit_emails: xiaochengxufabu@iformall.com + deploy: 3 + upload_dir: /root/uploads/ + +logging: + level: + tk.mybatis: debug + com.iformall: debug + path: ./logs/o \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/resources/application-test.yml b/mlToutiaoOpen/src/main/resources/application-test.yml new file mode 100644 index 0000000..8d58e69 --- /dev/null +++ b/mlToutiaoOpen/src/main/resources/application-test.yml @@ -0,0 +1,109 @@ +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 + connectionProperties: "druid.stat.mergeSql=true;druid.stat.slowSqlMillis=6000" + # 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: 100 + max-idle: 20 + 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 + virtual-host: / + flyway: + enabled: true + +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 + audit_emails: xiaochengxufabu@iformall.com + deploy: 2 + upload_dir: /home/ec2-user/server/uploads/ + +ueditor: + config: config.json + unified: true + upload-path: ./upload/ + url-prefix: "" + +logging: + level: + tk.mybatis: debug + com.iformall: debug + path: ./logs/admin \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/resources/application.yml b/mlToutiaoOpen/src/main/resources/application.yml new file mode 100644 index 0000000..ccce917 --- /dev/null +++ b/mlToutiaoOpen/src/main/resources/application.yml @@ -0,0 +1,52 @@ +server: + port: 6070 + servlet: + context-path: / + +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 + servlet: + multipart: + max-file-size: 2MB + max-request-size: 2MB + cache: + type: REDIS + cache-names: redis_cache #缓存的名字(可以不指定) + redis: + time-to-live: 60000ms #很重要,缓存的有效时间,以便缓存的过期(单位为毫秒) + +#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 + +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 + +version: @project.version@ \ No newline at end of file diff --git a/mlToutiaoOpen/src/main/resources/logback-spring.xml b/mlToutiaoOpen/src/main/resources/logback-spring.xml new file mode 100644 index 0000000..80e8379 --- /dev/null +++ b/mlToutiaoOpen/src/main/resources/logback-spring.xml @@ -0,0 +1,100 @@ + + + + + + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level] --%mdc{client}%msg%n + + + + + ${logPath}/trace.log + + ${logPath}/daily/trace.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n + + + + + ${logPath}/info.log + + ${logPath}/daily/info.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n + + + INFO + ACCEPT + DENY + + + + + ${logPath}/debug.log + + ${logPath}/daily/debug.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n + + + DEBUG + ACCEPT + DENY + + + + + + ${logPath}/warn.log + + ${logPath}/daily/warn.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n + + + WARN + ACCEPT + DENY + + + + + + + ${logPath}/error.log + + ${logPath}/daily/error.%d{yyyy-MM-dd}.log + 180 + + + [%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n + + + ERROR + ACCEPT + DENY + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mlWechatOpen/src/main/java/com/iformall/controller/WechatWeappSetController.java b/mlWechatOpen/src/main/java/com/iformall/controller/WechatWeappSetController.java index 5df98e3..495c7f8 100644 --- a/mlWechatOpen/src/main/java/com/iformall/controller/WechatWeappSetController.java +++ b/mlWechatOpen/src/main/java/com/iformall/controller/WechatWeappSetController.java @@ -6,14 +6,19 @@ import com.iformall.common.ErrorCode; import com.iformall.common.Result; import com.iformall.common.ResultData; import com.iformall.domain.po.WxAuthorizerInfo; +import com.iformall.domain.po.WxWeappBasicSet; import com.iformall.enums.EnumEnableType; import com.iformall.enums.EnumWxAuthorizationStatus; import com.iformall.service.WxAuthorizerInfoService; +import com.iformall.service.WxWeappBasicSetService; import com.iformall.service.wechat.FmOpenService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import me.chanjar.weixin.common.error.WxErrorException; import me.chanjar.weixin.open.api.WxOpenMaService; +import me.chanjar.weixin.open.bean.ma.privacy.GetPrivacySettingResult; +import me.chanjar.weixin.open.bean.ma.privacy.PrivacyOwnerSetting; +import me.chanjar.weixin.open.bean.ma.privacy.SetPrivacySetting; import me.chanjar.weixin.open.bean.result.*; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; @@ -21,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; +import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; @@ -33,12 +39,19 @@ import java.util.Map; @Api(description = "微信第三方开发平台-小程序设置") public class WechatWeappSetController { private final Logger logger = LoggerFactory.getLogger(getClass()); + + @Autowired + private Integer getFmDeploy; + @Autowired private FmOpenService openService; @Autowired private WxAuthorizerInfoService authorizerInfoService; + @Autowired + private WxWeappBasicSetService weappBasicSetService; + @ApiOperation("获取小程序的信息") @GetMapping("/getInfo") public ResultData getAccountBasicInfo(String appId) { @@ -228,4 +241,67 @@ public class WechatWeappSetController { } return new ResultData(Result.ERROR); } + + + @ApiOperation(value = "配置小程序用户隐私保护指引", notes = "{\n" + + " }") + @PostMapping("/setprivacysetting") + public ResultData setprivacysetting(String appId) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + WxWeappBasicSet weappBasicSetQ = new WxWeappBasicSet(); + weappBasicSetQ.setType(authorizerInfo.getType()); + weappBasicSetQ.setDeploy(getFmDeploy); + WxWeappBasicSet weappBasicSet = weappBasicSetService.getByTypeAndDeploy(weappBasicSetQ); + if(weappBasicSet == null || StringUtils.isBlank(weappBasicSet.getPrivacySetting())) { + logger.error("未找到相关的基础设置参数"); + return new ResultData(ErrorCode.WEAPP_BASIC_SET_ERR); + } + try { + SetPrivacySetting setting = JSON.parseObject(weappBasicSet.getPrivacySetting(),SetPrivacySetting.class); + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + String setRet = openMaService.getPrivacyService().setPrivacySetting(setting); + logger.info(setRet); + JSONObject webRetObj = JSON.parseObject(setRet); + if(webRetObj.getInteger("errcode").equals(0)) { + logger.info("配置小程序用户隐私保护指引成功"); + authorizerInfo.setPrivacySettingStatus(EnumEnableType.SUCC.getCode()); + } else { + logger.info("配置小程序用户隐私保护指引失败"); + authorizerInfo.setPrivacySettingStatus(EnumEnableType.FAIL.getCode()); + } + authorizerInfoService.updatePrivacySetting(authorizerInfo); + return new ResultData(setRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + return new ResultData(Result.ERROR); + } + + @ApiOperation(value = "查询小程序用户隐私保护指引", notes = "{\n" + + " }") + @GetMapping("/getPrivacySetting") + public ResultData setprivacysetting(String appId,Integer privacyVer) { + WxAuthorizerInfo authorizerInfo = authorizerInfoService.getByAppId(appId); + if(authorizerInfo == null) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + if(!authorizerInfo.getAuthorizationStatus().equals(EnumWxAuthorizationStatus.AUTHORIZED.getCode())) { + return new ResultData(ErrorCode.WEAPP_APPID_NOT_AUTH); + } + try { + WxOpenMaService openMaService = openService.getWxOpenComponentService().getWxMaServiceByAppid(appId); + GetPrivacySettingResult getRet = openMaService.getPrivacyService().getPrivacySetting(privacyVer); + return new ResultData(getRet); + } catch (WxErrorException e) { + logger.error(e.getMessage()); + } + return new ResultData(Result.ERROR); + } + } diff --git a/pom.xml b/pom.xml index bf2f729..1452b70 100644 --- a/pom.xml +++ b/pom.xml @@ -12,6 +12,7 @@ mallinkService + mlToutiaoOpen mlWechatOpen