Merge branch 'format' into format
This commit is contained in:
commit
3d9f20a3e3
93
pom.xml
93
pom.xml
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.3.5.RELEASE</version>
|
||||
<version>2.7.2</version>
|
||||
<relativePath/> <!-- lookup parent from repository -->
|
||||
</parent>
|
||||
<groupId>com.rymcu</groupId>
|
||||
@ -17,7 +17,7 @@
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<lucene.version>8.11.1</lucene.version>
|
||||
<lucene.version>8.11.2</lucene.version>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
@ -40,6 +40,7 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.mybatis.spring.boot</groupId>
|
||||
<artifactId>mybatis-spring-boot-starter</artifactId>
|
||||
@ -49,6 +50,7 @@
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<version>8.0.30</version>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
@ -74,8 +76,19 @@
|
||||
<groupId>com.vaadin.external.google</groupId>
|
||||
<artifactId>android-json</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>net.minidev</groupId>
|
||||
<artifactId>json-smart</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!-- https://mvnrepository.com/artifact/net.minidev/json-smart -->
|
||||
<dependency>
|
||||
<groupId>net.minidev</groupId>
|
||||
<artifactId>json-smart</artifactId>
|
||||
<version>2.4.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
@ -84,7 +97,7 @@
|
||||
<dependency>
|
||||
<groupId>tk.mybatis</groupId>
|
||||
<artifactId>mapper</artifactId>
|
||||
<version>4.1.5</version>
|
||||
<version>4.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.jtds</groupId>
|
||||
@ -95,32 +108,31 @@
|
||||
<dependency>
|
||||
<groupId>com.github.pagehelper</groupId>
|
||||
<artifactId>pagehelper</artifactId>
|
||||
<version>5.3.0</version>
|
||||
<version>5.3.1</version>
|
||||
</dependency>
|
||||
<!-- fastjson -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.83</version>
|
||||
<version>2.0.12</version>
|
||||
</dependency>
|
||||
<!-- shiro权限控制框架 -->
|
||||
<dependency>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-spring</artifactId>
|
||||
<version>1.7.1</version>
|
||||
</dependency>
|
||||
<!-- shiro-redis -->
|
||||
<dependency>
|
||||
<groupId>org.crazycake</groupId>
|
||||
<artifactId>shiro-redis</artifactId>
|
||||
<version>3.2.3</version>
|
||||
<version>1.9.1</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.shiro</groupId>
|
||||
<artifactId>shiro-core</artifactId>
|
||||
<groupId>commons-collections</groupId>
|
||||
<artifactId>commons-collections</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
<version>4.4</version>
|
||||
</dependency>
|
||||
<!--apache相关依赖-->
|
||||
<dependency>
|
||||
<groupId>commons-lang</groupId>
|
||||
@ -151,7 +163,7 @@
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.2.8</version>
|
||||
<version>1.2.11</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
@ -163,7 +175,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-to-slf4j</artifactId>
|
||||
<version>2.17.1</version>
|
||||
<version>2.18.0</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
@ -174,7 +186,7 @@
|
||||
<dependency>
|
||||
<groupId>org.apache.logging.log4j</groupId>
|
||||
<artifactId>log4j-api</artifactId>
|
||||
<version>2.17.1</version>
|
||||
<version>2.18.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
@ -185,11 +197,6 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sourceforge.nekohtml</groupId>
|
||||
<artifactId>nekohtml</artifactId>
|
||||
<version>1.9.22</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-websocket</artifactId>
|
||||
@ -197,26 +204,7 @@
|
||||
<dependency>
|
||||
<groupId>org.jodd</groupId>
|
||||
<artifactId>jodd-http</artifactId>
|
||||
<version>6.2.1</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.github.binarywang</groupId>
|
||||
<artifactId>weixin-java-open</artifactId>
|
||||
<version>4.2.5.B</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>commons-codec</groupId>
|
||||
<artifactId>commons-codec</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>commons-io</groupId>
|
||||
<artifactId>commons-io</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
<artifactId>xstream</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
<version>6.3.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.thoughtworks.xstream</groupId>
|
||||
@ -228,21 +216,6 @@
|
||||
<artifactId>jedis-lock</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.baidu.aip</groupId>
|
||||
<artifactId>java-sdk</artifactId>
|
||||
<version>4.16.5</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.slf4j</groupId>
|
||||
<artifactId>slf4j-simple</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<!-- lucene -->
|
||||
<dependency>
|
||||
@ -273,12 +246,12 @@
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-core</artifactId>
|
||||
<version>5.7.20</version>
|
||||
<version>5.8.5</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>cn.hutool</groupId>
|
||||
<artifactId>hutool-http</artifactId>
|
||||
<version>5.7.20</version>
|
||||
<version>5.8.5</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@ -292,8 +265,6 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
@ -3,14 +3,12 @@ package com.rymcu.forest.config;
|
||||
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
|
||||
import org.apache.shiro.mgt.SecurityManager;
|
||||
import org.apache.shiro.session.mgt.SessionManager;
|
||||
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
|
||||
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.filter.authc.FormAuthenticationFilter;
|
||||
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
|
||||
import org.crazycake.shiro.RedisCacheManager;
|
||||
import org.crazycake.shiro.RedisManager;
|
||||
import org.crazycake.shiro.RedisSessionDAO;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.EnvironmentAware;
|
||||
@ -116,62 +114,12 @@ public class ShiroConfig implements EnvironmentAware {
|
||||
@Bean
|
||||
public SessionManager sessionManager() {
|
||||
BaseSessionManager sessionManager = new BaseSessionManager();
|
||||
sessionManager.setSessionDAO(redisSessionDAO());
|
||||
sessionManager.setSessionDAO(new MemorySessionDAO());
|
||||
sessionManager.setSessionIdUrlRewritingEnabled(false);
|
||||
sessionManager.setGlobalSessionTimeout(21600000L);
|
||||
return sessionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置shiro redisManager
|
||||
* <p>
|
||||
* 使用的是shiro-redis开源插件
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
|
||||
public RedisManager redisManager() {
|
||||
StringBuffer host = new StringBuffer(env.getProperty("spring.redis.host"));
|
||||
host.append(":").append(env.getProperty("spring.redis.port"));
|
||||
// 设置redis配置信息
|
||||
RedisManager redisManager = new RedisManager();
|
||||
redisManager.setHost(host.toString());
|
||||
redisManager.setPassword(env.getProperty("spring.redis.password"));
|
||||
return redisManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* cacheManager 缓存 redis实现
|
||||
* <p>
|
||||
* 使用的是shiro-redis开源插件
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
|
||||
|
||||
@Bean
|
||||
public RedisCacheManager cacheManager() {
|
||||
RedisCacheManager redisCacheManager = new RedisCacheManager();
|
||||
redisCacheManager.setRedisManager(redisManager());
|
||||
return redisCacheManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* RedisSessionDAO shiro sessionDao层的实现 通过redis
|
||||
* <p>
|
||||
* 使用的是shiro-redis开源插件
|
||||
*/
|
||||
|
||||
|
||||
@Bean
|
||||
public RedisSessionDAO redisSessionDAO() {
|
||||
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
|
||||
redisSessionDAO.setRedisManager(redisManager());
|
||||
redisSessionDAO.setExpire(21600);
|
||||
return redisSessionDAO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 开启shiro aop注解支持.
|
||||
* 使用代理方式;所以需要开启代码支持;
|
||||
|
@ -12,6 +12,7 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
|
||||
@ -54,7 +55,7 @@ public class WebMvcConfigurer extends WebMvcConfigurationSupport {
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**")
|
||||
.allowedOrigins("*")
|
||||
.allowedOriginPatterns(CorsConfiguration.ALL)
|
||||
.allowCredentials(true)
|
||||
.allowedMethods("GET", "POST", "DELETE", "PUT", "PATCH");
|
||||
}
|
||||
|
26
src/main/java/com/rymcu/forest/handler/AccountHandler.java
Normal file
26
src/main/java/com/rymcu/forest/handler/AccountHandler.java
Normal file
@ -0,0 +1,26 @@
|
||||
package com.rymcu.forest.handler;
|
||||
|
||||
import com.rymcu.forest.handler.event.AccountEvent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* Created on 2022/8/24 14:44.
|
||||
*
|
||||
* @author ronger
|
||||
* @email ronger-x@outlook.com
|
||||
* @packageName com.rymcu.forest.handler
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
public class AccountHandler {
|
||||
|
||||
@Async
|
||||
@EventListener
|
||||
public void processAccountLastLoginEvent(AccountEvent accountEvent) {
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
package com.rymcu.forest.handler;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.rymcu.forest.core.constant.NotificationConstant;
|
||||
import com.rymcu.forest.handler.event.ArticleDeleteEvent;
|
||||
import com.rymcu.forest.handler.event.ArticleEvent;
|
||||
import com.rymcu.forest.lucene.service.LuceneService;
|
||||
import com.rymcu.forest.util.NotificationUtils;
|
||||
import com.rymcu.forest.wx.mp.utils.JsonUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
@ -29,7 +29,7 @@ public class ArticleHandler {
|
||||
@Async
|
||||
public void processArticlePostEvent(ArticleEvent articleEvent) throws InterruptedException {
|
||||
Thread.sleep(1000);
|
||||
log.info(String.format("执行文章发布相关事件:[%s]", JsonUtils.toJson(articleEvent)));
|
||||
log.info(String.format("执行文章发布相关事件:[%s]", JSON.toJSONString(articleEvent)));
|
||||
// 发送系统通知
|
||||
if (articleEvent.getNotification()) {
|
||||
NotificationUtils.sendAnnouncement(articleEvent.getIdArticle(), NotificationConstant.Article, articleEvent.getArticleTitle());
|
||||
@ -59,7 +59,7 @@ public class ArticleHandler {
|
||||
@Async
|
||||
public void processArticleDeleteEvent(ArticleDeleteEvent articleDeleteEvent) throws InterruptedException {
|
||||
Thread.sleep(1000);
|
||||
log.info(String.format("执行文章删除相关事件:[%s]", JsonUtils.toJson(articleDeleteEvent)));
|
||||
log.info(String.format("执行文章删除相关事件:[%s]", JSON.toJSONString(articleDeleteEvent)));
|
||||
luceneService.deleteArticle(articleDeleteEvent.getIdArticle());
|
||||
log.info("执行完成文章删除相关事件...id={}", articleDeleteEvent.getIdArticle());
|
||||
}
|
||||
|
@ -1,12 +1,12 @@
|
||||
package com.rymcu.forest.handler;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.rymcu.forest.core.constant.NotificationConstant;
|
||||
import com.rymcu.forest.entity.Comment;
|
||||
import com.rymcu.forest.handler.event.CommentEvent;
|
||||
import com.rymcu.forest.mapper.CommentMapper;
|
||||
import com.rymcu.forest.util.Html2TextUtil;
|
||||
import com.rymcu.forest.util.NotificationUtils;
|
||||
import com.rymcu.forest.wx.mp.utils.JsonUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
@ -32,7 +32,7 @@ public class CommentHandler {
|
||||
@Async
|
||||
@EventListener
|
||||
public void processCommentCreatedEvent(CommentEvent commentEvent) throws InterruptedException {
|
||||
log.info(String.format("开始执行评论发布事件:[%s]", JsonUtils.toJson(commentEvent)));
|
||||
log.info(String.format("开始执行评论发布事件:[%s]", JSON.toJSONString(commentEvent)));
|
||||
String commentContent = commentEvent.getContent();
|
||||
Integer length = commentContent.length();
|
||||
if (length > MAX_PREVIEW) {
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.rymcu.forest.handler.event;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Created on 2022/8/24 14:45.
|
||||
*
|
||||
* @author ronger
|
||||
* @email ronger-x@outlook.com
|
||||
* @packageName com.rymcu.forest.handler.event
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class AccountEvent {
|
||||
|
||||
private String account;
|
||||
|
||||
}
|
@ -1,13 +1,14 @@
|
||||
package com.rymcu.forest.jwt.service;
|
||||
|
||||
|
||||
import com.rymcu.forest.handler.event.AccountEvent;
|
||||
import com.rymcu.forest.jwt.def.JwtConstants;
|
||||
import com.rymcu.forest.jwt.model.TokenModel;
|
||||
import com.rymcu.forest.service.UserService;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@ -27,7 +28,7 @@ public class RedisTokenManager implements TokenManager {
|
||||
@Autowired
|
||||
private StringRedisTemplate redisTemplate;
|
||||
@Resource
|
||||
private UserService userService;
|
||||
private ApplicationEventPublisher applicationEventPublisher;
|
||||
|
||||
/**
|
||||
* 生成TOKEN
|
||||
@ -62,7 +63,7 @@ public class RedisTokenManager implements TokenManager {
|
||||
String result = redisTemplate.boundValueOps(key.toString()).get();
|
||||
if (StringUtils.isBlank(result)) {
|
||||
// 更新最后在线时间
|
||||
userService.updateLastOnlineTimeByEmail(model.getUsername());
|
||||
applicationEventPublisher.publishEvent(new AccountEvent(model.getUsername()));
|
||||
redisTemplate.boundValueOps(key.toString()).set(LocalDateTime.now().toString(), JwtConstants.LAST_ONLINE_EXPIRES_MINUTE, TimeUnit.MINUTES);
|
||||
}
|
||||
return true;
|
||||
|
@ -39,4 +39,11 @@ public interface BankAccountMapper extends Mapper<BankAccount> {
|
||||
* @return
|
||||
*/
|
||||
BankAccountDTO selectByBankAccount(@Param("bankAccount") String bankAccount);
|
||||
|
||||
/**
|
||||
* 查询用户个人银行账户信息
|
||||
* @param idUser
|
||||
* @return
|
||||
*/
|
||||
BankAccountDTO findPersonBankAccountByIdUser(@Param("idUser") Long idUser);
|
||||
}
|
||||
|
@ -1,14 +0,0 @@
|
||||
package com.rymcu.forest.service;
|
||||
|
||||
import com.rymcu.forest.core.service.Service;
|
||||
import com.rymcu.forest.entity.WxUser;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
||||
|
||||
/**
|
||||
* @author ronger
|
||||
*/
|
||||
public interface WxUserService extends Service<WxUser> {
|
||||
|
||||
WxUser saveUser(WxMpUser wxMpUser, String appId);
|
||||
|
||||
}
|
@ -5,13 +5,11 @@ import com.rymcu.forest.core.exception.ServiceException;
|
||||
import com.rymcu.forest.core.service.AbstractService;
|
||||
import com.rymcu.forest.dto.ArticleTagDTO;
|
||||
import com.rymcu.forest.dto.LabelModel;
|
||||
import com.rymcu.forest.dto.baidu.TagNlpDTO;
|
||||
import com.rymcu.forest.entity.Article;
|
||||
import com.rymcu.forest.entity.Tag;
|
||||
import com.rymcu.forest.mapper.ArticleMapper;
|
||||
import com.rymcu.forest.mapper.TagMapper;
|
||||
import com.rymcu.forest.service.TagService;
|
||||
import com.rymcu.forest.util.BaiDuAipUtils;
|
||||
import com.rymcu.forest.util.CacheUtils;
|
||||
import com.rymcu.forest.util.XssUtils;
|
||||
import com.rymcu.forest.web.api.common.UploadController;
|
||||
@ -95,16 +93,6 @@ public class TagServiceImpl extends AbstractService<Tag> implements TagService {
|
||||
return 1;
|
||||
} else {
|
||||
if (StringUtils.isNotBlank(articleContentHtml)) {
|
||||
List<TagNlpDTO> list = BaiDuAipUtils.getKeywords(article.getArticleTitle(), articleContentHtml);
|
||||
if (list.size() > 0) {
|
||||
StringBuffer tags = new StringBuffer();
|
||||
for (TagNlpDTO tagNlpDTO : list) {
|
||||
tags.append(tagNlpDTO.getTag()).append(",");
|
||||
}
|
||||
article.setArticleTags(tags.toString());
|
||||
} else {
|
||||
article.setArticleTags("待分类");
|
||||
}
|
||||
saveTagArticle(article, articleContentHtml, userId);
|
||||
}
|
||||
}
|
||||
|
@ -9,10 +9,11 @@ import com.rymcu.forest.entity.BankAccount;
|
||||
import com.rymcu.forest.entity.TransactionRecord;
|
||||
import com.rymcu.forest.enumerate.TransactionCode;
|
||||
import com.rymcu.forest.enumerate.TransactionEnum;
|
||||
import com.rymcu.forest.mapper.BankAccountMapper;
|
||||
import com.rymcu.forest.mapper.TransactionRecordMapper;
|
||||
import com.rymcu.forest.service.BankAccountService;
|
||||
import com.rymcu.forest.service.TransactionRecordService;
|
||||
import com.rymcu.forest.util.DateUtil;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@ -32,7 +33,7 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
@Resource
|
||||
private TransactionRecordMapper transactionRecordMapper;
|
||||
@Resource
|
||||
private BankAccountService bankAccountService;
|
||||
private BankAccountMapper bankAccountMapper;
|
||||
@Resource
|
||||
private RedisService redisService;
|
||||
|
||||
@ -62,8 +63,8 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
}
|
||||
|
||||
private TransactionRecordDTO genTransactionRecord(TransactionRecordDTO transactionRecordDTO) {
|
||||
BankAccountDTO toBankAccount = bankAccountService.findByBankAccount(transactionRecordDTO.getToBankAccount());
|
||||
BankAccountDTO formBankAccount = bankAccountService.findByBankAccount(transactionRecordDTO.getFormBankAccount());
|
||||
BankAccountDTO toBankAccount = bankAccountMapper.selectByBankAccount(transactionRecordDTO.getToBankAccount());
|
||||
BankAccountDTO formBankAccount = bankAccountMapper.selectByBankAccount(transactionRecordDTO.getFormBankAccount());
|
||||
transactionRecordDTO.setFormBankAccountInfo(formBankAccount);
|
||||
transactionRecordDTO.setToBankAccountInfo(toBankAccount);
|
||||
return transactionRecordDTO;
|
||||
@ -71,8 +72,8 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
|
||||
@Override
|
||||
public TransactionRecord userTransfer(Long toUserId, Long formUserId, TransactionEnum transactionType) {
|
||||
BankAccountDTO toBankAccount = bankAccountService.findBankAccountByIdUser(toUserId);
|
||||
BankAccountDTO formBankAccount = bankAccountService.findBankAccountByIdUser(formUserId);
|
||||
BankAccountDTO toBankAccount = bankAccountMapper.findPersonBankAccountByIdUser(toUserId);
|
||||
BankAccountDTO formBankAccount = bankAccountMapper.findPersonBankAccountByIdUser(formUserId);
|
||||
TransactionRecord transactionRecord = new TransactionRecord();
|
||||
transactionRecord.setToBankAccount(toBankAccount.getBankAccount());
|
||||
transactionRecord.setFormBankAccount(formBankAccount.getBankAccount());
|
||||
@ -83,7 +84,7 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
|
||||
@Override
|
||||
public TransactionRecord bankTransfer(Long idUser, TransactionEnum transactionType) {
|
||||
BankAccountDTO toBankAccount = bankAccountService.findBankAccountByIdUser(idUser);
|
||||
BankAccountDTO toBankAccount = bankAccountMapper.findPersonBankAccountByIdUser(idUser);
|
||||
Boolean isTrue;
|
||||
// 校验货币规则
|
||||
switch (transactionType) {
|
||||
@ -95,7 +96,7 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
isTrue = true;
|
||||
}
|
||||
if (isTrue) {
|
||||
BankAccount formBankAccount = bankAccountService.findSystemBankAccount();
|
||||
BankAccount formBankAccount = findSystemBankAccount();
|
||||
TransactionRecord transactionRecord = new TransactionRecord();
|
||||
transactionRecord.setToBankAccount(toBankAccount.getBankAccount());
|
||||
transactionRecord.setFormBankAccount(formBankAccount.getBankAccount());
|
||||
@ -106,6 +107,14 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
return null;
|
||||
}
|
||||
|
||||
private BankAccount findSystemBankAccount() {
|
||||
BankAccount bankAccount = new BankAccount();
|
||||
bankAccount.setIdBank(1L);
|
||||
bankAccount.setAccountType("1");
|
||||
bankAccount.setAccountOwner(2L);
|
||||
return bankAccountMapper.selectOne(bankAccount);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TransactionRecord newbieRewards(TransactionRecord transactionRecord) {
|
||||
// 判断是否重复发放
|
||||
@ -113,7 +122,7 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
if (result) {
|
||||
return transactionRecord;
|
||||
}
|
||||
BankAccount formBankAccount = bankAccountService.findSystemBankAccount();
|
||||
BankAccount formBankAccount = findSystemBankAccount();
|
||||
transactionRecord.setFormBankAccount(formBankAccount.getBankAccount());
|
||||
transactionRecord.setMoney(new BigDecimal(TransactionEnum.NewbieRewards.getMoney()));
|
||||
transactionRecord.setFunds(TransactionEnum.NewbieRewards.getDescription());
|
||||
@ -146,7 +155,7 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
}
|
||||
|
||||
private boolean checkFormAccountStatus(String formBankAccount, BigDecimal money) {
|
||||
BankAccount bankAccount = bankAccountService.findInfoByBankAccount(formBankAccount);
|
||||
BankAccount bankAccount = findInfoByBankAccount(formBankAccount);
|
||||
if (Objects.nonNull(bankAccount)) {
|
||||
if (bankAccount.getAccountBalance().compareTo(money) > 0) {
|
||||
return true;
|
||||
@ -154,4 +163,10 @@ public class TransactionRecordServiceImpl extends AbstractService<TransactionRec
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private BankAccount findInfoByBankAccount(String bankAccount) {
|
||||
BankAccount searchBankAccount = new BankAccount();
|
||||
searchBankAccount.setBankAccount(bankAccount);
|
||||
return bankAccountMapper.selectOne(searchBankAccount);
|
||||
}
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
package com.rymcu.forest.service.impl;
|
||||
|
||||
import com.rymcu.forest.core.service.AbstractService;
|
||||
import com.rymcu.forest.entity.WxUser;
|
||||
import com.rymcu.forest.mapper.WxUserMapper;
|
||||
import com.rymcu.forest.service.WxUserService;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ronger
|
||||
*/
|
||||
@Service
|
||||
public class WxUserServiceImpl extends AbstractService<WxUser> implements WxUserService {
|
||||
|
||||
@Resource
|
||||
private WxUserMapper wxUserMapper;
|
||||
|
||||
@Override
|
||||
public WxUser saveUser(WxMpUser wxMpUser, String appId) {
|
||||
WxUser searchWxUser = new WxUser();
|
||||
if (StringUtils.isBlank(wxMpUser.getUnionId())) {
|
||||
searchWxUser.setUnionId(wxMpUser.getUnionId());
|
||||
} else {
|
||||
searchWxUser.setAppId(appId);
|
||||
searchWxUser.setOpenId(searchWxUser.getOpenId());
|
||||
}
|
||||
List<WxUser> wxUsers = wxUserMapper.select(searchWxUser);
|
||||
WxUser wxUser;
|
||||
if (wxUsers.isEmpty()) {
|
||||
wxUser = new WxUser();
|
||||
wxUser.setAppId(appId);
|
||||
wxUser = copyWxUser(wxMpUser,wxUser);
|
||||
wxUserMapper.insertSelective(wxUser);
|
||||
} else {
|
||||
wxUser = wxUsers.get(0);
|
||||
wxUser = copyWxUser(wxMpUser,wxUser);
|
||||
wxUserMapper.updateByPrimaryKeySelective(wxUser);
|
||||
}
|
||||
return wxUser;
|
||||
}
|
||||
|
||||
private WxUser copyWxUser(WxMpUser wxMpUser, WxUser wxUser) {
|
||||
wxUser.setSubscribe(wxMpUser.getSubscribe());
|
||||
wxUser.setSubscribeTime(wxMpUser.getSubscribeTime());
|
||||
wxUser.setUnionId(wxMpUser.getUnionId());
|
||||
wxUser.setOpenId(wxMpUser.getOpenId());
|
||||
wxUser.setLanguage(wxMpUser.getLanguage());
|
||||
return wxUser;
|
||||
}
|
||||
}
|
@ -1,197 +0,0 @@
|
||||
package com.rymcu.forest.util;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.baidu.aip.nlp.AipNlp;
|
||||
import com.rymcu.forest.dto.baidu.TagNlpDTO;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author ronger
|
||||
*/
|
||||
public class BaiDuAipUtils {
|
||||
|
||||
public static final String APP_ID = "18094949";
|
||||
public static final String API_KEY = "3h3BOgejXI1En5aq1iGHeWrF";
|
||||
public static final String SECRET_KEY = "8guDNvxWF1wu8ogpVxLHlRY5FeOBE8z7";
|
||||
|
||||
public static final Integer MAX_CONTENT_LENGTH = 3000;
|
||||
|
||||
public static void main(String[] args) {
|
||||
String title = "51单片机第4章--跑马灯实验";
|
||||
System.out.println(title.length());
|
||||
String content = "<h2>4.1 进制转换基础知识</h2>\n" +
|
||||
"<p>进制实际是一个非常简单易懂的概念,对于初学者来说也很容易上手。我们接触最多的就是十进制了,它的特点为逢十进一,包含 0,1,2,3,4,5,6,7,8,9 共十个元素。在生活中我们用到的基本都是十进制了,所以大家对它已经非常熟悉并能应用自如,但是在计算机(包括单片机)世界里,所有都是以二进制为基础的。二进制的特点为逢二进一,包含 0,1 共两个元素。计算机中的数据都是以二进制存储的,这就是我们所说的 0,1 世界。通常我们讲的 32 位或 64 位操作系统这里的位指的就是二进制位数。因为我们实际多用十进制,那么我们在和计算机系统沟通过程中,十进制与二进制之间的转换就变得很重要了。进制之间的转换如下表所示。<br />\n" +
|
||||
"<img src=\"https://static.rymcu.com/article/1584363905093.png\" alt=\"表4-1进制转换.png\" /><br />\n" +
|
||||
"二进制转换十进制公式如下:<br />\n" +
|
||||
"<img src=\"https://static.rymcu.com/article/1584363941039.png\" alt=\"进制转换公式.png\" /><br />\n" +
|
||||
"其中,n 表示二进制的位数。<br />\n" +
|
||||
"下面我们举个例子来更加直观的说明这个公式:<br />\n" +
|
||||
"例如:1101,这是一个 4 位的二进制数,计算如下,<br />\n" +
|
||||
"<img src=\"https://static.rymcu.com/article/1584363961871.png\" alt=\"进制转换公式1.png\" /><br />\n" +
|
||||
"大家可以利用这个公式计算的结果和上表进行一一对照。<br />\n" +
|
||||
"十六进制也是我们常用的进制,它的特点为逢十六进一,包括 0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F 共十六个元素。实际上十六进制是二进制的一种特殊形式,十六进制的 1 位等价于二进制的 4 位,在 C 语言编程中我们常用十六进制来表示二进制数。在实际应用中我们常常该数字之前加一个前缀来表示他的进制:“0b”表示二进制,“0x”表示十六进制。下面我们举例说明:<br />\n" +
|
||||
"0b10010010 = 0x92<br />\n" +
|
||||
"上面一个八位的二进制数转换为一个两位的十六进制数。二进制的前 4 位等于十六进制的第 1 位:<br />\n" +
|
||||
"0b1001 = 0x9<br />\n" +
|
||||
"二进制数的后 4 位等于十六进制的第 2 位:<br />\n" +
|
||||
"0b0010 = 0x2<br />\n" +
|
||||
"在计算机中,我们通常所说的二进制的 1 位也叫 1bit,8 位表示 1 个字节,也叫 1Byte。根据二进制与十六机制的关系,一个 2 位的十六进制数则可表示 1 个字节。在运用的过程中牢记 0~15 的十进制与二进制、十六进制之间的转换关系对于程序的编写有很大的好处。</p>\n" +
|
||||
"<h2>4.2 闪烁 LED 小灯</h2>\n" +
|
||||
"<p>怎么让 LED 小灯闪烁?我们最先想到的办法当然是先让 LED 小灯点亮,延时一段时间,熄灭 LED 小灯,再延时一段时间,一直循环上面的步骤就能实现 LED 小灯的闪烁了。根据第 3 章的知识我们知道点亮 LED 的语句为“led0 = 0;”,熄灭 LED 的语句为“led0 = 1;”。按照第 3 章介绍我们重新建立一个 LED 小灯闪烁的工程。程序代码设计如下:</p>\n" +
|
||||
"<pre><code class=\"language-C++\">#include<reg52.h> //寄存器声明头文件 \n" +
|
||||
"sbit led0 = P1^0; // 位声明,将P1.0管脚声明为led0 \n" +
|
||||
" \n" +
|
||||
"void main() //程序主函数入口,每个C语言程序有且只有一个 \n" +
|
||||
"{ \n" +
|
||||
" int i; //变量声明 \n" +
|
||||
" while(1) //循环 \n" +
|
||||
" { \n" +
|
||||
" led0 = 0; //赋值管脚P1.0为低电平,点亮LED小灯 \n" +
|
||||
" for(i=0;i<5000;i++);//延时一段时间 \n" +
|
||||
" led0 = 1;//熄灭LED小灯 \n" +
|
||||
" for(i=0;i<5000;i++);//再延时一段时间 \n" +
|
||||
" } \n" +
|
||||
"} \n" +
|
||||
"</code></pre>\n" +
|
||||
"<h2>4.3\t跑马灯设计</h2>\n" +
|
||||
"<p>在我们的开发板上设计了 8 个依次排列的 LED 小灯,让小灯依次点亮和熄灭实现跑马灯的效果是我们这一节的主要内容。</p>\n" +
|
||||
"<h3>4.3.1 硬件设计</h3>\n" +
|
||||
"<p>8 个 LED 小灯的硬件电路设计原理图如下图所示:<br />\n" +
|
||||
"<img src=\"https://static.rymcu.com/article/1584364202185.png\" alt=\"图4-1-8位跑马灯设计原理图.png\" /><br />\n" +
|
||||
"如上图所示,8 个 LED 小灯 LED0-LED7 的正极和电源 VCC 之间均串联了一个 1K 的限流电阻。LED7-LED0 的负极与 74HC573 锁存器的 Q0-Q7 一一相连接。锁存器 74HC573 的功能我们这里不详细介绍,把它的 D0-D7 与 Q0-Q7 之间看作是电气上一一联通的。由图所示,锁存器的 D0-D7 和单片机的 P1.7-P1.0 是一一连接的。因此,LED 小灯 LED7-LED0 的负极与单片机的 P1.7~P1.0 管脚一一相连,在单片机程序中通过控制 P1.7-P1.0 管脚的高低电平便可控制 8 个 LED 小灯的亮灭。<br />\n" +
|
||||
"该实验要实现的功能为:首先点亮 LED0,然后延迟一段时间,熄灭 LED0,熄灭 LED0 点亮 LED1,延迟一段时间,熄灭 LED1 点亮 LED2,延迟一段时间,一直到熄灭 LED6 点亮 LED7,依照上面的步骤一直循环下去,便实现了一个简单的跑马灯的效果。</p>\n" +
|
||||
"<h3>4.3.2 软件设计</h3>\n" +
|
||||
"<p>前面我们试验中都是只对 P1.0 这个管脚进行赋值,来控制 LED 小灯 led0 的亮灭。实际在编写程序的过程中我们可以对 P1 寄存器进行直接赋值来同时控制 8 个 LED 小灯。<br />\n" +
|
||||
"<img src=\"https://static.rymcu.com/article/1584364354304.png\" alt=\"表4-2-P1寄存器对照表.png\" /><br />\n" +
|
||||
"如上表所示,P1 寄存器是一个 8 位的寄存器,最高位到最低位依次对应的 P1.7 管脚到 P1.0 管脚。点亮某个 LED 小灯的二进制,十六进制赋值如上表所示。例如 P1 = 0xFE;表示点亮 led0,P1=0x7F;则表示点亮 led7。在软件代码设计时,我们想到的第一个方法为依次点亮小灯并延时,代码如下所示。</p>\n" +
|
||||
"<pre><code class=\"language-C++\">#include<reg52.h> //加载头文件\n" +
|
||||
"int i;\n" +
|
||||
"\n" +
|
||||
"void main()//主函数入口\n" +
|
||||
"{\n" +
|
||||
"\tP1 = 0xFE; //点亮LED0\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"\tP1 = 0xFD; //点亮LED1\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"\tP1 = 0xFB; //点亮LED2\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"\tP1 = 0xF7; //点亮LED3\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"\tP1 = 0xEF; //点亮LED4\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"\tP1 = 0xDF; //点亮LED5\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"\tP1 = 0xBF; //点亮LED6\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"\tP1 = 0x7F; //点亮LED7\n" +
|
||||
"\tfor(i=0;i<5000;i++);//延时一段时间\n" +
|
||||
"} \n" +
|
||||
"</code></pre>\n" +
|
||||
"<p>我们对代码进行一下小的改进,这个方法这里称之为“左移取反”法,这个方法在很多的应用中都能用到,非常实用。代码如下图所示。</p>\n" +
|
||||
"<pre><code class=\"language-C++\">#include<reg52.h> //加载头文件\n" +
|
||||
"int i;\n" +
|
||||
"int flag=0;\n" +
|
||||
" \n" +
|
||||
"void main()//主函数入口\n" +
|
||||
"{ \n" +
|
||||
" P0 = 0xff;\n" +
|
||||
"\twhile(1)\n" +
|
||||
"\t{\n" +
|
||||
"\t\tP1 = ~(0x01<<flag);//P1的值等于1左移flag位后取反,点亮第flag位LED小灯亮\n" +
|
||||
"\t\tfor(i=0;i<25000;i++);//延时一段时间\n" +
|
||||
"\n" +
|
||||
"\t\tif(flag>=8)\t //flag大于7时,置零,从零开始\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\tflag=0;\n" +
|
||||
"\t\t}\n" +
|
||||
"\t\telse\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\tflag++;\t //flag累加\n" +
|
||||
"\t\t}\n" +
|
||||
"\t}\n" +
|
||||
"}\n" +
|
||||
"</code></pre>\n" +
|
||||
"<p>我们对上面代码进行分析,flag 是一个从 0 到 7 依次循环的数,P1 等于 1 向左移 flag 位再取反。当 flag 等于 2 时,0b0000,0001 左移 2 位等于 0b0000,0100,再取反等于 0b1111,1011=0xFB,并赋值给 P1,点亮了小灯 led2。同理,当 flag 等于 6 时,0b0000,0001 左移 6 位等于 0b0100,0000,再取反等于 0b1011,1111=0xBF 并赋值给 P1,点亮了小灯 led6。flag 为其他值时,大家可以进行一一分析。</p>\n" +
|
||||
"<h3>4.3.3 下载验证</h3>\n" +
|
||||
"<p>将程序通过 STC-isp 软件下载到单片机,观察 8 个 LED 小灯效果与设想的效果是否一致?至此,本章的内容讲解完毕,内容包括进制转换的基础知识、LED 小灯闪速程序以及跑马灯的两种程序。大家在动手操作的过程中多多下载到单片机中观察现象,加深印象。</p>\n";
|
||||
System.out.println(getKeywords(title, content));
|
||||
System.out.println(getNewsSummary(title, content, 200));
|
||||
|
||||
}
|
||||
|
||||
public static List<TagNlpDTO> getKeywords(String title, String content) {
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return null;
|
||||
}
|
||||
// api 限制内容不能超过 3000 字
|
||||
if (content.length() > MAX_CONTENT_LENGTH) {
|
||||
content = content.substring(0, MAX_CONTENT_LENGTH);
|
||||
}
|
||||
// 初始化一个AipNlp
|
||||
AipNlp client = new AipNlp(APP_ID, API_KEY, SECRET_KEY);
|
||||
|
||||
// 可选:设置网络连接参数
|
||||
client.setConnectionTimeoutInMillis(2000);
|
||||
client.setSocketTimeoutInMillis(60000);
|
||||
|
||||
// 传入可选参数调用接口
|
||||
HashMap<String, Object> options = new HashMap<String, Object>(1);
|
||||
|
||||
// 新闻摘要接口
|
||||
JSONObject res = client.keyword(title, Html2TextUtil.getContent(content), options);
|
||||
List<TagNlpDTO> list = JSON.parseArray(res.get("items").toString(), TagNlpDTO.class);
|
||||
return list;
|
||||
}
|
||||
|
||||
public static String getTopic(String title, String content) {
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return "";
|
||||
}
|
||||
// api 限制内容不能超过 3000 字
|
||||
if (content.length() > MAX_CONTENT_LENGTH) {
|
||||
content = content.substring(0, MAX_CONTENT_LENGTH);
|
||||
}
|
||||
// 初始化一个AipNlp
|
||||
AipNlp client = new AipNlp(APP_ID, API_KEY, SECRET_KEY);
|
||||
|
||||
// 可选:设置网络连接参数
|
||||
client.setConnectionTimeoutInMillis(2000);
|
||||
client.setSocketTimeoutInMillis(60000);
|
||||
|
||||
// 传入可选参数调用接口
|
||||
HashMap<String, Object> options = new HashMap<String, Object>(1);
|
||||
|
||||
// 新闻摘要接口
|
||||
JSONObject res = client.topic(title, Html2TextUtil.getContent(content), options);
|
||||
return res.toString(2);
|
||||
}
|
||||
|
||||
public static String getNewsSummary(String title, String content, int maxSummaryLen) {
|
||||
if (StringUtils.isBlank(content)) {
|
||||
return "";
|
||||
}
|
||||
// api 限制内容不能超过 3000 字
|
||||
if (content.length() > MAX_CONTENT_LENGTH) {
|
||||
content = content.substring(0, MAX_CONTENT_LENGTH);
|
||||
}
|
||||
// 初始化一个AipNlp
|
||||
AipNlp client = new AipNlp(APP_ID, API_KEY, SECRET_KEY);
|
||||
|
||||
// 可选:设置网络连接参数
|
||||
client.setConnectionTimeoutInMillis(2000);
|
||||
client.setSocketTimeoutInMillis(60000);
|
||||
|
||||
// 传入可选参数调用接口
|
||||
HashMap<String, Object> options = new HashMap<String, Object>(1);
|
||||
options.put("title", title);
|
||||
|
||||
// 新闻摘要接口
|
||||
JSONObject res = client.newsSummary(Html2TextUtil.getContent(content), maxSummaryLen, options);
|
||||
return res.getString("summary");
|
||||
}
|
||||
|
||||
}
|
@ -1,149 +0,0 @@
|
||||
package com.rymcu.forest.wx.miniapp.config;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.api.impl.WxMaServiceImpl;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaKefuMessage;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaSubscribeMessage;
|
||||
import cn.binarywang.wx.miniapp.config.impl.WxMaDefaultConfigImpl;
|
||||
import cn.binarywang.wx.miniapp.message.WxMaMessageHandler;
|
||||
import cn.binarywang.wx.miniapp.message.WxMaMessageRouter;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.collect.Maps;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.io.File;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Slf4j
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxMaProperties.class)
|
||||
public class WxMaConfiguration {
|
||||
private final WxMaProperties properties;
|
||||
|
||||
private static final Map<String, WxMaMessageRouter> routers = Maps.newHashMap();
|
||||
private static Map<String, WxMaService> maServices;
|
||||
|
||||
@Autowired
|
||||
public WxMaConfiguration(WxMaProperties properties) {
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public static WxMaService getMaService(String appid) {
|
||||
WxMaService wxService = maServices.get(appid);
|
||||
if (wxService == null) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appid));
|
||||
}
|
||||
|
||||
return wxService;
|
||||
}
|
||||
|
||||
public static WxMaMessageRouter getRouter(String appid) {
|
||||
return routers.get(appid);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
List<WxMaProperties.Config> configs = this.properties.getConfigs();
|
||||
if (configs == null) {
|
||||
throw new RuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
|
||||
}
|
||||
|
||||
maServices = configs.stream()
|
||||
.map(a -> {
|
||||
WxMaDefaultConfigImpl config = new WxMaDefaultConfigImpl();
|
||||
// WxMaDefaultConfigImpl config = new WxMaRedisConfigImpl(new JedisPool());
|
||||
// 使用上面的配置时,需要同时引入jedis-lock的依赖,否则会报类无法找到的异常
|
||||
config.setAppid(a.getAppId());
|
||||
config.setSecret(a.getSecret());
|
||||
config.setToken(a.getToken());
|
||||
config.setAesKey(a.getAesKey());
|
||||
config.setMsgDataFormat(a.getMsgDataFormat());
|
||||
|
||||
WxMaService service = new WxMaServiceImpl();
|
||||
service.setWxMaConfig(config);
|
||||
routers.put(a.getAppId(), this.newRouter(service));
|
||||
return service;
|
||||
}).collect(Collectors.toMap(s -> s.getWxMaConfig().getAppid(), a -> a));
|
||||
}
|
||||
|
||||
private WxMaMessageRouter newRouter(WxMaService service) {
|
||||
final WxMaMessageRouter router = new WxMaMessageRouter(service);
|
||||
router
|
||||
.rule().handler(logHandler).next()
|
||||
.rule().async(false).content("订阅消息").handler(subscribeMsgHandler).end()
|
||||
.rule().async(false).content("文本").handler(textHandler).end()
|
||||
.rule().async(false).content("图片").handler(picHandler).end()
|
||||
.rule().async(false).content("二维码").handler(qrcodeHandler).end();
|
||||
return router;
|
||||
}
|
||||
|
||||
private final WxMaMessageHandler subscribeMsgHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
service.getMsgService().sendSubscribeMsg(WxMaSubscribeMessage.builder()
|
||||
.templateId("此处更换为自己的模板id")
|
||||
.data(Lists.newArrayList(
|
||||
new WxMaSubscribeMessage.MsgData("keyword1", "339208499")))
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler logHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
log.info("收到消息:" + wxMessage.toString());
|
||||
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("收到信息为:" + wxMessage.toJson())
|
||||
.toUser(wxMessage.getFromUser()).build());
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler textHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
service.getMsgService().sendKefuMsg(WxMaKefuMessage.newTextBuilder().content("回复文本消息")
|
||||
.toUser(wxMessage.getFromUser()).build());
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler picHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
try {
|
||||
WxMediaUploadResult uploadResult = service.getMediaService()
|
||||
.uploadMedia("image", "png",
|
||||
ClassLoader.getSystemResourceAsStream("tmp.png"));
|
||||
service.getMsgService().sendKefuMsg(
|
||||
WxMaKefuMessage
|
||||
.newImageBuilder()
|
||||
.mediaId(uploadResult.getMediaId())
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
} catch (WxErrorException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
private final WxMaMessageHandler qrcodeHandler = (wxMessage, context, service, sessionManager) -> {
|
||||
try {
|
||||
final File file = service.getQrcodeService().createQrcode("123", 430);
|
||||
WxMediaUploadResult uploadResult = service.getMediaService().uploadMedia("image", file);
|
||||
service.getMsgService().sendKefuMsg(
|
||||
WxMaKefuMessage
|
||||
.newImageBuilder()
|
||||
.mediaId(uploadResult.getMediaId())
|
||||
.toUser(wxMessage.getFromUser())
|
||||
.build());
|
||||
} catch (WxErrorException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package com.rymcu.forest.wx.miniapp.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "wx.miniapp")
|
||||
public class WxMaProperties {
|
||||
|
||||
private List<Config> configs;
|
||||
|
||||
@Data
|
||||
public static class Config {
|
||||
/**
|
||||
* 设置微信小程序的appid
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 设置微信小程序的Secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置微信小程序消息服务器配置的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置微信小程序消息服务器配置的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
|
||||
/**
|
||||
* 消息格式,XML或者JSON
|
||||
*/
|
||||
private String msgDataFormat;
|
||||
}
|
||||
|
||||
}
|
@ -1,80 +0,0 @@
|
||||
package com.rymcu.forest.wx.miniapp.controller;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.constant.WxMaConstants;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.common.io.Files;
|
||||
import com.rymcu.forest.wx.miniapp.config.WxMaConfiguration;
|
||||
import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 小程序临时素材接口
|
||||
* Created by BinaryWang on 2017/6/16.
|
||||
* </pre>
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/wx/media/{appId}")
|
||||
public class WxMaMediaController {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* 上传临时素材
|
||||
*
|
||||
* @return 素材的media_id列表,实际上如果有的话,只会有一个
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public List<String> uploadMedia(@PathVariable String appId, HttpServletRequest request) throws WxErrorException {
|
||||
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
|
||||
|
||||
CommonsMultipartResolver resolver = new CommonsMultipartResolver(request.getSession().getServletContext());
|
||||
|
||||
if (!resolver.isMultipart(request)) {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
|
||||
Iterator<String> it = multiRequest.getFileNames();
|
||||
List<String> result = Lists.newArrayList();
|
||||
while (it.hasNext()) {
|
||||
try {
|
||||
MultipartFile file = multiRequest.getFile(it.next());
|
||||
File newFile = new File(Files.createTempDir(), file.getOriginalFilename());
|
||||
this.logger.info("filePath is :" + newFile.toString());
|
||||
file.transferTo(newFile);
|
||||
WxMediaUploadResult uploadResult = wxService.getMediaService().uploadMedia(WxMaConstants.KefuMsgType.IMAGE, newFile);
|
||||
this.logger.info("media_id : " + uploadResult.getMediaId());
|
||||
result.add(uploadResult.getMediaId());
|
||||
} catch (IOException e) {
|
||||
this.logger.error(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 下载临时素材
|
||||
*/
|
||||
@GetMapping("/download/{mediaId}")
|
||||
public File getMedia(@PathVariable String appId, @PathVariable String mediaId) throws WxErrorException {
|
||||
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
|
||||
|
||||
return wxService.getMediaService().getMedia(mediaId);
|
||||
}
|
||||
}
|
@ -1,93 +0,0 @@
|
||||
package com.rymcu.forest.wx.miniapp.controller;
|
||||
|
||||
import cn.binarywang.wx.miniapp.api.WxMaService;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaJscode2SessionResult;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaPhoneNumberInfo;
|
||||
import cn.binarywang.wx.miniapp.bean.WxMaUserInfo;
|
||||
import com.rymcu.forest.wx.miniapp.config.WxMaConfiguration;
|
||||
import com.rymcu.forest.wx.miniapp.utils.JsonUtils;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 微信小程序用户接口
|
||||
*
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/wx/user/{appId}")
|
||||
public class WxMaUserController {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
/**
|
||||
* 登陆接口
|
||||
*/
|
||||
@GetMapping("/login")
|
||||
public String login(@PathVariable String appId, String code) {
|
||||
if (StringUtils.isBlank(code)) {
|
||||
return "empty jscode";
|
||||
}
|
||||
|
||||
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
|
||||
|
||||
try {
|
||||
WxMaJscode2SessionResult session = wxService.getUserService().getSessionInfo(code);
|
||||
this.logger.info(session.getSessionKey());
|
||||
this.logger.info(session.getOpenid());
|
||||
//TODO 可以增加自己的逻辑,关联业务相关数据
|
||||
return JsonUtils.toJson(session);
|
||||
} catch (WxErrorException e) {
|
||||
this.logger.error(e.getMessage(), e);
|
||||
return e.toString();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取用户信息接口
|
||||
* </pre>
|
||||
*/
|
||||
@GetMapping("/info")
|
||||
public String info(@PathVariable String appId, String sessionKey,
|
||||
String signature, String rawData, String encryptedData, String iv) {
|
||||
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
|
||||
|
||||
// 用户信息校验
|
||||
if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
|
||||
return "user check failed";
|
||||
}
|
||||
|
||||
// 解密用户信息
|
||||
WxMaUserInfo userInfo = wxService.getUserService().getUserInfo(sessionKey, encryptedData, iv);
|
||||
|
||||
return JsonUtils.toJson(userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 获取用户绑定手机号信息
|
||||
* </pre>
|
||||
*/
|
||||
@GetMapping("/phone")
|
||||
public String phone(@PathVariable String appId, String sessionKey, String signature,
|
||||
String rawData, String encryptedData, String iv) {
|
||||
final WxMaService wxService = WxMaConfiguration.getMaService(appId);
|
||||
|
||||
// 用户信息校验
|
||||
if (!wxService.getUserService().checkUserInfo(sessionKey, rawData, signature)) {
|
||||
return "user check failed";
|
||||
}
|
||||
|
||||
// 解密
|
||||
WxMaPhoneNumberInfo phoneNoInfo = wxService.getUserService().getPhoneNoInfo(sessionKey, encryptedData, iv);
|
||||
|
||||
return JsonUtils.toJson(phoneNoInfo);
|
||||
}
|
||||
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
package com.rymcu.forest.wx.miniapp.utils;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonInclude.Include;
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/binarywang">Binary Wang</a>
|
||||
*/
|
||||
public class JsonUtils {
|
||||
private static final ObjectMapper JSON = new ObjectMapper();
|
||||
|
||||
static {
|
||||
JSON.setSerializationInclusion(Include.NON_NULL);
|
||||
JSON.configure(SerializationFeature.INDENT_OUTPUT, Boolean.TRUE);
|
||||
}
|
||||
|
||||
public static String toJson(Object obj) {
|
||||
try {
|
||||
return JSON.writeValueAsString(obj);
|
||||
} catch (JsonProcessingException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package com.rymcu.forest.wx.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 Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
public abstract class AbstractBuilder {
|
||||
protected final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public abstract WxMpXmlOutMessage build(String content,
|
||||
WxMpXmlMessage wxMessage, WxMpService service);
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.rymcu.forest.wx.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;
|
||||
}
|
||||
|
||||
}
|
@ -1,22 +0,0 @@
|
||||
package com.rymcu.forest.wx.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;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
public class TextBuilder extends AbstractBuilder {
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
@ -1,111 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.config;
|
||||
|
||||
import com.rymcu.forest.wx.mp.handler.*;
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.api.impl.WxMpServiceImpl;
|
||||
import me.chanjar.weixin.mp.config.impl.WxMpDefaultConfigImpl;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType.SUBSCRIBE;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType.UNSUBSCRIBE;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType.EVENT;
|
||||
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.CustomerService.*;
|
||||
import static me.chanjar.weixin.mp.constant.WxMpEventConstants.POI_CHECK_NOTIFY;
|
||||
|
||||
/**
|
||||
* wechat mp configuration
|
||||
*
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(WxMpProperties.class)
|
||||
public class WxMpConfiguration {
|
||||
private final LogHandler logHandler;
|
||||
private final NullHandler nullHandler;
|
||||
private final KfSessionHandler kfSessionHandler;
|
||||
private final StoreCheckNotifyHandler storeCheckNotifyHandler;
|
||||
private final LocationHandler locationHandler;
|
||||
private final MenuHandler menuHandler;
|
||||
private final MsgHandler msgHandler;
|
||||
private final UnsubscribeHandler unsubscribeHandler;
|
||||
private final SubscribeHandler subscribeHandler;
|
||||
private final ScanHandler scanHandler;
|
||||
private final WxMpProperties properties;
|
||||
|
||||
@Bean
|
||||
public WxMpService wxMpService() {
|
||||
// 代码里 getConfigs()处报错的同学,请注意仔细阅读项目说明,你的IDE需要引入lombok插件!!!!
|
||||
final List<WxMpProperties.MpConfig> configs = this.properties.getConfigs();
|
||||
if (configs == null) {
|
||||
throw new RuntimeException("大哥,拜托先看下项目首页的说明(readme文件),添加下相关配置,注意别配错了!");
|
||||
}
|
||||
|
||||
WxMpService service = new WxMpServiceImpl();
|
||||
service.setMultiConfigStorages(configs
|
||||
.stream().map(a -> {
|
||||
WxMpDefaultConfigImpl configStorage = new WxMpDefaultConfigImpl();
|
||||
configStorage.setAppId(a.getAppId());
|
||||
configStorage.setSecret(a.getSecret());
|
||||
configStorage.setToken(a.getToken());
|
||||
configStorage.setAesKey(a.getAesKey());
|
||||
return configStorage;
|
||||
}).collect(Collectors.toMap(WxMpDefaultConfigImpl::getAppId, a -> a, (o, n) -> o)));
|
||||
return service;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WxMpMessageRouter messageRouter(WxMpService wxMpService) {
|
||||
final WxMpMessageRouter newRouter = new WxMpMessageRouter(wxMpService);
|
||||
|
||||
// 记录所有事件的日志 (异步执行)
|
||||
newRouter.rule().handler(this.logHandler).next();
|
||||
|
||||
// 接收客服会话管理事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(KF_CREATE_SESSION)
|
||||
.handler(this.kfSessionHandler).end();
|
||||
newRouter.rule().async(false).msgType(EVENT).event(KF_CLOSE_SESSION)
|
||||
.handler(this.kfSessionHandler).end();
|
||||
newRouter.rule().async(false).msgType(EVENT).event(KF_SWITCH_SESSION)
|
||||
.handler(this.kfSessionHandler).end();
|
||||
|
||||
// 门店审核事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(POI_CHECK_NOTIFY).handler(this.storeCheckNotifyHandler).end();
|
||||
|
||||
// 自定义菜单事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(EventType.CLICK).handler(this.menuHandler).end();
|
||||
|
||||
// 点击菜单连接事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(EventType.VIEW).handler(this.nullHandler).end();
|
||||
|
||||
// 关注事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(SUBSCRIBE).handler(this.subscribeHandler).end();
|
||||
|
||||
// 取消关注事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(UNSUBSCRIBE).handler(this.unsubscribeHandler).end();
|
||||
|
||||
// 上报地理位置事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(EventType.LOCATION).handler(this.locationHandler).end();
|
||||
|
||||
// 接收地理位置消息
|
||||
newRouter.rule().async(false).msgType(XmlMsgType.LOCATION).handler(this.locationHandler).end();
|
||||
|
||||
// 扫码事件
|
||||
newRouter.rule().async(false).msgType(EVENT).event(EventType.SCAN).handler(this.scanHandler).end();
|
||||
|
||||
// 默认
|
||||
newRouter.rule().async(false).handler(this.msgHandler).end();
|
||||
|
||||
return newRouter;
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.config;
|
||||
|
||||
import com.rymcu.forest.wx.mp.utils.JsonUtils;
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* wechat mp properties
|
||||
*
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "wx.mp")
|
||||
public class WxMpProperties {
|
||||
private List<MpConfig> configs;
|
||||
|
||||
@Data
|
||||
public static class MpConfig {
|
||||
/**
|
||||
* 设置微信公众号的appid
|
||||
*/
|
||||
private String appId;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的app secret
|
||||
*/
|
||||
private String secret;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的token
|
||||
*/
|
||||
private String token;
|
||||
|
||||
/**
|
||||
* 设置微信公众号的EncodingAESKey
|
||||
*/
|
||||
private String aesKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return JsonUtils.toJson(this);
|
||||
}
|
||||
}
|
@ -1,133 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.controller;
|
||||
|
||||
import com.rymcu.forest.wx.mp.service.WxMenuService;
|
||||
import lombok.AllArgsConstructor;
|
||||
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.api.WxMpService;
|
||||
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 javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.MenuButtonType;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/wx/menu/{appId}")
|
||||
public class WxMenuController {
|
||||
private final WxMpService wxService;
|
||||
@Resource
|
||||
private WxMenuService wxMenuService;
|
||||
/**
|
||||
* <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 this.wxService.switchoverTo(appId).getMenuService().menuCreate(menu);
|
||||
}
|
||||
|
||||
@GetMapping("/create")
|
||||
public String menuCreateSample(@PathVariable String appId) throws WxErrorException, IOException {
|
||||
this.wxService.switchover(appId);
|
||||
return this.wxService.getMenuService().menuCreate(wxMenuService.getMenus());
|
||||
}
|
||||
|
||||
/**
|
||||
* <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("/createByJson")
|
||||
public String menuCreate(@PathVariable String appId, @RequestBody String json) throws WxErrorException {
|
||||
return this.wxService.switchoverTo(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 {
|
||||
this.wxService.switchoverTo(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 {
|
||||
this.wxService.switchoverTo(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 this.wxService.switchoverTo(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 this.wxService.switchoverTo(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 this.wxService.switchoverTo(appId).getMenuService().getSelfMenuInfo();
|
||||
}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.controller;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageRouter;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Slf4j
|
||||
@AllArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/wx/portal/{appId}")
|
||||
public class WxPortalController {
|
||||
private final WxMpService wxService;
|
||||
private final WxMpMessageRouter messageRouter;
|
||||
|
||||
@GetMapping(produces = "text/plain;charset=utf-8")
|
||||
public String authGet(@PathVariable String appId,
|
||||
@RequestParam(name = "signature", required = false) String signature,
|
||||
@RequestParam(name = "timestamp", required = false) String timestamp,
|
||||
@RequestParam(name = "nonce", required = false) String nonce,
|
||||
@RequestParam(name = "echostr", required = false) String echostr) {
|
||||
|
||||
log.info("\n接收到来自微信服务器的认证消息:[{}, {}, {}, {}]", signature,
|
||||
timestamp, nonce, echostr);
|
||||
if (StringUtils.isAnyBlank(signature, timestamp, nonce, echostr)) {
|
||||
throw new IllegalArgumentException("请求参数非法,请核实!");
|
||||
}
|
||||
|
||||
if (!this.wxService.switchover(appId)) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appId));
|
||||
}
|
||||
|
||||
if (wxService.checkSignature(timestamp, nonce, signature)) {
|
||||
return echostr;
|
||||
}
|
||||
|
||||
return "非法请求";
|
||||
}
|
||||
|
||||
@PostMapping(produces = "application/xml; charset=UTF-8")
|
||||
public String post(@PathVariable String appId,
|
||||
@RequestBody String requestBody,
|
||||
@RequestParam("signature") String signature,
|
||||
@RequestParam("timestamp") String timestamp,
|
||||
@RequestParam("nonce") String nonce,
|
||||
@RequestParam("openid") String openid,
|
||||
@RequestParam(name = "encrypt_type", required = false) String encType,
|
||||
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
|
||||
log.info("\n接收微信请求:[openid=[{}], [signature=[{}], encType=[{}], msgSignature=[{}],"
|
||||
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
|
||||
openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
|
||||
|
||||
if (!this.wxService.switchover(appId)) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应appid=[%s]的配置,请核实!", appId));
|
||||
}
|
||||
|
||||
if (!wxService.checkSignature(timestamp, nonce, signature)) {
|
||||
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
|
||||
}
|
||||
|
||||
String out = null;
|
||||
if (encType == null) {
|
||||
// 明文传输的消息
|
||||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromXml(requestBody);
|
||||
WxMpXmlOutMessage outMessage = this.route(inMessage);
|
||||
if (outMessage == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
out = outMessage.toXml();
|
||||
} else if ("aes".equalsIgnoreCase(encType)) {
|
||||
// aes加密的消息
|
||||
WxMpXmlMessage inMessage = WxMpXmlMessage.fromEncryptedXml(requestBody, wxService.getWxMpConfigStorage(),
|
||||
timestamp, nonce, msgSignature);
|
||||
log.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
|
||||
WxMpXmlOutMessage outMessage = this.route(inMessage);
|
||||
if (outMessage == null) {
|
||||
return "";
|
||||
}
|
||||
|
||||
out = outMessage.toEncryptedXml(wxService.getWxMpConfigStorage());
|
||||
}
|
||||
|
||||
log.debug("\n组装回复信息:{}", out);
|
||||
return out;
|
||||
}
|
||||
|
||||
private WxMpXmlOutMessage route(WxMpXmlMessage message) {
|
||||
try {
|
||||
return this.messageRouter.route(message);
|
||||
} catch (Exception e) {
|
||||
log.error("路由消息时出现异常!", e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.controller;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import me.chanjar.weixin.common.bean.WxOAuth2UserInfo;
|
||||
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
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 Edward
|
||||
*/
|
||||
@AllArgsConstructor
|
||||
@Controller
|
||||
@RequestMapping("/wx/redirect/{appId}")
|
||||
public class WxRedirectController {
|
||||
private final WxMpService wxService;
|
||||
|
||||
@RequestMapping("/greet")
|
||||
public String greetUser(@PathVariable String appId, @RequestParam String code, ModelMap map) {
|
||||
if (!this.wxService.switchover(appId)) {
|
||||
throw new IllegalArgumentException(String.format("未找到对应appId=[%s]的配置,请核实!", appId));
|
||||
}
|
||||
|
||||
try {
|
||||
WxOAuth2AccessToken accessToken = wxService.getOAuth2Service().getAccessToken(code);
|
||||
WxOAuth2UserInfo user = wxService.getOAuth2Service().getUserInfo(accessToken, null);
|
||||
map.put("user", user);
|
||||
} catch (WxErrorException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
return "greet_user";
|
||||
}
|
||||
}
|
@ -1,77 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.controller;
|
||||
|
||||
import com.rymcu.forest.service.WxUserService;
|
||||
import com.rymcu.forest.util.ContextHolderUtils;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
import me.chanjar.weixin.common.bean.WxJsapiSignature;
|
||||
import me.chanjar.weixin.common.bean.oauth2.WxOAuth2AccessToken;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.util.http.URIUtil;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.result.WxMpUser;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author ronger
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/wx/oauth/{appId}")
|
||||
public class WxoAuthController {
|
||||
|
||||
@Resource
|
||||
private WxMpService wxMpService;
|
||||
@Resource
|
||||
private WxUserService wxUserService;
|
||||
|
||||
@Value("${resource.domain}")
|
||||
private String domain;
|
||||
|
||||
@Value("${server.servlet.context-path}")
|
||||
private String contextPath;
|
||||
|
||||
@GetMapping
|
||||
public String wxAuth(@PathVariable String appId, @RequestParam(name = "redirectUrl") String redirectUrl) {
|
||||
StringBuilder baseUrl;
|
||||
wxMpService.switchoverTo(appId);
|
||||
// 测试号
|
||||
if ("wxa49093339a5a822b".equals(appId)) {
|
||||
baseUrl = new StringBuilder("http://1wx.rymcu.com").append(contextPath);
|
||||
} else {
|
||||
baseUrl = new StringBuilder(domain).append(contextPath);
|
||||
}
|
||||
StringBuilder accessTokenUrl = baseUrl.append("/wx/oauth/" + appId + "/getAccessToken?redirectUrl=").append(URIUtil.encodeURIComponent(redirectUrl));
|
||||
String oauth2Url = wxMpService.getOAuth2Service().buildAuthorizationUrl(accessTokenUrl.toString(), WxConsts.OAuth2Scope.SNSAPI_USERINFO, null);
|
||||
|
||||
return "redirect:" + oauth2Url;
|
||||
}
|
||||
|
||||
@GetMapping("getAccessToken")
|
||||
public String getAccessToken(@PathVariable String appId, @RequestParam(name = "code") String code, @RequestParam(name = "redirectUrl") String redirectUrl) throws Exception {
|
||||
wxMpService.switchoverTo(appId);
|
||||
WxOAuth2AccessToken oAuth2AccessToken = wxMpService.getOAuth2Service().getAccessToken(code);
|
||||
boolean valid = wxMpService.getOAuth2Service().validateAccessToken(oAuth2AccessToken);
|
||||
if (!valid) {
|
||||
throw new Exception("无权限");
|
||||
}
|
||||
|
||||
WxMpUser wxMpUser = wxMpService.getUserService().userInfo(oAuth2AccessToken.getOpenId());
|
||||
wxUserService.saveUser(wxMpUser, appId);
|
||||
ContextHolderUtils.getSession2().setAttribute("wxUser", wxMpUser);
|
||||
return "redirect:" + redirectUrl;
|
||||
}
|
||||
|
||||
@GetMapping("validJs")
|
||||
@ResponseBody
|
||||
public WxJsapiSignature validJs(String url) throws WxErrorException {
|
||||
return wxMpService.createJsapiSignature(url);
|
||||
}
|
||||
|
||||
@GetMapping("t")
|
||||
public String reOauth() {
|
||||
return "wx/oauth";
|
||||
}
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
package com.rymcu.forest.wx.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";
|
||||
}
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.rymcu.forest.wx.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")
|
||||
);
|
||||
}
|
||||
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
public abstract class AbstractHandler implements WxMpMessageHandler {
|
||||
protected Logger logger = LoggerFactory.getLogger(getClass());
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class KfSessionHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
//TODO 对会话做处理
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,44 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import com.rymcu.forest.wx.mp.builder.TextBuilder;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class LocationHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
if (wxMessage.getMsgType().equals(XmlMsgType.LOCATION)) {
|
||||
//TODO 接收处理用户发送的地理位置消息
|
||||
try {
|
||||
String content = "感谢反馈,您的的地理位置已收到!";
|
||||
return new TextBuilder().build(content, wxMessage, null);
|
||||
} catch (Exception e) {
|
||||
this.logger.error("位置消息接收处理失败", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//上报地理位置事件
|
||||
this.logger.info("上报地理位置,纬度 : {},经度 : {},精度 : {}",
|
||||
wxMessage.getLatitude(), wxMessage.getLongitude(), String.valueOf(wxMessage.getPrecision()));
|
||||
|
||||
//TODO 可以将用户地理位置信息保存到本地数据库,以便以后使用
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import com.rymcu.forest.wx.mp.utils.JsonUtils;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class LogHandler extends AbstractHandler {
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
this.logger.info("\n接收到请求消息,内容:{}", JsonUtils.toJson(wxMessage));
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,35 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.EventType;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class MenuHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService weixinService,
|
||||
WxSessionManager sessionManager) {
|
||||
String msg = String.format("type:%s, event:%s, key:%s",
|
||||
wxMessage.getMsgType(), wxMessage.getEvent(),
|
||||
wxMessage.getEventKey());
|
||||
if (EventType.VIEW.equals(wxMessage.getEvent())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return WxMpXmlOutMessage.TEXT().content(msg)
|
||||
.fromUser(wxMessage.getToUser()).toUser(wxMessage.getFromUser())
|
||||
.build();
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import com.rymcu.forest.wx.mp.builder.TextBuilder;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static me.chanjar.weixin.common.api.WxConsts.XmlMsgType;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class MsgHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
|
||||
if (!wxMessage.getMsgType().equals(XmlMsgType.EVENT)) {
|
||||
//TODO 可以选择将消息保存到本地
|
||||
}
|
||||
|
||||
if (wxMessage == null || StringUtils.isBlank(wxMessage.getContent())) {
|
||||
return WxMpXmlOutMessage.TRANSFER_CUSTOMER_SERVICE()
|
||||
.fromUser(wxMessage.getToUser())
|
||||
.toUser(wxMessage.getFromUser()).build();
|
||||
}
|
||||
|
||||
logger.info("\n接收到 {} 公众号请求消息,内容:{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMessage);
|
||||
|
||||
|
||||
String content = "我们已经收到您的留言,稍后客服将会联系您!";
|
||||
|
||||
return new TextBuilder().build(content, wxMessage, wxMpService);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class NullHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlMessage;
|
||||
import me.chanjar.weixin.mp.bean.message.WxMpXmlOutMessage;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class ScanHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMpXmlMessage, Map<String, Object> map,
|
||||
WxMpService wxMpService, WxSessionManager wxSessionManager) throws WxErrorException {
|
||||
// 扫码事件处理
|
||||
return null;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 门店审核事件处理
|
||||
*
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class StoreCheckNotifyHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
// TODO 处理门店审核事件
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,71 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import com.rymcu.forest.wx.mp.builder.TextBuilder;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.result.WxMpUser;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class SubscribeHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService weixinService,
|
||||
WxSessionManager sessionManager) throws WxErrorException {
|
||||
|
||||
this.logger.info("新关注用户 OPENID: " + wxMessage.getFromUser());
|
||||
|
||||
// 获取微信用户基本信息
|
||||
try {
|
||||
WxMpUser userWxInfo = weixinService.getUserService()
|
||||
.userInfo(wxMessage.getFromUser(), null);
|
||||
if (userWxInfo != null) {
|
||||
// TODO 可以添加关注用户到本地数据库
|
||||
}
|
||||
} catch (WxErrorException e) {
|
||||
if (e.getError().getErrorCode() == 48001) {
|
||||
this.logger.info("该公众号没有获取用户信息权限!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WxMpXmlOutMessage responseResult = null;
|
||||
try {
|
||||
responseResult = this.handleSpecial(wxMessage);
|
||||
} catch (Exception e) {
|
||||
this.logger.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
if (responseResult != null) {
|
||||
return responseResult;
|
||||
}
|
||||
|
||||
try {
|
||||
return new TextBuilder().build("感谢关注", wxMessage, weixinService);
|
||||
} catch (Exception e) {
|
||||
this.logger.error(e.getMessage(), e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理特殊请求,比如如果是扫码进来的,可以做相应处理
|
||||
*/
|
||||
private WxMpXmlOutMessage handleSpecial(WxMpXmlMessage wxMessage)
|
||||
throws Exception {
|
||||
//TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.handler;
|
||||
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
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.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Binary Wang(https://github.com/binarywang)
|
||||
*/
|
||||
@Component
|
||||
public class UnsubscribeHandler extends AbstractHandler {
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage,
|
||||
Map<String, Object> context, WxMpService wxMpService,
|
||||
WxSessionManager sessionManager) {
|
||||
String openId = wxMessage.getFromUser();
|
||||
this.logger.info("取消关注用户 OPENID: " + openId);
|
||||
// TODO 可以更新本地数据库为取消关注状态
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.service;
|
||||
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author ronger
|
||||
*/
|
||||
public interface WxMenuService {
|
||||
/**
|
||||
* 获取公众号菜单配置
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
WxMenu getMenus() throws IOException;
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.service.impl;
|
||||
|
||||
import com.rymcu.forest.wx.mp.service.WxMenuService;
|
||||
import me.chanjar.weixin.common.bean.menu.WxMenu;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Scanner;
|
||||
|
||||
/**
|
||||
* @author ronger
|
||||
*/
|
||||
@Service
|
||||
public class WxMenuServiceImpl implements WxMenuService {
|
||||
@Value("classpath:wxMpMenus.json")
|
||||
private Resource menuResource;
|
||||
|
||||
@Override
|
||||
public WxMenu getMenus() throws IOException {
|
||||
File file = menuResource.getFile();
|
||||
String menuJson = this.jsonRead(file);
|
||||
WxMenu wxMenu = WxMenu.fromJson(menuJson);
|
||||
return wxMenu;
|
||||
}
|
||||
|
||||
private String jsonRead(File file) {
|
||||
Scanner scanner = null;
|
||||
StringBuilder buffer = new StringBuilder();
|
||||
try {
|
||||
scanner = new Scanner(file, "utf-8");
|
||||
while (scanner.hasNextLine()) {
|
||||
buffer.append(scanner.nextLine());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
} finally {
|
||||
if (scanner != null) {
|
||||
scanner.close();
|
||||
}
|
||||
}
|
||||
return buffer.toString();
|
||||
}
|
||||
}
|
@ -1,9 +0,0 @@
|
||||
package com.rymcu.forest.wx.mp.utils;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
|
||||
public class JsonUtils {
|
||||
public static String toJson(Object obj) {
|
||||
return JSONObject.toJSONString(obj);
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
package com.rymcu.forest.wx.open.config;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/007gzs">007</a>
|
||||
*/
|
||||
@Getter
|
||||
@Setter
|
||||
@ConfigurationProperties(prefix = "wx.open")
|
||||
public class WxOpenProperties {
|
||||
/**
|
||||
* 设置微信三方平台的appid
|
||||
*/
|
||||
private String componentAppId;
|
||||
|
||||
/**
|
||||
* 设置微信三方平台的app secret
|
||||
*/
|
||||
private String componentSecret;
|
||||
|
||||
/**
|
||||
* 设置微信三方平台的token
|
||||
*/
|
||||
private String componentToken;
|
||||
|
||||
/**
|
||||
* 设置微信三方平台的EncodingAESKey
|
||||
*/
|
||||
private String componentAesKey;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return ToStringBuilder.reflectionToString(this,
|
||||
ToStringStyle.MULTI_LINE_STYLE);
|
||||
}
|
||||
}
|
@ -1,78 +0,0 @@
|
||||
package com.rymcu.forest.wx.open.controller;
|
||||
|
||||
import com.rymcu.forest.wx.open.handler.WxOpenServiceHandler;
|
||||
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.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/007gzs">007</a>
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/wx/open/auth")
|
||||
public class WxOpenApiController {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Resource
|
||||
private WxOpenServiceHandler wxOpenServiceHandler;
|
||||
|
||||
@GetMapping("/goto_auth_url_show")
|
||||
@ResponseBody
|
||||
public String gotoPreAuthUrlShow(){
|
||||
return "<a href='goto_auth_url'>go</a>";
|
||||
}
|
||||
|
||||
@GetMapping("/goto_auth_url")
|
||||
public void gotoPreAuthUrl(HttpServletRequest request, HttpServletResponse response){
|
||||
System.out.println("===================================Host:");
|
||||
System.out.println(request.getHeader("host"));
|
||||
String host = request.getHeader("host");
|
||||
String url = "http://"+host+"/open/auth/jump";
|
||||
try {
|
||||
url = wxOpenServiceHandler.getWxOpenComponentService().getPreAuthUrl(url);
|
||||
// 添加来源,解决302跳转来源丢失的问题
|
||||
response.addHeader("Referer", "http://"+host);
|
||||
response.sendRedirect(url);
|
||||
} catch (WxErrorException | IOException e) {
|
||||
logger.error("gotoPreAuthUrl", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/jump")
|
||||
@ResponseBody
|
||||
public WxOpenQueryAuthResult jump(@RequestParam("auth_code") String authorizationCode){
|
||||
try {
|
||||
WxOpenQueryAuthResult queryAuthResult = wxOpenServiceHandler.getWxOpenComponentService().getQueryAuth(authorizationCode);
|
||||
logger.info("getQueryAuth", queryAuthResult);
|
||||
return queryAuthResult;
|
||||
} catch (WxErrorException e) {
|
||||
logger.error("gotoPreAuthUrl", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@GetMapping("/get_auth_info")
|
||||
@ResponseBody
|
||||
public WxOpenAuthorizerInfoResult getAuthInfo(@RequestParam String appId){
|
||||
try {
|
||||
return wxOpenServiceHandler.getWxOpenComponentService().getAuthorizerInfo(appId);
|
||||
} catch (WxErrorException e) {
|
||||
logger.error("getAuthInfo", e);
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,122 +0,0 @@
|
||||
package com.rymcu.forest.wx.open.controller;
|
||||
|
||||
import com.rymcu.forest.wx.open.handler.WxOpenServiceHandler;
|
||||
import me.chanjar.weixin.common.api.WxConsts;
|
||||
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.message.WxOpenXmlMessage;
|
||||
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.*;
|
||||
|
||||
/**
|
||||
* @author <a href="https://github.com/007gzs">007</a>
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/wx/notify")
|
||||
public class WxOpenNotifyController {
|
||||
private final Logger logger = LoggerFactory.getLogger(this.getClass());
|
||||
@Autowired
|
||||
protected WxOpenServiceHandler wxOpenService;
|
||||
|
||||
/**
|
||||
* 全网发布官方测试小程序 AppId
|
||||
*/
|
||||
private final static String testMiniProgramAppId = "wxd101a85aa106f53e";
|
||||
/**
|
||||
* 全网发布官方测试公众号 AppId
|
||||
*/
|
||||
private final static String testMpAppId = "wx570bc396a51b8ff8";
|
||||
private final static String TESTCOMPONENT_MSG_TYPE_TEXT = "TESTCOMPONENT_MSG_TYPE_TEXT";
|
||||
private final static String TESTCOMPONENT_MSG_TYPE_TEXT_callback = "TESTCOMPONENT_MSG_TYPE_TEXT_callback";
|
||||
|
||||
@RequestMapping("/receive_ticket")
|
||||
public Object receiveTicket(@RequestBody(required = false) String requestBody, @RequestParam("timestamp") String timestamp,
|
||||
@RequestParam("nonce") String nonce, @RequestParam("signature") String signature,
|
||||
@RequestParam(name = "encrypt_type", required = false) String encType,
|
||||
@RequestParam(name = "msg_signature", required = false) String msgSignature) {
|
||||
this.logger.info(
|
||||
"\n接收微信请求:[signature=[{}], encType=[{}], msgSignature=[{}],"
|
||||
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
|
||||
signature, encType, msgSignature, timestamp, nonce, requestBody);
|
||||
|
||||
if (!StringUtils.equalsIgnoreCase("aes", encType)
|
||||
|| !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
|
||||
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
|
||||
}
|
||||
|
||||
// aes加密的消息
|
||||
WxOpenXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedXml(requestBody,
|
||||
wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
|
||||
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
|
||||
try {
|
||||
String out = wxOpenService.getWxOpenComponentService().route(inMessage);
|
||||
this.logger.debug("\n组装回复信息:{}", out);
|
||||
} catch (WxErrorException e) {
|
||||
this.logger.error("receive_ticket", e);
|
||||
}
|
||||
|
||||
|
||||
return "success";
|
||||
}
|
||||
|
||||
@RequestMapping("/{appId}/callback")
|
||||
public Object callback(@RequestBody(required = false) String requestBody,
|
||||
@PathVariable("appId") String appId,
|
||||
@RequestParam("signature") String signature,
|
||||
@RequestParam("timestamp") String timestamp,
|
||||
@RequestParam("nonce") String nonce,
|
||||
@RequestParam("openid") String openid,
|
||||
@RequestParam("encrypt_type") String encType,
|
||||
@RequestParam("msg_signature") String msgSignature) {
|
||||
this.logger.info(
|
||||
"\n接收微信请求:[appId=[{}], openid=[{}], signature=[{}], encType=[{}], msgSignature=[{}],"
|
||||
+ " timestamp=[{}], nonce=[{}], requestBody=[\n{}\n] ",
|
||||
appId, openid, signature, encType, msgSignature, timestamp, nonce, requestBody);
|
||||
if (!StringUtils.equalsIgnoreCase("aes", encType)
|
||||
|| !wxOpenService.getWxOpenComponentService().checkSignature(timestamp, nonce, signature)) {
|
||||
throw new IllegalArgumentException("非法请求,可能属于伪造的请求!");
|
||||
}
|
||||
|
||||
String out = "";
|
||||
// aes加密的消息
|
||||
WxMpXmlMessage inMessage = WxOpenXmlMessage.fromEncryptedMpXml(requestBody,
|
||||
wxOpenService.getWxOpenConfigStorage(), timestamp, nonce, msgSignature);
|
||||
this.logger.debug("\n消息解密后内容为:\n{} ", inMessage.toString());
|
||||
// 全网发布测试用例
|
||||
if (StringUtils.equalsAnyIgnoreCase(appId, testMiniProgramAppId, testMpAppId)) {
|
||||
try {
|
||||
if (StringUtils.equals(inMessage.getMsgType(), WxConsts.XmlMsgType.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(),
|
||||
wxOpenService.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();
|
||||
wxOpenService.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();
|
||||
wxOpenService.getWxOpenComponentService().getWxMpServiceByAppid(appId).getKefuService().sendKefuMessage(kefuMessage);
|
||||
}
|
||||
} catch (WxErrorException e) {
|
||||
logger.error("callback", e);
|
||||
}
|
||||
} else {
|
||||
WxMpXmlOutMessage outMessage = wxOpenService.getWxOpenMessageRouter().route(inMessage, appId);
|
||||
if (outMessage != null) {
|
||||
out = WxOpenXmlMessage.wxMpOutXmlMessageToEncryptedXml(outMessage, wxOpenService.getWxOpenConfigStorage());
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
}
|
@ -1,67 +0,0 @@
|
||||
package com.rymcu.forest.wx.open.handler;
|
||||
|
||||
import com.rymcu.forest.config.RedisProperties;
|
||||
import com.rymcu.forest.wx.open.config.WxOpenProperties;
|
||||
import me.chanjar.weixin.open.api.impl.WxOpenInRedisConfigStorage;
|
||||
import me.chanjar.weixin.open.api.impl.WxOpenMessageRouter;
|
||||
import me.chanjar.weixin.open.api.impl.WxOpenServiceImpl;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.stereotype.Service;
|
||||
import redis.clients.jedis.JedisPool;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author ronger
|
||||
*/
|
||||
@Service
|
||||
@EnableConfigurationProperties({WxOpenProperties.class, RedisProperties.class})
|
||||
public class WxOpenServiceHandler extends WxOpenServiceImpl {
|
||||
|
||||
private Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Resource
|
||||
private WxOpenProperties wxOpenProperties;
|
||||
@Resource
|
||||
private RedisProperties redisProperties;
|
||||
private static JedisPool pool;
|
||||
private WxOpenMessageRouter wxOpenMessageRouter;
|
||||
|
||||
@PostConstruct
|
||||
public void init() {
|
||||
WxOpenInRedisConfigStorage inRedisConfigStorage = new WxOpenInRedisConfigStorage(getJedisPool());
|
||||
inRedisConfigStorage.setComponentAppId(wxOpenProperties.getComponentAppId());
|
||||
inRedisConfigStorage.setComponentAppSecret(wxOpenProperties.getComponentSecret());
|
||||
inRedisConfigStorage.setComponentToken(wxOpenProperties.getComponentToken());
|
||||
inRedisConfigStorage.setComponentAesKey(wxOpenProperties.getComponentAesKey());
|
||||
setWxOpenConfigStorage(inRedisConfigStorage);
|
||||
wxOpenMessageRouter = new WxOpenMessageRouter(this);
|
||||
wxOpenMessageRouter.rule().handler((wxMpXmlMessage, map, wxMpService, wxSessionManager) -> {
|
||||
logger.info("\n接收到 {} 公众号请求消息,内容:{}", wxMpService.getWxMpConfigStorage().getAppId(), wxMpXmlMessage);
|
||||
return null;
|
||||
}).next();
|
||||
}
|
||||
|
||||
private JedisPool getJedisPool() {
|
||||
if (pool == null) {
|
||||
synchronized (WxOpenServiceHandler.class) {
|
||||
if (pool == null) {
|
||||
pool = new JedisPool(redisProperties, redisProperties.getHost(),
|
||||
redisProperties.getPort(), redisProperties.getConnectionTimeout(),
|
||||
redisProperties.getSoTimeout(), redisProperties.getPassword(),
|
||||
redisProperties.getDatabase(), redisProperties.getClientName(),
|
||||
redisProperties.isSsl(), redisProperties.getSslSocketFactory(),
|
||||
redisProperties.getSslParameters(), redisProperties.getHostnameVerifier());
|
||||
}
|
||||
}
|
||||
}
|
||||
return pool;
|
||||
}
|
||||
|
||||
public WxOpenMessageRouter getWxOpenMessageRouter() {
|
||||
return wxOpenMessageRouter;
|
||||
}
|
||||
}
|
@ -26,16 +26,27 @@
|
||||
</if>
|
||||
</select>
|
||||
<select id="selectBankAccount" resultMap="DTOResultMap">
|
||||
select fb.bank_name, fu.nickname as account_owner_name, fba.* from forest_bank_account fba
|
||||
join forest_bank fb on fba.id_bank = fb.id
|
||||
join forest_user fu on fba.account_owner = fu.id where fba.id = #{idBank}
|
||||
select fb.bank_name, fu.nickname as account_owner_name, fba.*
|
||||
from forest_bank_account fba
|
||||
join forest_bank fb on fba.id_bank = fb.id
|
||||
join forest_user fu on fba.account_owner = fu.id
|
||||
where fba.id = #{idBank}
|
||||
</select>
|
||||
<select id="selectMaxBankAccount" resultType="java.lang.String">
|
||||
select max(bank_account) as max_bank_account from forest_bank_account where account_type = 0
|
||||
select max(bank_account) as max_bank_account
|
||||
from forest_bank_account
|
||||
where account_type = 0
|
||||
</select>
|
||||
<select id="selectByBankAccount" resultMap="DTOResultMap">
|
||||
select fb.bank_name, ifnull(fu.nickname, '系统') as account_owner_name, fba.bank_account from forest_bank_account fba
|
||||
join forest_bank fb on fba.id_bank = fb.id
|
||||
left join forest_user fu on fba.account_owner = fu.id where fba.bank_account = #{bankAccount}
|
||||
select fb.bank_name, ifnull(fu.nickname, '系统') as account_owner_name, fba.bank_account
|
||||
from forest_bank_account fba
|
||||
join forest_bank fb on fba.id_bank = fb.id
|
||||
left join forest_user fu on fba.account_owner = fu.id
|
||||
where fba.bank_account = #{bankAccount}
|
||||
</select>
|
||||
<select id="findPersonBankAccountByIdUser" resultMap="DTOResultMap">
|
||||
select fba.*
|
||||
from forest_bank_account fba
|
||||
where fba.account_owner = #{idUser}
|
||||
</select>
|
||||
</mapper>
|
Loading…
Reference in New Issue
Block a user