| @@ -54,6 +54,8 @@ public class WxAuthorizerInfo extends BaseEntity { | |||||
| private Integer templateStatus; | private Integer templateStatus; | ||||
| @io.swagger.annotations.ApiModelProperty(value="微信小程序模板设置时间",name="templateTime") | @io.swagger.annotations.ApiModelProperty(value="微信小程序模板设置时间",name="templateTime") | ||||
| private Date templateTime; | private Date templateTime; | ||||
| @io.swagger.annotations.ApiModelProperty(value="微信小程序用户隐私指引,0为已设置,1为设置失败",name="privacySettingStatus") | |||||
| private Integer privacySettingStatus; | |||||
| @io.swagger.annotations.ApiModelProperty(value="小程序每月审核撤回次数",name="auditBackNum") | @io.swagger.annotations.ApiModelProperty(value="小程序每月审核撤回次数",name="auditBackNum") | ||||
| private Integer auditBackNum; | private Integer auditBackNum; | ||||
| @io.swagger.annotations.ApiModelProperty(value="微信小程序审核最后撤回时间",name="auditBackTime") | @io.swagger.annotations.ApiModelProperty(value="微信小程序审核最后撤回时间",name="auditBackTime") | ||||
| @@ -25,6 +25,8 @@ public class WxWeappBasicSet extends BaseEntity { | |||||
| private String version; | private String version; | ||||
| @io.swagger.annotations.ApiModelProperty(value="模板库信息",name="templateInfo") | @io.swagger.annotations.ApiModelProperty(value="模板库信息",name="templateInfo") | ||||
| private String templateInfo; | private String templateInfo; | ||||
| @io.swagger.annotations.ApiModelProperty(value="小程序用户隐私保护指引",name="privacySetting") | |||||
| private String privacySetting; | |||||
| @io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate") | @io.swagger.annotations.ApiModelProperty(value="创建时间",name="createDate") | ||||
| private Date createDate; | private Date createDate; | ||||
| @io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate") | @io.swagger.annotations.ApiModelProperty(value="更新时间",name="updateDate") | ||||
| @@ -84,4 +84,5 @@ public interface WxAuthorizerInfoService { | |||||
| int updateAuthBackInfo(WxAuthorizerInfo record); | int updateAuthBackInfo(WxAuthorizerInfo record); | ||||
| int updatePrivacySetting(WxAuthorizerInfo authorizerInfo); | |||||
| } | } | ||||
| @@ -229,9 +229,16 @@ public class WxAuthorizerInfoServiceImpl implements WxAuthorizerInfoService { | |||||
| } | } | ||||
| return 0; | 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); | |||||
| } | |||||
| } | } | ||||
| @@ -21,6 +21,8 @@ | |||||
| <result column="webdomain_time" jdbcType="TIMESTAMP" property="webdomainTime"/> | <result column="webdomain_time" jdbcType="TIMESTAMP" property="webdomainTime"/> | ||||
| <result column="template_status" jdbcType="INTEGER" property="templateStatus"/> | <result column="template_status" jdbcType="INTEGER" property="templateStatus"/> | ||||
| <result column="template_time" jdbcType="TIMESTAMP" property="templateTime"/> | <result column="template_time" jdbcType="TIMESTAMP" property="templateTime"/> | ||||
| <result column="privacy_setting_status" jdbcType="INTEGER" property="privacySettingStatus"/> | |||||
| <result column="current_version" jdbcType="VARCHAR" property="currentVersion"/> | <result column="current_version" jdbcType="VARCHAR" property="currentVersion"/> | ||||
| <result column="current_desc" jdbcType="VARCHAR" property="currentDesc"/> | <result column="current_desc" jdbcType="VARCHAR" property="currentDesc"/> | ||||
| <result column="release_time" jdbcType="TIMESTAMP" property="releaseTime"/> | <result column="release_time" jdbcType="TIMESTAMP" property="releaseTime"/> | ||||
| @@ -34,6 +36,7 @@ | |||||
| <sql id="allColumns"> | <sql id="allColumns"> | ||||
| `id`,`tenant_id`,`type`,`authorizer_appid`,`head_img`,`alias`,`qrcode_url`,`create_time`,`authorization_status`,`auth_time`, | `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`, | `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`, | `current_version`,`current_desc`,`release_time`, | ||||
| `open_appid`,`bind_open_time`,`refresh_token`, | `open_appid`,`bind_open_time`,`refresh_token`, | ||||
| `access_token`,`access_token_expire` | `access_token`,`access_token_expire` | ||||
| @@ -98,6 +101,9 @@ | |||||
| <if test=" null != templateTime "> | <if test=" null != templateTime "> | ||||
| and `template_time` = #{templateTime} | and `template_time` = #{templateTime} | ||||
| </if> | </if> | ||||
| <if test=" null != privacySettingStatus "> | |||||
| and `privacy_setting_status` = #{privacySettingStatus} | |||||
| </if> | |||||
| <if test=" null != currentVersion "> | <if test=" null != currentVersion "> | ||||
| and `current_version` = #{currentVersion} | and `current_version` = #{currentVersion} | ||||
| </if> | </if> | ||||
| @@ -201,6 +207,8 @@ | |||||
| <result column="webdomain_time" jdbcType="TIMESTAMP" property="webdomainTime"/> | <result column="webdomain_time" jdbcType="TIMESTAMP" property="webdomainTime"/> | ||||
| <result column="template_status" jdbcType="INTEGER" property="templateStatus"/> | <result column="template_status" jdbcType="INTEGER" property="templateStatus"/> | ||||
| <result column="template_time" jdbcType="TIMESTAMP" property="templateTime"/> | <result column="template_time" jdbcType="TIMESTAMP" property="templateTime"/> | ||||
| <result column="privacy_setting_status" jdbcType="INTEGER" property="privacySettingStatus"/> | |||||
| <result column="current_version" jdbcType="VARCHAR" property="currentVersion"/> | <result column="current_version" jdbcType="VARCHAR" property="currentVersion"/> | ||||
| <result column="current_desc" jdbcType="VARCHAR" property="currentDesc"/> | <result column="current_desc" jdbcType="VARCHAR" property="currentDesc"/> | ||||
| <result column="release_time" jdbcType="TIMESTAMP" property="releaseTime"/> | <result column="release_time" jdbcType="TIMESTAMP" property="releaseTime"/> | ||||
| @@ -216,6 +224,7 @@ | |||||
| ai.`domain_status`,ai.`domain_time`, | ai.`domain_status`,ai.`domain_time`, | ||||
| ai.`webdomain_status`,ai.`webdomain_time`, | ai.`webdomain_status`,ai.`webdomain_time`, | ||||
| ai.`template_status`,ai.`template_time`, | ai.`template_status`,ai.`template_time`, | ||||
| ai.`privacy_setting_status`, | |||||
| ai.`current_version` as `current_version`,ai.`current_desc`,ai.`release_time`, | ai.`current_version` as `current_version`,ai.`current_desc`,ai.`release_time`, | ||||
| ai.`open_appid`,ai.`bind_open_time`, | ai.`open_appid`,ai.`bind_open_time`, | ||||
| a.`name` as `name` | a.`name` as `name` | ||||
| @@ -268,6 +277,9 @@ | |||||
| <if test=" null != templateTime "> | <if test=" null != templateTime "> | ||||
| and ai.`template_time` = #{templateTime} | and ai.`template_time` = #{templateTime} | ||||
| </if> | </if> | ||||
| <if test=" null != privacySettingStatus "> | |||||
| and ai.`privacy_setting_status` = #{privacySettingStatus} | |||||
| </if> | |||||
| <if test=" null != currentVersion "> | <if test=" null != currentVersion "> | ||||
| and ai.`current_version` = #{currentVersion} | and ai.`current_version` = #{currentVersion} | ||||
| </if> | </if> | ||||
| @@ -8,12 +8,13 @@ | |||||
| <result column="domain_url" jdbcType="VARCHAR" property="domainUrl"/> | <result column="domain_url" jdbcType="VARCHAR" property="domainUrl"/> | ||||
| <result column="version" jdbcType="VARCHAR" property="version"/> | <result column="version" jdbcType="VARCHAR" property="version"/> | ||||
| <result column="template_info" jdbcType="VARCHAR" property="templateInfo"/> | <result column="template_info" jdbcType="VARCHAR" property="templateInfo"/> | ||||
| <result column="privacy_setting" jdbcType="VARCHAR" property="privacySetting"/> | |||||
| <result column="create_date" jdbcType="TIMESTAMP" property="createDate"/> | <result column="create_date" jdbcType="TIMESTAMP" property="createDate"/> | ||||
| <result column="update_date" jdbcType="TIMESTAMP" property="updateDate"/> | <result column="update_date" jdbcType="TIMESTAMP" property="updateDate"/> | ||||
| </resultMap> | </resultMap> | ||||
| <sql id="allColumns"> | <sql id="allColumns"> | ||||
| `id`,`type`,`domain_url`,`version`,`template_info`,`create_date`,`update_date` | |||||
| `id`,`type`,`domain_url`,`version`,`template_info`,`privacy_setting`,`create_date`,`update_date` | |||||
| </sql> | </sql> | ||||
| <sql id="dynamicWhereConditions"> | <sql id="dynamicWhereConditions"> | ||||
| @@ -0,0 +1 @@ | |||||
| /target/ | |||||
| @@ -0,0 +1,179 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <project xmlns="http://maven.apache.org/POM/4.0.0" | |||||
| xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | |||||
| xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | |||||
| <modelVersion>4.0.0</modelVersion> | |||||
| <parent> | |||||
| <artifactId>mallink</artifactId> | |||||
| <groupId>com.iformall</groupId> | |||||
| <version>1.0</version> | |||||
| </parent> | |||||
| <artifactId>mlToutiaoOpen</artifactId> | |||||
| <properties> | |||||
| </properties> | |||||
| <dependencies> | |||||
| <dependency> | |||||
| <groupId>com.iformall</groupId> | |||||
| <artifactId>mallinkService</artifactId> | |||||
| <version>1.0</version> | |||||
| <exclusions> | |||||
| <exclusion> | |||||
| <groupId>com.fasterxml.jackson.core</groupId> | |||||
| <artifactId>jackson-core</artifactId> | |||||
| </exclusion> | |||||
| </exclusions> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>com.google.zxing</groupId> | |||||
| <artifactId>core</artifactId> | |||||
| <version>3.3.3</version> | |||||
| </dependency> | |||||
| <dependency> | |||||
| <groupId>com.github.axet</groupId> | |||||
| <artifactId>kaptcha</artifactId> | |||||
| <version>0.0.9</version> | |||||
| </dependency> | |||||
| </dependencies> | |||||
| <build> | |||||
| <plugins> | |||||
| <plugin> | |||||
| <groupId>org.springframework.boot</groupId> | |||||
| <artifactId>spring-boot-maven-plugin</artifactId> | |||||
| <configuration> | |||||
| <executable>true</executable> | |||||
| <layout>ZIP</layout> | |||||
| <excludeGroupIds> | |||||
| antlr, | |||||
| cn.afterturn, | |||||
| ch.qos.logback, | |||||
| com.alibaba, | |||||
| com.amazonaws, | |||||
| com.baomidou, | |||||
| com.mchange, | |||||
| com.fasterxml.jackson.core, | |||||
| com.fasterxml.jackson.dataformat, | |||||
| com.fasterxml.jackson.datatype, | |||||
| com.fasterxml.jackson.module, | |||||
| com.fasterxml.uuid, | |||||
| com.fasterxml, | |||||
| com.github.axet, | |||||
| com.github.jsqlparser, | |||||
| com.github.pagehelper, | |||||
| com.github.ulisesbocchio, | |||||
| com.github.virtuald, | |||||
| com.google.code.findbugs, | |||||
| com.google.code.gson, | |||||
| com.google.errorprone, | |||||
| com.google.guava, | |||||
| com.google.protobuf, | |||||
| com.google.zxing, | |||||
| com.jayway.jsonpath, | |||||
| com.jhlabs, | |||||
| com.puppycrawl.tools, | |||||
| com.rabbitmq, | |||||
| com.squareup.okhttp3, | |||||
| com.squareup.okio, | |||||
| com.sun, | |||||
| com.sun.mail, | |||||
| com.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 | |||||
| </excludeGroupIds> | |||||
| </configuration> | |||||
| </plugin> | |||||
| </plugins> | |||||
| </build> | |||||
| </project> | |||||
| @@ -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); | |||||
| } | |||||
| } | |||||
| @@ -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); | |||||
| } | |||||
| }; | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(); | |||||
| redisCacheConfigurationMap.put("user", userCacheConfiguration); | |||||
| //初始化一个RedisCacheWriter | |||||
| RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory); | |||||
| // 设置CacheManager的值序列化方式为JdkSerializationRedisSerializer,但其实RedisCacheConfiguration默认就是使用StringRedisSerializer序列化key,JdkSerializationRedisSerializer序列化value,所以以下注释代码为默认实现 | |||||
| // ClassLoader loader = this.getClass().getClassLoader(); | |||||
| // JdkSerializationRedisSerializer jdkSerializer = new JdkSerializationRedisSerializer(loader); | |||||
| // RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair.fromSerializer(jdkSerializer); | |||||
| // RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair); | |||||
| RedisCacheConfiguration defaultCacheConfig = RedisCacheConfiguration.defaultCacheConfig(); | |||||
| //设置默认超过期时间是30秒 | |||||
| defaultCacheConfig.entryTtl(Duration.ofSeconds(30)); | |||||
| //初始化RedisCacheManager | |||||
| RedisCacheManager cacheManager = new RedisCacheManager(redisCacheWriter, defaultCacheConfig, redisCacheConfigurationMap); | |||||
| return cacheManager; | |||||
| */ | |||||
| RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig(); // 生成一个默认配置,通过config对象即可对缓存进行自定义配置 | |||||
| config = config.entryTtl(Duration.ofMinutes(1)) // 设置缓存的默认过期时间,也是使用Duration设置 | |||||
| .disableCachingNullValues(); // 不缓存空值 | |||||
| // 设置一个初始化的缓存空间set集合 | |||||
| Set<String> cacheNames = new HashSet<>(); | |||||
| cacheNames.add("my-redis-cache1"); | |||||
| cacheNames.add("my-redis-cache2"); | |||||
| // 对每个缓存空间应用不同的配置 | |||||
| Map<String, RedisCacheConfiguration> 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; | |||||
| } | |||||
| } | |||||
| @@ -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() { | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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 | |||||
| * <p> | |||||
| * 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<String, Filter> filters = new LinkedHashMap<String, Filter>(); | |||||
| 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<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); | |||||
| //配置退出 过滤器,其中的具体的退出代码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"); | |||||
| //<!-- 过滤链定义,从上向下顺序执行,一般将 /**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; | |||||
| //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> | |||||
| //自定义加载权限资源关系 | |||||
| // Map<String,Object> map = new HashMap<>(); | |||||
| // List<SysPermission> 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"); | |||||
| // //<!-- 记住我cookie生效时间30天 ,单位秒;--> | |||||
| // 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; | |||||
| // } | |||||
| } | |||||
| @@ -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()) ) ; | |||||
| } | |||||
| } | |||||
| @@ -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<HttpMessageConverter<?>> converters) { | |||||
| MappingJackson2HttpMessageConverter jackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter(); | |||||
| //ObjectMapper 是Jackson库的主要类。它提供一些功能将转换成Java对象匹配JSON结构,反之亦然 | |||||
| ObjectMapper objectMapper = new ObjectMapper(); | |||||
| SimpleModule simpleModule = new SimpleModule(); | |||||
| //不显示为null的字段 | |||||
| objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); | |||||
| DeserializationConfig dc = objectMapper.getDeserializationConfig(); | |||||
| // 设置反序列化日期格式、忽略不存在get、set的属性 | |||||
| objectMapper.setConfig( | |||||
| dc.with(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")) | |||||
| .without(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) | |||||
| ); | |||||
| //序列化将Long转String类型 | |||||
| simpleModule.addSerializer(Long.class, ToStringSerializer.instance); | |||||
| simpleModule.addSerializer(Long.TYPE, ToStringSerializer.instance); | |||||
| SimpleModule bigIntegerModule = new SimpleModule(); | |||||
| //序列化将BigInteger转String类型 | |||||
| bigIntegerModule.addSerializer(BigInteger.class, ToStringSerializer.instance); | |||||
| SimpleModule bigDecimalModule = new SimpleModule(); | |||||
| //序列化将BigDecimal转String类型 | |||||
| bigDecimalModule.addSerializer(BigDecimal.class, ToStringSerializer.instance); | |||||
| objectMapper.registerModule(simpleModule); | |||||
| objectMapper.registerModule(bigDecimalModule); | |||||
| objectMapper.registerModule(bigIntegerModule); | |||||
| jackson2HttpMessageConverter.setObjectMapper(objectMapper); | |||||
| converters.add(jackson2HttpMessageConverter); | |||||
| } | |||||
| @Bean | |||||
| public FilterRegistrationBean<HttpServletRequestWrapperFilter> Filters() { | |||||
| FilterRegistrationBean<HttpServletRequestWrapperFilter> registrationBean = new FilterRegistrationBean<HttpServletRequestWrapperFilter>(); | |||||
| registrationBean.setFilter(new HttpServletRequestWrapperFilter()); | |||||
| registrationBean.addUrlPatterns("/*"); | |||||
| registrationBean.setName("koalaSignFilter"); | |||||
| return registrationBean; | |||||
| } | |||||
| } | |||||
| @@ -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); | |||||
| } | |||||
| } | |||||
| @@ -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 "<html>" + | |||||
| "<body>" + | |||||
| "<a href='/O/wt_auth/goto_auth_url'>go</a>" + | |||||
| "</body>" + | |||||
| "</html>"; | |||||
| } | |||||
| @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); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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<String, String> 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()); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| @@ -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<WxMaOpenCommitExtInfo>() {}.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<String, String> 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<WxWeappCodeStatusVo> codeStatusList = weappCodeStatusService.getList(codeQ); | |||||
| if(codeStatusList.size() == 1) { | |||||
| WxWeappCodeStatusVo codeStatus = codeStatusList.get(0); | |||||
| WxOpenMaSubmitAuditMessage subMessage = gson.fromJson(extSet.getReleaseJson(), new TypeToken<WxOpenMaSubmitAuditMessage>() {}.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<WxWeappCodeStatusVo> codeStatusList = weappCodeStatusService.getList(codeQ); | |||||
| if(codeStatusList.size() == 1) { | |||||
| WxWeappCodeStatusVo codeStatus = codeStatusList.get(0); | |||||
| WxOpenMaSubmitAuditMessage subMessage = gson.fromJson(extSet.getReleaseJson(), new TypeToken<WxOpenMaSubmitAuditMessage>() {}.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, "没有审核记录,不能撤回"); | |||||
| } | |||||
| } | |||||
| @@ -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<WxOpenMaCodeTemplate> 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<WxOpenMaCodeTemplate> 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()); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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<Integer> 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<String, String> 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()); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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<String> requestDomain, List<String> wsrequestdomain, | |||||
| List<String> uploaddomain, List<String> 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<String> 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<String, String> 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<String, String> 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); | |||||
| } | |||||
| } | |||||
| @@ -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<WxWeappBasicSet> 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(); | |||||
| } | |||||
| } | |||||
| @@ -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<WxWeappExtSet> 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<WxWeappExtSet> 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(); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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() { | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,125 @@ | |||||
| package com.iformall.interceptor; | |||||
| import org.slf4j.Logger; | |||||
| import org.slf4j.LoggerFactory; | |||||
| import org.springframework.util.StringUtils; | |||||
| import javax.servlet.http.HttpServletRequest; | |||||
| import javax.servlet.http.HttpServletRequestWrapper; | |||||
| import java.util.HashMap; | |||||
| import java.util.HashSet; | |||||
| import java.util.Map; | |||||
| import java.util.Set; | |||||
| /** | |||||
| * 防止sql注入,xss攻击 | |||||
| * 前端可以对输入信息做预处理,后端也可以做处理。 | |||||
| */ | |||||
| public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper { | |||||
| private final Logger log = LoggerFactory.getLogger(getClass()); | |||||
| private static String key = "and|exec|insert|select|delete|update|count|*|%|chr|mid|master|truncate|char|declare|;|or|-|+"; | |||||
| private static Set<String> notAllowedKeyWords = new HashSet<String>(0); | |||||
| private static String replacedString="INVALID"; | |||||
| static { | |||||
| String keyStr[] = key.split("\\|"); | |||||
| for (String str : keyStr) { | |||||
| notAllowedKeyWords.add(str); | |||||
| } | |||||
| } | |||||
| private String currentUrl; | |||||
| public XssHttpServletRequestWrapper(HttpServletRequest servletRequest) { | |||||
| super(servletRequest); | |||||
| currentUrl = servletRequest.getRequestURI(); | |||||
| } | |||||
| /**覆盖getParameter方法,将参数名和参数值都做xss过滤。 | |||||
| * 如果需要获得原始的值,则通过super.getParameterValues(name)来获取 | |||||
| * getParameterNames,getParameterValues和getParameterMap也可能需要覆盖 | |||||
| */ | |||||
| @Override | |||||
| public String getParameter(String parameter) { | |||||
| String value = super.getParameter(parameter); | |||||
| if (value == null) { | |||||
| return null; | |||||
| } | |||||
| return cleanXSS(value); | |||||
| } | |||||
| @Override | |||||
| public String[] getParameterValues(String parameter) { | |||||
| String[] values = super.getParameterValues(parameter); | |||||
| if (values == null) { | |||||
| return null; | |||||
| } | |||||
| int count = values.length; | |||||
| String[] encodedValues = new String[count]; | |||||
| for (int i = 0; i < count; i++) { | |||||
| encodedValues[i] = cleanXSS(values[i]); | |||||
| } | |||||
| return encodedValues; | |||||
| } | |||||
| @Override | |||||
| public Map<String, String[]> getParameterMap(){ | |||||
| Map<String, String[]> values=super.getParameterMap(); | |||||
| if (values == null) { | |||||
| return null; | |||||
| } | |||||
| Map<String, String[]> result=new HashMap<>(); | |||||
| for(String key:values.keySet()){ | |||||
| String encodedKey=cleanXSS(key); | |||||
| int count=values.get(key).length; | |||||
| String[] encodedValues = new String[count]; | |||||
| for (int i = 0; i < count; i++){ | |||||
| encodedValues[i]=cleanXSS(values.get(key)[i]); | |||||
| } | |||||
| result.put(encodedKey,encodedValues); | |||||
| } | |||||
| return result; | |||||
| } | |||||
| /** | |||||
| * 覆盖getHeader方法,将参数名和参数值都做xss过滤。 | |||||
| * 如果需要获得原始的值,则通过super.getHeaders(name)来获取 | |||||
| * getHeaderNames 也可能需要覆盖 | |||||
| */ | |||||
| @Override | |||||
| public String getHeader(String name) { | |||||
| if(name.equalsIgnoreCase("user-agent")) { | |||||
| return super.getHeader(name); | |||||
| } | |||||
| String value = super.getHeader(name); | |||||
| if (value == null) { | |||||
| return null; | |||||
| } | |||||
| return cleanXSS(value); | |||||
| } | |||||
| private String cleanXSS(String valueP) { | |||||
| // You'll need to remove the spaces from the html entities below | |||||
| String value = valueP.replaceAll("<", "<").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; | |||||
| } | |||||
| } | |||||
| @@ -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); | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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<String> 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<String> openIds, WxAuthorizerInfo authorizerInfo) { | |||||
| if(openIds.size() <= 0) { | |||||
| return; | |||||
| } | |||||
| List<WxMpUser> 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()); | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| /** | |||||
| * <pre> | |||||
| * 自定义菜单创建接口 | |||||
| * 详情请见: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 | |||||
| * </pre> | |||||
| * | |||||
| * @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); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 自定义菜单创建接口 | |||||
| * 详情请见: 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 | |||||
| * </pre> | |||||
| * | |||||
| * @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); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 自定义菜单删除接口 | |||||
| * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141015&token=&lang=zh_CN | |||||
| * </pre> | |||||
| */ | |||||
| @GetMapping("/delete") | |||||
| public void menuDelete(@PathVariable String appId) throws WxErrorException { | |||||
| wxMpManager.getMpService(appId).getMenuService().menuDelete(); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 删除个性化菜单接口 | |||||
| * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1455782296&token=&lang=zh_CN | |||||
| * </pre> | |||||
| * | |||||
| * @param menuId 个性化菜单的menuid | |||||
| */ | |||||
| @GetMapping("/delete/{menuId}") | |||||
| public void menuDelete(@PathVariable String appId, @PathVariable String menuId) throws WxErrorException { | |||||
| wxMpManager.getMpService(appId).getMenuService().menuDelete(menuId); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 自定义菜单查询接口 | |||||
| * 详情请见: https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141014&token=&lang=zh_CN | |||||
| * </pre> | |||||
| */ | |||||
| @GetMapping("/get") | |||||
| public WxMpMenu menuGet(@PathVariable String appId) throws WxErrorException { | |||||
| return wxMpManager.getMpService(appId).getMenuService().menuGet(); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 测试个性化菜单匹配结果 | |||||
| * 详情请见: http://mp.weixin.qq.com/wiki/0/c48ccd12b69ae023159b4bfaa7c39c20.html | |||||
| * </pre> | |||||
| * | |||||
| * @param userid 可以是粉丝的OpenID,也可以是粉丝的微信号。 | |||||
| */ | |||||
| @GetMapping("/menuTryMatch/{userid}") | |||||
| public WxMenu menuTryMatch(@PathVariable String appId, @PathVariable String userid) throws WxErrorException { | |||||
| return wxMpManager.getMpService(appId).getMenuService().menuTryMatch(userid); | |||||
| } | |||||
| /** | |||||
| * <pre> | |||||
| * 获取自定义菜单配置接口 | |||||
| * 本接口将会提供公众号当前使用的自定义菜单的配置,如果公众号是通过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 | |||||
| * </pre> | |||||
| */ | |||||
| @GetMapping("/getSelfMenuInfo") | |||||
| public WxMpGetSelfMenuInfoResult getSelfMenuInfo(@PathVariable String appId) throws WxErrorException { | |||||
| return wxMpManager.getMpService(appId).getMenuService().getSelfMenuInfo(); | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| @@ -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"; | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| /** | |||||
| * <pre> | |||||
| * 出错页面控制器 | |||||
| * Created by Binary Wang on 2018/8/25. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| @Controller | |||||
| @RequestMapping("/error") | |||||
| public class ErrorController { | |||||
| @GetMapping(value = "/404") | |||||
| public String error404() { | |||||
| return "error"; | |||||
| } | |||||
| @GetMapping(value = "/500") | |||||
| public String error500() { | |||||
| return "error"; | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| /** | |||||
| * <pre> | |||||
| * 配置错误状态与对应访问路径 | |||||
| * Created by Binary Wang on 2018/8/25. | |||||
| * </pre> | |||||
| * | |||||
| * @author <a href="https://github.com/binarywang">Binary Wang</a> | |||||
| */ | |||||
| @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") | |||||
| ); | |||||
| } | |||||
| } | |||||
| @@ -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<String, WxMpMessageRouter> myRouterMap = new ConcurrentHashMap<String, WxMpMessageRouter>(); | |||||
| @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; | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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<WxWeappInfo> weappList = authorizerInfoMapper.findWeappList(); | |||||
| weappList.stream().forEach(weappInfo -> { | |||||
| try { | |||||
| openService.getWxOpenComponentService().getAuthorizerAccessToken(weappInfo.getAuthorizerAppid(), true); | |||||
| } catch (WxErrorException e) { | |||||
| logger.error(e.getMessage()); | |||||
| } | |||||
| }); | |||||
| // 微信公众号 | |||||
| List<WxWeappInfo> wxmpList = authorizerInfoMapper.findWxMpList(); | |||||
| wxmpList.stream().forEach(weappInfo -> { | |||||
| try { | |||||
| openService.getWxOpenComponentService().getAuthorizerAccessToken(weappInfo.getAuthorizerAppid(), true); | |||||
| } catch (WxErrorException e) { | |||||
| logger.error(e.getMessage()); | |||||
| } | |||||
| }); | |||||
| */ | |||||
| } | |||||
| } | |||||
| @@ -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) { | |||||
| } | |||||
| } | |||||
| @@ -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<WxPayOrderVo> 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()); | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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<String,Object> map = new HashMap<String,Object>(); | |||||
| // map.put("userid",user.getId()); | |||||
| // List<SysPermission> 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); | |||||
| } | |||||
| */ | |||||
| } | |||||
| @@ -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()); | |||||
| } | |||||
| } | |||||
| @@ -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<String, String> loadFilterChainDefinitions() { | |||||
| // 权限控制map.从数据库获取 | |||||
| Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>(); | |||||
| 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<String,Object> map = new HashMap<>(); | |||||
| // List<SysPermission> 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<String, String> chains = shiroFilterFactoryBean | |||||
| .getFilterChainDefinitionMap(); | |||||
| for (Map.Entry<String, String> 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<Integer> userIds){ | |||||
| if(null == userIds || userIds.size() == 0) return ; | |||||
| //获取所有session | |||||
| Collection<Session> sessions = redisSessionDAO.getActiveSessions(); | |||||
| //定义返回 | |||||
| List<SimplePrincipalCollection> list = new ArrayList<SimplePrincipalCollection>(); | |||||
| 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); | |||||
| } | |||||
| }*/ | |||||
| } | |||||
| @@ -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"; | |||||
| } | |||||
| @@ -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; | |||||
| } | |||||
| } | |||||
| @@ -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(); | |||||
| } | |||||
| } | |||||
| @@ -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"); | |||||
| } | |||||
| } | |||||
| @@ -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 | |||||
| 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 | |||||
| @@ -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 | |||||
| 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 | |||||
| @@ -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 | |||||
| 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 | |||||
| @@ -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@ | |||||
| @@ -0,0 +1,100 @@ | |||||
| <?xml version="1.0" encoding="UTF-8"?> | |||||
| <configuration scan="true" scanPeriod="10 seconds"> | |||||
| <!-- 外部指定路径 --> | |||||
| <springProperty scop="context" name="logPath" source="logging.path" /> | |||||
| <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> | |||||
| <encoder> | |||||
| <Pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level] --%mdc{client}%msg%n</Pattern> | |||||
| </encoder> | |||||
| </appender> | |||||
| <appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||||
| <file>${logPath}/trace.log</file> | |||||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||||
| <FileNamePattern>${logPath}/daily/trace.%d{yyyy-MM-dd}.log</FileNamePattern> | |||||
| <maxHistory>180</maxHistory> <!-- 保留180天 --> | |||||
| </rollingPolicy> | |||||
| <layout> | |||||
| <pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n</pattern> | |||||
| </layout> | |||||
| </appender> | |||||
| <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||||
| <file>${logPath}/info.log</file> | |||||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||||
| <FileNamePattern>${logPath}/daily/info.%d{yyyy-MM-dd}.log</FileNamePattern> | |||||
| <maxHistory>180</maxHistory> <!-- 保留180天 --> | |||||
| </rollingPolicy> | |||||
| <layout> | |||||
| <pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n</pattern> | |||||
| </layout> | |||||
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |||||
| <level>INFO</level> | |||||
| <onMatch>ACCEPT</onMatch> | |||||
| <onMismatch>DENY</onMismatch> | |||||
| </filter> | |||||
| </appender> | |||||
| <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||||
| <file>${logPath}/debug.log</file> | |||||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||||
| <FileNamePattern>${logPath}/daily/debug.%d{yyyy-MM-dd}.log</FileNamePattern> | |||||
| <maxHistory>180</maxHistory> <!-- 保留180天 --> | |||||
| </rollingPolicy> | |||||
| <layout> | |||||
| <pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n</pattern> | |||||
| </layout> | |||||
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |||||
| <level>DEBUG</level> | |||||
| <onMatch>ACCEPT</onMatch> | |||||
| <onMismatch>DENY</onMismatch> | |||||
| </filter> | |||||
| </appender> | |||||
| <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||||
| <file>${logPath}/warn.log</file> | |||||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||||
| <FileNamePattern>${logPath}/daily/warn.%d{yyyy-MM-dd}.log</FileNamePattern> | |||||
| <maxHistory>180</maxHistory> <!-- 保留180天 --> | |||||
| </rollingPolicy> | |||||
| <layout> | |||||
| <pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n</pattern> | |||||
| </layout> | |||||
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |||||
| <level>WARN</level> | |||||
| <onMatch>ACCEPT</onMatch> | |||||
| <onMismatch>DENY</onMismatch> | |||||
| </filter> | |||||
| </appender> | |||||
| <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> | |||||
| <file>${logPath}/error.log</file> | |||||
| <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> | |||||
| <FileNamePattern>${logPath}/daily/error.%d{yyyy-MM-dd}.log</FileNamePattern> | |||||
| <maxHistory>180</maxHistory> <!-- 保留180天 --> | |||||
| </rollingPolicy> | |||||
| <layout> | |||||
| <pattern>[%date{yyyy-MM-dd HH:mm:ss.SSS}][%thread][%-5level][%logger:%line]--%mdc{client} %msg%n</pattern> | |||||
| </layout> | |||||
| <filter class="ch.qos.logback.classic.filter.LevelFilter"> | |||||
| <level>ERROR</level> | |||||
| <onMatch>ACCEPT</onMatch> | |||||
| <onMismatch>DENY</onMismatch> | |||||
| </filter> | |||||
| </appender> | |||||
| <root level="TRACE"> | |||||
| <appender-ref ref="TRACE_FILE" /> | |||||
| <appender-ref ref="INFO_FILE" /> | |||||
| <!-- <appender-ref ref="DEBUG_FILE" /> --> | |||||
| <!-- <appender-ref ref="WARN_FILE" /> --> | |||||
| <appender-ref ref="ERROR_FILE" /> | |||||
| </root> | |||||
| <root level="INFO"> | |||||
| <appender-ref ref="STDOUT" /> | |||||
| </root> | |||||
| </configuration> | |||||
| @@ -6,14 +6,19 @@ import com.iformall.common.ErrorCode; | |||||
| import com.iformall.common.Result; | import com.iformall.common.Result; | ||||
| import com.iformall.common.ResultData; | import com.iformall.common.ResultData; | ||||
| import com.iformall.domain.po.WxAuthorizerInfo; | import com.iformall.domain.po.WxAuthorizerInfo; | ||||
| import com.iformall.domain.po.WxWeappBasicSet; | |||||
| import com.iformall.enums.EnumEnableType; | import com.iformall.enums.EnumEnableType; | ||||
| import com.iformall.enums.EnumWxAuthorizationStatus; | import com.iformall.enums.EnumWxAuthorizationStatus; | ||||
| import com.iformall.service.WxAuthorizerInfoService; | import com.iformall.service.WxAuthorizerInfoService; | ||||
| import com.iformall.service.WxWeappBasicSetService; | |||||
| import com.iformall.service.wechat.FmOpenService; | import com.iformall.service.wechat.FmOpenService; | ||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||
| import me.chanjar.weixin.common.error.WxErrorException; | import me.chanjar.weixin.common.error.WxErrorException; | ||||
| import me.chanjar.weixin.open.api.WxOpenMaService; | 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 me.chanjar.weixin.open.bean.result.*; | ||||
| import org.apache.commons.lang3.StringUtils; | import org.apache.commons.lang3.StringUtils; | ||||
| import org.slf4j.Logger; | import org.slf4j.Logger; | ||||
| @@ -21,6 +26,7 @@ import org.slf4j.LoggerFactory; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.web.bind.annotation.*; | import org.springframework.web.bind.annotation.*; | ||||
| import java.util.ArrayList; | |||||
| import java.util.Date; | import java.util.Date; | ||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.Map; | import java.util.Map; | ||||
| @@ -33,12 +39,19 @@ import java.util.Map; | |||||
| @Api(description = "微信第三方开发平台-小程序设置") | @Api(description = "微信第三方开发平台-小程序设置") | ||||
| public class WechatWeappSetController { | public class WechatWeappSetController { | ||||
| private final Logger logger = LoggerFactory.getLogger(getClass()); | private final Logger logger = LoggerFactory.getLogger(getClass()); | ||||
| @Autowired | |||||
| private Integer getFmDeploy; | |||||
| @Autowired | @Autowired | ||||
| private FmOpenService openService; | private FmOpenService openService; | ||||
| @Autowired | @Autowired | ||||
| private WxAuthorizerInfoService authorizerInfoService; | private WxAuthorizerInfoService authorizerInfoService; | ||||
| @Autowired | |||||
| private WxWeappBasicSetService weappBasicSetService; | |||||
| @ApiOperation("获取小程序的信息") | @ApiOperation("获取小程序的信息") | ||||
| @GetMapping("/getInfo") | @GetMapping("/getInfo") | ||||
| public ResultData getAccountBasicInfo(String appId) { | public ResultData getAccountBasicInfo(String appId) { | ||||
| @@ -228,4 +241,67 @@ public class WechatWeappSetController { | |||||
| } | } | ||||
| return new ResultData(Result.ERROR); | 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); | |||||
| } | |||||
| } | } | ||||
| @@ -12,6 +12,7 @@ | |||||
| <modules> | <modules> | ||||
| <module>mallinkService</module> | <module>mallinkService</module> | ||||
| <module>mlToutiaoOpen</module> | |||||
| <module>mlWechatOpen</module> | <module>mlWechatOpen</module> | ||||
| </modules> | </modules> | ||||