Compare commits
1 Commits
develop
...
add-templa
Author | SHA1 | Date | |
---|---|---|---|
![]() |
8af53babd5 |
36
README.md
36
README.md
@@ -362,3 +362,39 @@
|
||||
|  |  |  |
|
||||
|
||||
目前已经实现登录、我的、工作台、编辑资料、头像修改、密码修改、常见问题、关于我们等基础功能。
|
||||
|
||||
### 微信公众号的模版消息对接
|
||||
|
||||
`yudao-module-mp` 模块现已支持微信公众号的模版消息对接功能。以下是使用说明和示例:
|
||||
|
||||
#### 使用说明
|
||||
|
||||
1. 确保在 `pom.xml` 文件中取消注释 `yudao-module-mp` 模块,以便将其包含在构建过程中。
|
||||
2. 在 `yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/message` 目录下,定义 `MpTemplateMessageService` 接口,并在同一目录下实现该接口。
|
||||
3. 在 `yudao-module-mp/yudao-module-mp-biz/src/main/java/cn/iocoder/yudao/module/mp/service/handler/message` 目录下,添加 `TemplateMessageHandler` 类以处理传入的模版消息。
|
||||
|
||||
#### 示例
|
||||
|
||||
以下是一个发送模版消息的示例:
|
||||
|
||||
```java
|
||||
@Service
|
||||
public class MpTemplateMessageServiceImpl implements MpTemplateMessageService {
|
||||
|
||||
@Resource
|
||||
private MpServiceFactory mpServiceFactory;
|
||||
|
||||
@Override
|
||||
public void sendTemplateMessage(WxMpTemplateMessage templateMessage) {
|
||||
WxMpService mpService = mpServiceFactory.getRequiredMpService(templateMessage.getAppid());
|
||||
try {
|
||||
mpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
|
||||
} catch (WxErrorException e) {
|
||||
log.error("[sendTemplateMessage][发送模板消息失败,templateMessage={}]", templateMessage, e);
|
||||
throw new RuntimeException("发送模板消息失败", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
更多详细信息,请参考项目中的相关代码和文档。
|
||||
|
2
pom.xml
2
pom.xml
@@ -18,7 +18,7 @@
|
||||
<!-- <module>yudao-module-member</module>-->
|
||||
<!-- <module>yudao-module-bpm</module>-->
|
||||
<!-- <module>yudao-module-report</module>-->
|
||||
<!-- <module>yudao-module-mp</module>-->
|
||||
<module>yudao-module-mp</module>
|
||||
<!-- <module>yudao-module-pay</module>-->
|
||||
<!-- <module>yudao-module-mall</module>-->
|
||||
<!-- <module>yudao-module-crm</module>-->
|
||||
|
@@ -3,15 +3,11 @@ package cn.iocoder.yudao.framework.common.util.spring;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import org.aspectj.lang.JoinPoint;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.core.DefaultParameterNameDiscoverer;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ExpressionParser;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
@@ -90,20 +86,4 @@ public class SpringExpressionUtils {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 Bean 工厂,解析 EL 表达式的结果
|
||||
*
|
||||
* @param expressionString EL 表达式
|
||||
* @return 执行界面
|
||||
*/
|
||||
public static Object parseExpression(String expressionString) {
|
||||
if (StrUtil.isBlank(expressionString)) {
|
||||
return null;
|
||||
}
|
||||
Expression expression = EXPRESSION_PARSER.parseExpression(expressionString);
|
||||
StandardEvaluationContext context = new StandardEvaluationContext();
|
||||
context.setBeanResolver(new BeanFactoryResolver(SpringUtil.getApplicationContext()));
|
||||
return expression.getValue(context);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -185,6 +185,10 @@ public interface BaseMapperX<T> extends MPJBaseMapper<T> {
|
||||
return Db.updateBatchById(entities, size);
|
||||
}
|
||||
|
||||
default boolean insertOrUpdate(T entity) {
|
||||
return Db.saveOrUpdate(entity);
|
||||
}
|
||||
|
||||
default Boolean insertOrUpdateBatch(Collection<T> collection) {
|
||||
return Db.saveOrUpdateBatch(collection);
|
||||
}
|
||||
|
@@ -32,11 +32,6 @@
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<scope>provided</scope> <!-- 解决工具类 SpringExpressionUtils 加载的时候访问不到 org.aspectj.lang.JoinPoint 问题 -->
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
|
@@ -1,7 +1,5 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.core.base.handler;
|
||||
|
||||
import cn.hutool.core.util.ReflectUtil;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
@@ -20,21 +18,4 @@ public interface DesensitizationHandler<T extends Annotation> {
|
||||
*/
|
||||
String desensitize(String origin, T annotation);
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏的 Spring EL 表达式
|
||||
*
|
||||
* 如果返回 true 则跳过脱敏
|
||||
*
|
||||
* @param annotation 注解信息
|
||||
* @return 是否禁用脱敏的 Spring EL 表达式
|
||||
*/
|
||||
default String getDisable(T annotation) {
|
||||
// 约定:默认就是 enable() 属性。如果不符合,子类重写
|
||||
try {
|
||||
return (String) ReflectUtil.invoke(annotation, "disable");
|
||||
} catch (Exception ex) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -33,12 +33,4 @@ public @interface EmailDesensitize {
|
||||
* 比如:example@gmail.com 脱敏之后为 e****@gmail.com
|
||||
*/
|
||||
String replacer() default "$1****$2";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -35,12 +35,4 @@ public @interface RegexDesensitize {
|
||||
* 脱敏后字符串 ******456789
|
||||
*/
|
||||
String replacer() default "******";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.core.regex.handler;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
|
||||
import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -15,13 +14,6 @@ public abstract class AbstractRegexDesensitizationHandler<T extends Annotation>
|
||||
|
||||
@Override
|
||||
public String desensitize(String origin, T annotation) {
|
||||
// 1. 判断是否禁用脱敏
|
||||
Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation));
|
||||
if (Boolean.TRUE.equals(disable)) {
|
||||
return origin;
|
||||
}
|
||||
|
||||
// 2. 执行脱敏
|
||||
String regex = getRegex(annotation);
|
||||
String replacer = getReplacer(annotation);
|
||||
return origin.replaceAll(regex, replacer);
|
||||
|
@@ -18,10 +18,4 @@ public class DefaultRegexDesensitizationHandler extends AbstractRegexDesensitiza
|
||||
String getReplacer(RegexDesensitize annotation) {
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisable(RegexDesensitize annotation) {
|
||||
return annotation.disable();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -37,11 +37,4 @@ public @interface BankCardDesensitize {
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -37,11 +37,4 @@ public @interface CarLicenseDesensitize {
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -37,11 +37,4 @@ public @interface ChineseNameDesensitize {
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -37,11 +37,4 @@ public @interface FixedPhoneDesensitize {
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -37,11 +37,4 @@ public @interface IdCardDesensitize {
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -37,11 +37,4 @@ public @interface MobileDesensitize {
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -39,11 +39,4 @@ public @interface PasswordDesensitize {
|
||||
*/
|
||||
String replacer() default "*";
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -40,12 +40,4 @@ public @interface SliderDesensitize {
|
||||
* 前缀保留长度
|
||||
*/
|
||||
int prefixKeep() default 0;
|
||||
|
||||
/**
|
||||
* 是否禁用脱敏
|
||||
*
|
||||
* 支持 Spring EL 表达式,如果返回 true 则跳过脱敏
|
||||
*/
|
||||
String disable() default "";
|
||||
|
||||
}
|
||||
|
@@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.framework.desensitize.core.slider.handler;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.util.spring.SpringExpressionUtils;
|
||||
import cn.iocoder.yudao.framework.desensitize.core.base.handler.DesensitizationHandler;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
@@ -15,13 +14,6 @@ public abstract class AbstractSliderDesensitizationHandler<T extends Annotation>
|
||||
|
||||
@Override
|
||||
public String desensitize(String origin, T annotation) {
|
||||
// 1. 判断是否禁用脱敏
|
||||
Object disable = SpringExpressionUtils.parseExpression(getDisable(annotation));
|
||||
if (Boolean.FALSE.equals(disable)) {
|
||||
return origin;
|
||||
}
|
||||
|
||||
// 2. 执行脱敏
|
||||
int prefixKeep = getPrefixKeep(annotation);
|
||||
int suffixKeep = getSuffixKeep(annotation);
|
||||
String replacer = getReplacer(annotation);
|
||||
|
@@ -24,9 +24,4 @@ public class BankCardDesensitization extends AbstractSliderDesensitizationHandle
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisable(BankCardDesensitize annotation) {
|
||||
return "";
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.CarLicenseD
|
||||
* @author gaibu
|
||||
*/
|
||||
public class CarLicenseDesensitization extends AbstractSliderDesensitizationHandler<CarLicenseDesensitize> {
|
||||
|
||||
@Override
|
||||
Integer getPrefixKeep(CarLicenseDesensitize annotation) {
|
||||
return annotation.prefixKeep();
|
||||
@@ -23,10 +22,4 @@ public class CarLicenseDesensitization extends AbstractSliderDesensitizationHand
|
||||
String getReplacer(CarLicenseDesensitize annotation) {
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDisable(CarLicenseDesensitize annotation) {
|
||||
return annotation.disable();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.SliderDesen
|
||||
* @author gaibu
|
||||
*/
|
||||
public class DefaultDesensitizationHandler extends AbstractSliderDesensitizationHandler<SliderDesensitize> {
|
||||
|
||||
@Override
|
||||
Integer getPrefixKeep(SliderDesensitize annotation) {
|
||||
return annotation.prefixKeep();
|
||||
@@ -23,5 +22,4 @@ public class DefaultDesensitizationHandler extends AbstractSliderDesensitization
|
||||
String getReplacer(SliderDesensitize annotation) {
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -8,7 +8,6 @@ import cn.iocoder.yudao.framework.desensitize.core.slider.annotation.FixedPhoneD
|
||||
* @author gaibu
|
||||
*/
|
||||
public class FixedPhoneDesensitization extends AbstractSliderDesensitizationHandler<FixedPhoneDesensitize> {
|
||||
|
||||
@Override
|
||||
Integer getPrefixKeep(FixedPhoneDesensitize annotation) {
|
||||
return annotation.prefixKeep();
|
||||
@@ -23,5 +22,4 @@ public class FixedPhoneDesensitization extends AbstractSliderDesensitizationHand
|
||||
String getReplacer(FixedPhoneDesensitize annotation) {
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -22,5 +22,4 @@ public class IdCardDesensitization extends AbstractSliderDesensitizationHandler<
|
||||
String getReplacer(IdCardDesensitize annotation) {
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -23,5 +23,4 @@ public class MobileDesensitization extends AbstractSliderDesensitizationHandler<
|
||||
String getReplacer(MobileDesensitize annotation) {
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -22,5 +22,4 @@ public class PasswordDesensitization extends AbstractSliderDesensitizationHandle
|
||||
String getReplacer(PasswordDesensitize annotation) {
|
||||
return annotation.replacer();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -0,0 +1,35 @@
|
||||
package cn.iocoder.yudao.module.mp.service.handler.message;
|
||||
|
||||
import cn.iocoder.yudao.module.mp.framework.mp.core.context.MpContextHolder;
|
||||
import cn.iocoder.yudao.module.mp.service.message.MpTemplateMessageService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.session.WxSessionManager;
|
||||
import me.chanjar.weixin.mp.api.WxMpMessageHandler;
|
||||
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 jakarta.annotation.Resource;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 模板消息的事件处理器
|
||||
*/
|
||||
@Component
|
||||
@Slf4j
|
||||
public class TemplateMessageHandler implements WxMpMessageHandler {
|
||||
|
||||
@Resource
|
||||
private MpTemplateMessageService mpTemplateMessageService;
|
||||
|
||||
@Override
|
||||
public WxMpXmlOutMessage handle(WxMpXmlMessage wxMessage, Map<String, Object> context,
|
||||
WxMpService wxMpService, WxSessionManager sessionManager) {
|
||||
log.info("[handle][接收到模板消息,内容:{}]", wxMessage);
|
||||
// 处理模板消息的逻辑
|
||||
mpTemplateMessageService.sendTemplateMessage(MpContextHolder.getAppId(), wxMessage);
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
package cn.iocoder.yudao.module.mp.service.message;
|
||||
|
||||
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
|
||||
|
||||
/**
|
||||
* 公众号模板消息 Service 接口
|
||||
*/
|
||||
public interface MpTemplateMessageService {
|
||||
|
||||
/**
|
||||
* 发送模板消息
|
||||
*
|
||||
* @param templateMessage 模板消息
|
||||
*/
|
||||
void sendTemplateMessage(WxMpTemplateMessage templateMessage);
|
||||
|
||||
}
|
@@ -0,0 +1,32 @@
|
||||
package cn.iocoder.yudao.module.mp.service.message;
|
||||
|
||||
import cn.iocoder.yudao.module.mp.framework.mp.core.MpServiceFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import me.chanjar.weixin.common.error.WxErrorException;
|
||||
import me.chanjar.weixin.mp.api.WxMpService;
|
||||
import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import jakarta.annotation.Resource;
|
||||
|
||||
@Service
|
||||
@Validated
|
||||
@Slf4j
|
||||
public class MpTemplateMessageServiceImpl implements MpTemplateMessageService {
|
||||
|
||||
@Resource
|
||||
private MpServiceFactory mpServiceFactory;
|
||||
|
||||
@Override
|
||||
public void sendTemplateMessage(WxMpTemplateMessage templateMessage) {
|
||||
WxMpService mpService = mpServiceFactory.getRequiredMpService(templateMessage.getAppid());
|
||||
try {
|
||||
mpService.getTemplateMsgService().sendTemplateMsg(templateMessage);
|
||||
} catch (WxErrorException e) {
|
||||
log.error("[sendTemplateMessage][发送模板消息失败,templateMessage={}]", templateMessage, e);
|
||||
throw new RuntimeException("发送模板消息失败", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user