烽火云长椿街3.25 2:05

master
DanielDeng 3 months ago
parent 6dcef0d351
commit ce800117f6

@ -7,5 +7,7 @@
<file url="file://$PROJECT_DIR$/beacon-common/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/beacon-strategy/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/beacon-test/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/java" charset="UTF-8" />
<file url="file://$PROJECT_DIR$/src/main/resources" charset="UTF-8" />
</component>
</project>

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
/**
* @author dch
@ -88,6 +89,7 @@ public class SmsController {
//============================基于雪花算法生成唯一标识sequenceId=================================
submit.setSequenceId(snowFlakeUtil.nextId());
submit.setSendTime(LocalDateTime.now());
//=========================发送到MQ交给策略模块处理=========================================
rabbitTemplate.convertAndSend(RabbitMQConstants.SMS_PRE_SEND,submit,new CorrelationData(submit.getSequenceId().toString()));

@ -9,9 +9,9 @@ spring:
cloud:
nacos:
discovery:
server-addr: 172.20.10.2:8848
server-addr: 192.168.43.132:8848
# nacos配置中心地址:
config:
server-addr: 172.20.10.2:8848
server-addr: 192.168.43.132:8848
file-extension: yml
# beacon-api-dev.yml

@ -3,6 +3,7 @@ package com.mashibing.cache.controller;
import com.msb.framework.redis.RedisClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
@ -18,47 +19,131 @@ public class CacheController {
@Autowired
private RedisClient redisClient;
@PostMapping(value = "/cache/hmset/{key}")
public void hmset(@PathVariable(value = "key")String key, @RequestBody Map<String,Object> map){
log.info("【缓存模块】 hmset方法存储key = {}存储value = {}",key,map);
redisClient.hSet(key,map);
public void hmset(@PathVariable(value = "key") String key, @RequestBody Map<String, Object> map) {
log.info("【缓存模块】 hmset方法存储key = {}存储value = {}", key, map);
redisClient.hSet(key, map);
}
@PostMapping(value = "/cache/set/{key}")
public void set(@PathVariable(value = "key")String key, @RequestParam(value = "value")Object value){
log.info("【缓存模块】 set方法存储key = {}存储value = {}",key,value);
redisClient.set(key,value);
public void set(@PathVariable(value = "key") String key, @RequestParam(value = "value") Object value) {
log.info("【缓存模块】 set方法存储key = {}存储value = {}", key, value);
redisClient.set(key, value);
}
@PostMapping(value = "/cache/sadd/{key}")
public void sadd(@PathVariable(value = "key")String key, @RequestBody Map<String,Object>... value){
public void sadd(@PathVariable(value = "key") String key, @RequestBody Map<String, Object>... value) {
log.info("【缓存模块】 sadd方法存储key = {}存储value = {}", key, value);
redisClient.sAdd(key,value);
redisClient.sAdd(key, value);
}
@PostMapping(value = "/cache/saddstr/{key}")
public void saddStr(@PathVariable(value = "key") String key, @RequestBody String... value) {
log.info("【缓存模块】 saddStr方法存储key = {}存储value = {}", key, value);
redisClient.sAdd(key, value);
}
@GetMapping("/cache/hgetall/{key}")
public Map hGetAll(@PathVariable(value = "key")String key){
public Map hGetAll(@PathVariable(value = "key") String key) {
log.info("【缓存模块】 hGetAll方法获取key ={} 的数据", key);
Map<String, Object> value = redisClient.hGetAll(key);
log.info("【缓存模块】 hGetAll方法获取key ={} 的数据 value = {}", key,value);
log.info("【缓存模块】 hGetAll方法获取key ={} 的数据 value = {}", key, value);
return value;
}
@GetMapping("/cache/hget/{key}/{field}")
public Object hget(@PathVariable(value = "key")String key,@PathVariable(value = "field")String field){
log.info("【缓存模块】 hget方法获取key ={}field = {}的数据", key,field);
public Object hget(@PathVariable(value = "key") String key, @PathVariable(value = "field") String field) {
log.info("【缓存模块】 hget方法获取key ={}field = {}的数据", key, field);
Object value = redisClient.hGet(key, field);
log.info("【缓存模块】 hget获取key ={}field = {} 的数据 value = {}", key,field,value);
log.info("【缓存模块】 hget获取key ={}field = {} 的数据 value = {}", key, field, value);
return value;
}
@GetMapping("/cache/smember/{key}")
public Set smember(@PathVariable(value = "key")String key){
public Set smember(@PathVariable(value = "key") String key) {
log.info("【缓存模块】 smember方法获取key ={}的数据", key);
Set<Object> values = redisClient.sMembers(key);
log.info("【缓存模块】 smember方法获取key ={} 的数据 value = {}", key,values);
log.info("【缓存模块】 smember方法获取key ={} 的数据 value = {}", key, values);
return values;
}
@GetMapping("/cache/smemberMap/{key}")
public Set smemberMap(@PathVariable(value = "key") String key) {
log.info("【缓存模块】 smemberMap方法获取key ={}的数据", key);
Set<Object> values = redisClient.sMembers(key);
log.info("【缓存模块】 smemberMap方法获取key ={} 的数据 value = {}", key, values);
return values;
}
@PostMapping("/cache/pipeline/string")
public void pipelineString(@RequestBody Map<String, String> map) {
log.info("【缓存模块】 pipelineString获取到存储的数据map的长度 ={}的数据", map.size());
redisClient.pipelined(operations -> {
for (Map.Entry<String, String> entry : map.entrySet()) {
operations.opsForValue().set(entry.getKey(), entry.getValue());
}
});
}
@GetMapping("/cache/get/{key}")
public Object getString(@PathVariable(value = "key") String key) {
log.info("【缓存模块】 get方法获取key ={}", key);
Object value = redisClient.get(key);
log.info("【缓存模块】 get方法查询key ={} 的数据 value = {}", key, value);
return value;
}
@PostMapping(value = "/cache/sinterstr/{key}/{sinterKey}")
public Set<Object> sinterStr(@PathVariable(value = "key") String key, @PathVariable String sinterKey, @RequestBody String... value) {
log.info("【缓存模块】 sinterStr的交集方法存储key = {}sinterKey = {}存储value = {}", key, sinterKey, value);
//1、 存储数据到set集合
redisClient.sAdd(key, value);
//2、 需要将key和sinterKey做交集操作并拿到返回的setRedisClient没提供(已提供),自己写的~~
Set<Object> result = redisClient.sIntersect(key, sinterKey);
//3、 将key删除
redisClient.delete(key);
//4、 返回交集结果
return result;
}
@PostMapping(value = "/cache/zadd/{key}/{score}/{member}")
public Boolean zadd(@PathVariable(value = "key") String key,
@PathVariable(value = "score") Long score,
@PathVariable(value = "member") Object member) {
log.info("【缓存模块】 zadd方法存储key = {}存储score = {}存储value = {}", key, score, member);
Boolean result = redisClient.zAdd(key, member, score);
return result;
}
@GetMapping(value = "/cache/zrangebyscorecount/{key}/{start}/{end}")
public Integer zRangeByScoreCount(@PathVariable(value = "key") String key,
@PathVariable(value = "start") Double start,
@PathVariable(value = "end") Double end) {
log.info("【缓存模块】 zRangeByScoreCount方法查询key = {},start = {},end = {}", key, start, end);
Set<ZSetOperations.TypedTuple<Object>> values = redisClient.zRangeByScore(key, start, end);
// redisTemplate.opsForZSet().rangeByScoreWithScores(key, start, end);
if (values != null) {
return values.size();
}
return 0;
}
@DeleteMapping(value = "/cache/zremove/{key}/{member}")
public void zRemove(@PathVariable(value = "key") String key, @PathVariable(value = "member") String member) {
log.info("【缓存模块】 zRemove方法删除key = {},member = {}", key, member);
redisClient.zRemove(key, member);
}
@PostMapping(value = "/cache/hincrby/{key}/{field}/{delta}")
public Long hIncrBy(@PathVariable(value = "key") String key,
@PathVariable(value = "field") String field,
@PathVariable(value = "delta") Long delta) {
log.info("【缓存模块】 hIncrBy方法自增 key = {},field = {}number = {}", key, field, delta);
Long result = redisClient.hIncrementBy(key, field, delta);
log.info("【缓存模块】 hIncrBy方法自增 key = {},field = {}number = {},剩余数值为 = {}", key, field, delta, result);
return result;
}
}

@ -22,26 +22,19 @@ public class TestController {
// 写测试 hash结构
@PostMapping("/test/set/{key}")
public String set(@PathVariable String key, @RequestBody Map map){
public String set(@PathVariable String key, @RequestBody Map map) {
// redisTemplate.opsForHash().putAll(key,map);
redisClient.hSet(key,map);
redisClient.hSet(key, map);
return "ok";
}
// 读测试
@GetMapping("/test/get/{key}")
public Map get(@PathVariable String key){
public Map get(@PathVariable String key) {
// Map<Object, Object> result = redisTemplate.opsForHash().entries(key);
Map<String, Object> result = redisClient.hGetAll(key);
return result;
}
@PostMapping("/cache/pipeline/string")
public void pipelineString(@RequestBody Map<String,String> map){
log.info("【缓存模块】 pipelineString获取到存储的数据map的长度 ={}的数据", map.size());
redisClient.pipelined(operations -> {
for (Map.Entry<String, String> entry : map.entrySet()) {
operations.opsForValue().set(entry.getKey(),entry.getValue());
}
});
}
}

@ -9,9 +9,9 @@ spring:
cloud:
nacos:
discovery:
server-addr: 172.20.10.2:8848
server-addr: 192.168.43.132:8848
# nacos配置中心地址:
config:
server-addr: 172.20.10.2:8848
server-addr: 192.168.43.132:8848
file-extension: yml
# beacon-cache-dev.yml

@ -13,4 +13,26 @@ public interface CacheConstant {
String CLIENT_TEMPLATE = "client_template:";
String CLIENT_BALANCE = "client_balance:";
String PHASE = "phase:";
String DIRTY_WORD = "dirty_word";
String BLACK = "black:";
String SEPARATE = ":";
String TRANSFER = "transfer:";
/**
*
*/
String LIMIT_MINUTES = "limit:minutes:";
String LIMIT_HOURS = "limit:hours:";
String CLIENT_CHANNEL= "client_channel:";
String CHANNEL = "channel:";
}

@ -13,4 +13,19 @@ public interface RabbitMQConstants {
*
*/
String SMS_PRE_SEND = "sms_pre_send_topic";
String MOBILE_AREA_OPERATIR = "mobile_area_operator_topic";
/**
* ElasticSearch
* @return
*/
String SMS_WRITE_LOG = "sms_write_log_topic";
String SMS_PUSH_REPORT = "sms_push_report_topic";
/**
*
*/
String SMS_GATEWAY = "sms_gateway_topic_";
}

@ -0,0 +1,28 @@
package com.mashibing.common.constant;
/**
* @author dch
* @create 2024-03-23 23:28
*
*/
public interface SmsConstant {
/**
*
*/
int REPORT_SUCCESS = 1;
/**
*
*/
int REPORT_FAIL = 2;
/**
*
*/
int CODE_TYPE = 0;
int NOTIFY_TYPE = 1;
int MARKETING_TYPE = 2;
}

@ -9,6 +9,7 @@ import lombok.Getter;
@Getter
public enum ExceptionEnums {
UNKNOWN_ERROR(-999,"未知错误"),
ERROR_APIKEY(-1,"非法的apikey"),
IP_NOT_WHITE(-2,"请求的ip不在白名单内"),
ERROR_SIGN(-3,"无可用签名"),
@ -17,7 +18,13 @@ public enum ExceptionEnums {
BALANCE_NOT_ENOUGH(-6,"手客户余额不足"),
PARAMETER_ERROR(-10, "参数不合法!"),
SNOWFLAKE_OUT_OF_RANGE(-11,"雪花算法的机器id或服务id超出最大范围!"),
SNOWFLAKE_TIME_BACK(-12,"雪花算法的服务器出现时间回拨问题")
SNOWFLAKE_TIME_BACK(-12,"雪花算法的服务器出现时间回拨问题"),
HAVE_DIRTY_WORD(-13,"当前短信内容中包含敏感词信息"),
BLACK_GLOBAL(-14,"当前手机号为平台黑名单"),
BLACK_CLIENT(-15,"当前手机号为用户黑名单"),
ONE_MINUTE_LIMIT(-16,"1分钟限流规则生效无法发送短信"),
ONE_HOUR_LIMIT(-17,"1小时限流规则生效无法发送短信"),
NO_CHANNEL(-18,"没有选择到合适的通道"),
;
private Integer code;

@ -0,0 +1,31 @@
package com.mashibing.common.enums;
import lombok.Getter;
/**
* @author dch
* @create 2024-03-22 22:17
*/
@Getter
public enum MobileOperatorEnum {
CHINA_MOBILE(1,"移动"),
CHINA_UNION(2,"联通"),
CHINA_TELECOM(3,"电信"),
UNKNOWN(4,"未知 未知,未知"),
;
private Integer operatorId;
private String operatorName;
/**
* id
*/
MobileOperatorEnum(Integer operatorId, String operatorName) {
this.operatorId = operatorId;
this.operatorName = operatorName;
}
}

@ -0,0 +1,27 @@
package com.mashibing.common.exception;
import com.mashibing.common.enums.ExceptionEnums;
import lombok.Getter;
/**
* @author dch
* @create 2024-03-20 12:15
*
*/
@Getter
public class StrategyException extends RuntimeException {
private Integer code;
public StrategyException(String message, Integer code) {
super(message);
this.code = code;
}
public StrategyException(ExceptionEnums enums) {
super(enums.getMsg());
this.code = enums.getCode();
}
}

@ -0,0 +1,70 @@
package com.mashibing.common.model;
/**
* @author dch
* @create 2024-03-24 17:05
*/
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
*
*
* @author zjw
* @description
*/
@Data
@NoArgsConstructor
@AllArgsConstructor
public class StandardReport implements Serializable {
/**
*
*/
private Long sequenceId;
/**
* IDapikeyID
*/
private Long clientId;
/**
* uid
*/
private String uid;
/**
*
*/
private String mobile;
/**
*
*/
private LocalDateTime sendTime;
/**
* 0-/ing1-2- 0
*/
private int reportState;
/**
*
*/
private String errorMsg;
/**
*
*
*/
private Integer isCallback;
private String callbackUrl;
}

@ -71,6 +71,7 @@ public class StandardSubmit implements Serializable {
/**
* 0451 0455
*
*/
private Integer areaCode;
@ -94,21 +95,40 @@ public class StandardSubmit implements Serializable {
*/
private int reportState;
/**
*
*/
private String errorMsg;
/**
IP
*/
/**
* IP
*/
private String realIP;
/** 请求携带的apiKey封装*/
/**
* apiKey
*/
private String apikey;
/**
0- 1- 3-
*/
/**
* 0- 1- 3-
*/
private Integer state;
/**签名的id*/
/**
* id
*/
private Long signId;
/**
*
*/
private Boolean isTransfer = false;
/**
*
*/
private Long oneHourLimitMilli;
}

@ -0,0 +1,28 @@
package com.mashibing.common.util;
import com.mashibing.common.enums.MobileOperatorEnum;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* @author dch
* @create 2024-03-22 22:22
*/
public class OperatorUtil {
private static Map<String,Integer> operators = new HashMap<>();
static {
MobileOperatorEnum[] operatorEnums = MobileOperatorEnum.values();
for (MobileOperatorEnum operatorEnum : operatorEnums){
operators.put(operatorEnum.getOperatorName(),operatorEnum.getOperatorId());
}
}
public static Integer getOperatorIdByOperatorName(String operatorName){
return operators.get(operatorName);
}
}

@ -52,6 +52,19 @@
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- IK分词器 -->
<dependency>
<groupId>com.janeluo</groupId>
<artifactId>ikanalyzer</artifactId>
<version>2012_u6</version>
</dependency>
<!-- 导入hutool工具类-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-dfa</artifactId>
<version>5.8.12</version>
</dependency>
</dependencies>
</project>

@ -4,6 +4,8 @@ import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;
/**
* @author dch
@ -18,4 +20,9 @@ public class StrategyStarterApp {
SpringApplication.run(StrategyStarterApp.class,args);
}
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}

@ -1,8 +1,10 @@
package com.mashibing.strategy.client;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.*;
import java.util.Map;
import java.util.Set;
/**
* @author dch
@ -12,6 +14,43 @@ import org.springframework.web.bind.annotation.PathVariable;
public interface BeaconCacheClient {
@GetMapping("/cache/hget/{key}/{field}")
String hget(@PathVariable(value = "key")String key, @PathVariable(value = "field")String field);
String hget(@PathVariable(value = "key") String key, @PathVariable(value = "field") String field);
@GetMapping("/cache/hgetall/{key}")
Map hGetAll(@PathVariable(value = "key") String key);
@GetMapping("/cache/hget/{key}/{field}")
Integer hgetInteger(@PathVariable(value = "key") String key, @PathVariable(value = "field") String field);
@GetMapping("/cache/get/{key}")
String getString(@PathVariable(value = "key") String key);
@PostMapping(value = "/cache/sinterstr/{key}/{sinterKey}")
Set<Object> sinterStr(@PathVariable(value = "key") String key, @PathVariable String sinterKey, @RequestBody String... value);
@GetMapping("/cache/smember/{key}")
Set<String> smember(@PathVariable(value = "key") String key);
@GetMapping("/cache/smemberMap/{key}")
Set<Map> smemberMap(@PathVariable(value = "key") String key);
@PostMapping(value = "/cache/zadd/{key}/{score}/{member}")
Boolean zadd(@PathVariable(value = "key")String key,
@PathVariable(value = "score")Long score,
@PathVariable(value = "member")Object member);
@GetMapping(value = "/cache/zrangebyscorecount/{key}/{start}/{end}")
Integer zRangeByScoreCount(@PathVariable(value = "key") String key,
@PathVariable(value = "start") Double start,
@PathVariable(value = "end") Double end);
@DeleteMapping(value = "/cache/zremove/{key}/{member}")
void zRemove(@PathVariable(value = "key") String key,@PathVariable(value = "member") String member);
@PostMapping(value = "/cache/hincrby/{key}/{field}/{delta}")
Long hIncrBy(@PathVariable(value = "key") String key,
@PathVariable(value = "field") String field,
@PathVariable(value = "delta") Long delta);
}
}

@ -0,0 +1,39 @@
package com.mashibing.strategy.config;
import com.mashibing.common.constant.RabbitMQConstants;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author dch
* @create 2024-03-22 23:16
*/
@Configuration
public class RabbitMQConfig {
/**
* &
* @return
*/
@Bean
public Queue preSendQueue(){
return QueueBuilder.durable(RabbitMQConstants.MOBILE_AREA_OPERATIR).build();
}
/**
*
* @return
*/
@Bean
public Queue writeLogQueue(){
return QueueBuilder.durable(RabbitMQConstants.SMS_WRITE_LOG).build();
}
@Bean
public Queue pushReportQueue(){
return QueueBuilder.durable(RabbitMQConstants.SMS_PUSH_REPORT).build();
}
}

@ -0,0 +1,60 @@
package com.mashibing.strategy.config;
/**
* @author dch
* @create 2024-03-21 0:31
*/
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* RabbitTemplateconfirm&return
* @author zjw
* @description
*/
@Configuration
@Slf4j
public class RabbitTemplateConfig {
@Bean
public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){
//1、构建RabbitTemplate对象
RabbitTemplate rabbitTemplate = new RabbitTemplate();
//2、设置connectionFactory
rabbitTemplate.setConnectionFactory(connectionFactory);
//3、配置confirm机制
rabbitTemplate.setConfirmCallback(new RabbitTemplate.ConfirmCallback(){
@Override
public void confirm(CorrelationData correlationData, boolean ack, String cause) {
// ack为false代表消息没有发送到exchange。
if(!ack){
log.error("【接口模块-发送消息】 消息没有发送到交换机correlationData = {}cause = {}",correlationData,cause);
}
}
});
//4、配置return机制
rabbitTemplate.setReturnCallback(new RabbitTemplate.ReturnCallback(){
// 触发这个回调,说明交换机没有把消息路由到指定的队列中
@Override
public void returnedMessage(Message message, int replyCode, String replyText, String exchange, String routingKey) {
log.error("【接口模块-发送消息】 消息没有路由到指定的Queue。 message = {},exchange = {},routingKey = {}",
new String(message.getBody()),exchange,routingKey);
}
});
//5、返回
return rabbitTemplate;
}
}

@ -0,0 +1,52 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.ErrorSendMsgUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author dch
* @create 2024-03-21 10:20
*/
@Service(value = "blackclient")
@Slf4j
public class BlackClientStrategyFilter implements StrategyFilter {
@Autowired
private ErrorSendMsgUtil sendMsgUtil;
@Autowired
private BeaconCacheClient cacheClient;
// 黑名单的默认value
private final String TRUE = "1";
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-客户级别黑名单校验】 校验ing…………");
//1、获取发送短信的手机号,以及客户的ID
String mobile = submit.getMobile();
Long clientId = submit.getClientId();
//2、调用Redis查询
String value = cacheClient.getString(CacheConstant.BLACK + clientId + CacheConstant.SEPARATE + mobile);
//3、如果查询的结果为"1",代表是黑名单
if(TRUE.equals(value)){
log.info("【策略模块-客户级别黑名单校验】 当前发送的手机号是客户黑名单! mobile = {}",mobile);
submit.setErrorMsg(ExceptionEnums.BLACK_CLIENT + ",mobile = " + mobile);
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.BLACK_CLIENT);
}
//4、不是1正常结束
log.info("【策略模块-客户级别黑名单校验】 当前手机号不是客户黑名单! ");
}
}

@ -0,0 +1,51 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.ErrorSendMsgUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author dch
* @create 2024-03-21 10:20
*/
@Service(value = "blackglobal")
@Slf4j
public class BlackGlobalStrategyFilter implements StrategyFilter {
@Autowired
private ErrorSendMsgUtil sendMsgUtil;
@Autowired
private BeaconCacheClient cacheClient;
// 黑名单的默认value
private final String TRUE = "1";
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-全局级别黑名单校验】 校验ing…………");
//1、获取发送短信的手机号
String mobile = submit.getMobile();
//2、调用Redis查询
String value = cacheClient.getString(CacheConstant.BLACK + mobile);
//3、如果查询的结果为"1",代表是黑名单
if(TRUE.equals(value)){
log.info("【策略模块-全局级别黑名单校验】 当前手机号是黑名单! mobile = {}",mobile);
submit.setErrorMsg(ExceptionEnums.BLACK_GLOBAL.getMsg() + ",mobile = " + mobile);
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.BLACK_GLOBAL);
}
//4、不是1正常结束
log.info("【策略模块-全局级别黑名单校验】 当前手机号不是黑名单!");
}
}

@ -1,19 +0,0 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.filter.StrategyFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
* @author dch
* @create 2024-03-21 10:20
*/
@Service(value = "black")
@Slf4j
public class BlackStrategyFilter implements StrategyFilter {
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-黑名单校验】 校验ing…………");
}
}

@ -0,0 +1,40 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.DFAUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Set;
/**
* @author dch
* @create 2024-03-23 11:01
*/
@Service(value = "dfadirtyword")
@Slf4j
public class DirtyWordDFAStrategyFilter implements StrategyFilter {
@Autowired
private BeaconCacheClient cacheClient;
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-敏感词校验】 校验ing…………");
//1、 获取短信内容
String text = submit.getText();
//2、 调用DFA查看敏感词
Set<String> dirtyWords = DFAUtil.getDirtyWord(text);
//4、 根据返回的set集合判断是否包含敏感词
if (dirtyWords != null && dirtyWords.size() > 0) {
//5、 如果有敏感词,抛出异常 / 其他操作。。
log.info("【策略模块-敏感词校验】 短信内容包含敏感词信息, dirtyWords = {}", dirtyWords);
// 还需要做其他处理
}
}
}

@ -0,0 +1,67 @@
package com.mashibing.strategy.filter.impl;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.constant.RabbitMQConstants;
import com.mashibing.common.constant.SmsConstant;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardReport;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.ErrorSendMsgUtil;
import com.mashibing.strategy.util.HutoolDFAUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import java.util.List;
/**
* @author dch
* @create 2024-03-23 11:50
*/
@Service(value = "hutooldfadirtyword")
@Slf4j
public class DirtyWordHutoolDFAStrategyFilter implements StrategyFilter {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private BeaconCacheClient cacheClient;
@Autowired
private ErrorSendMsgUtil errorSendMsgUtil;
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-敏感词校验】 校验ing…………");
//1、 获取短信内容
String text = submit.getText();
//2、 调用DFA查看敏感词
List<String> dirtyWords = HutoolDFAUtil.getDirtyWord(text);
//4、 根据返回的set集合判断是否包含敏感词
if (dirtyWords != null && dirtyWords.size() > 0) {
//5、 如果有敏感词,抛出异常 / 其他操作。。
log.info("【策略模块-敏感词校验】 短信内容包含敏感词信息, dirtyWords = {}", dirtyWords);
// 封装错误信息
// ================================发送写日志================================
submit.setErrorMsg(ExceptionEnums.HAVE_DIRTY_WORD.getMsg() + "dirtyWords = " + dirtyWords.toString());
errorSendMsgUtil.sendWriteLog(submit);
// ================================发送状态报告的消息前需要将report对象数据封装,回调================================
errorSendMsgUtil.sendPushReport(submit);
// // ================================抛出异常================================
throw new StrategyException(ExceptionEnums.HAVE_DIRTY_WORD);
}
log.info("【策略模块-敏感词校验】 校验通过,没有敏感词信息");
}
}

@ -1,9 +1,20 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.wltea.analyzer.core.IKSegmenter;
import org.wltea.analyzer.core.Lexeme;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
/**
* @author dch
@ -14,9 +25,39 @@ import org.springframework.stereotype.Service;
@Slf4j
public class DirtyWordStrategyFilter implements StrategyFilter {
@Autowired
private BeaconCacheClient cacheClient;
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-敏感词过滤】 过滤ing…………");
log.info("【策略模块-敏感词校验】 校验ing…………");
//1、 获取短信内容
String text = submit.getText();
//2、 对短信内容进行分词,并且将分析内容存储到集合中
Set<String> contents = new HashSet<>();
StringReader reader = new StringReader(text);
IKSegmenter ik = new IKSegmenter(reader, false);
Lexeme lex = null;
while (true) {
try {
if ((lex = ik.next()) == null) break;
} catch (IOException e) {
log.info("【策略模块-敏感词校验】 IK分词器在处理短信内容时出现异常 e = {}", e.getMessage());
}
contents.add(lex.getLexemeText());
}
//3、 调用Cache缓存模块的交集方法拿到结果
Set<Object> dirtyWords = cacheClient.sinterStr(UUID.randomUUID().toString(), CacheConstant.DIRTY_WORD, contents.toArray(new String[]{}));
//4、 根据返回的set集合判断是否包含敏感词
if (dirtyWords != null && dirtyWords.size() > 0) {
//5、 如果有敏感词,抛出异常 / 其他操作。。
log.info("【策略模块-敏感词校验】 短信内容包含敏感词信息, dirtyWords = {}", dirtyWords);
// 还需要做其他处理
}
}
}

@ -0,0 +1,55 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.ClientBalanceUtil;
import com.mashibing.strategy.util.ErrorSendMsgUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author dch
* @create 2024-03-24 23:21
*/
@Service(value = "fee")
@Slf4j
public class FeeStrategyFilter implements StrategyFilter {
@Autowired
private BeaconCacheClient cacheClient;
@Autowired
private ErrorSendMsgUtil sendMsgUtil;
private final String BALANCE = "balance";
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-扣费校验】 校验ing…………");
//1、获取submit中封装的金额
Long fee = submit.getFee();
Long clientId = submit.getClientId();
//2、调用Redis的decr扣减具体的金额
Long amount = cacheClient.hIncrBy(CacheConstant.CLIENT_BALANCE + clientId, BALANCE, -fee);
//3、获取当前客户的欠费金额的限制外部方法调用暂时写死为10000厘
Long amountLimit = ClientBalanceUtil.getClientAmountLimit(submit.getClientId());
//4、判断扣减过后的金额是否超出了金额限制
if(amount < amountLimit) {
log.info("【策略模块-扣费校验】 扣除费用后,超过欠费余额的限制,无法发送短信!!");
//5、如果超过了需要将扣除的费用增加回去并且做后续处理
cacheClient.hIncrBy(CacheConstant.CLIENT_BALANCE + clientId, BALANCE, fee);
submit.setErrorMsg(ExceptionEnums.BALANCE_NOT_ENOUGH.getMsg());
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.BALANCE_NOT_ENOUGH);
}
log.info("【策略模块-扣费校验】 扣费成功!!");
}
}

@ -0,0 +1,101 @@
package com.mashibing.strategy.filter.impl;
/**
* @author dch
* @create 2024-03-24 22:16
*/
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.constant.SmsConstant;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.ErrorSendMsgUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
* 13
* @author zjw
* @description
*/
@Service("limitonehour")
@Slf4j
public class LimitOneHourStrategyFilter implements StrategyFilter {
private final String UTC = "+8";
private final long ONE_HOUR = 60 * 1000 * 60 - 1;
private final int RETRY_COUNT = 2;
private final int LIMIT_HOUR = 3;
@Autowired
private BeaconCacheClient cacheClient;
@Autowired
private ErrorSendMsgUtil sendMsgUtil;
@Override
public void strategy(StandardSubmit submit) {
// 判断短信类型不是验证码类的,直接结束方法
if(submit.getState() != SmsConstant.CODE_TYPE){
return;
}
log.info("【策略模块-一小时限流策略】 开始校验ing......");
//1、基于submit获取短信的发送时间
LocalDateTime sendTime = submit.getSendTime();
//2、基于LocalDateTime获取到时间的毫秒值
long sendTimeMilli = sendTime.toInstant(ZoneOffset.of(UTC)).toEpochMilli();
submit.setOneHourLimitMilli(sendTimeMilli);
//3、基于submit获取客户标识以及手机号信息
Long clientId = submit.getClientId();
String mobile = submit.getMobile();
//4、优先将当前短信发送信息插入到Redis的ZSet结构中 zadd
String key = CacheConstant.LIMIT_HOURS + clientId + CacheConstant.SEPARATE + mobile;
//5、如果插入失败需要重新的将毫秒值做改变尝试重新插入
int retry = 0;
while(!cacheClient.zadd(key, submit.getOneHourLimitMilli(), submit.getOneHourLimitMilli())){
// 发送失败,尝试重试
if(retry == RETRY_COUNT) break;
retry++;
// 插入失败是因为存储的member不允许重复既然重复了将时间向后移动移动到当前系统时间
submit.setOneHourLimitMilli(System.currentTimeMillis());
}
// 如果retry为2代表已经重试了2次但是依然没有成功
if(retry == RETRY_COUNT){
log.info("【策略模块-一小时限流策略】 插入失败! 满足一小时限流规则,无法发送!");
submit.setErrorMsg(ExceptionEnums.ONE_HOUR_LIMIT + ",mobile = " + mobile);
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.ONE_HOUR_LIMIT);
}
// 没有重试2次3次之内将数据正常的插入了。基于zrangebyscore做范围查询
long start = submit.getOneHourLimitMilli() - ONE_HOUR;
int count = cacheClient.zRangeByScoreCount(key, Double.parseDouble(start + ""), Double.parseDouble(submit.getOneHourLimitMilli() + ""));
if(count > LIMIT_HOUR){
log.info("【策略模块-一小时限流策略】 插入失败! 满足一小时限流规则,无法发送!");
cacheClient.zRemove(key,submit.getOneHourLimitMilli() + "");
submit.setErrorMsg(ExceptionEnums.ONE_HOUR_LIMIT + ",mobile = " + mobile);
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.ONE_HOUR_LIMIT);
}
log.info("【策略模块-一小时限流策略】 一小时限流规则通过,可以发送!");
}
}

@ -0,0 +1,85 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.constant.SmsConstant;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.ErrorSendMsgUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
/**
* @author dch
* @create 2024-03-24 21:30
*/
@Service("limitoneminute")
@Slf4j
public class LimitOneMinuteStrategyFilter implements StrategyFilter {
private final String UTC = "+8";
private final long ONE_MINUTE = 60 * 1000 - 1;
@Autowired
private BeaconCacheClient cacheClient;
@Autowired
private ErrorSendMsgUtil sendMsgUtil;
@Override
public void strategy(StandardSubmit submit) {
// 判断短信类型不是验证码类的,直接结束方法
if(submit.getState() != SmsConstant.CODE_TYPE){
return;
}
log.info("【策略模块-一分钟时限流策略】 开始校验ing......");
//1、基于submit获取短信的发送时间
LocalDateTime sendTime = submit.getSendTime();
//2、基于LocalDateTime获取到时间的毫秒值
long sendTimeMilli = sendTime.toInstant(ZoneOffset.of(UTC)).toEpochMilli();
//3、基于submit获取客户标识以及手机号信息
Long clientId = submit.getClientId();
String mobile = submit.getMobile();
//4、优先将当前短信发送信息插入到Redis的ZSet结构中 zadd
String key = CacheConstant.LIMIT_MINUTES + clientId + CacheConstant.SEPARATE + mobile;
Boolean addOk = cacheClient.zadd(key, sendTimeMilli, sendTimeMilli);
//5、如果查询失败直接告辞有并发情况60s不能发送两条直接告辞
if(!addOk){
log.info("【策略模块-一分钟限流策略】 插入失败! 满足一分钟限流规则,无法发送!");
submit.setErrorMsg(ExceptionEnums.ONE_MINUTE_LIMIT + ",mobile = " + mobile);
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.ONE_MINUTE_LIMIT);
}
//6、基于zrangebyscore查询1分钟直接是否只有当前查询的发送短信信息
long start = sendTimeMilli - ONE_MINUTE;
int count = cacheClient.zRangeByScoreCount(key, Double.parseDouble(start + ""), Double.parseDouble(sendTimeMilli + ""));
//7、如果大于等于2条短信信息达到了60s一条的短信限流规则直接告辞。
if(count > 1){
// 一分钟之前,发送过短信,限流规则生效
log.info("【策略模块-一分钟限流策略】 插入失败! 满足一分钟限流规则,无法发送!");
cacheClient.zRemove(key,sendTimeMilli + "");
submit.setErrorMsg(ExceptionEnums.ONE_MINUTE_LIMIT + ",mobile = " + mobile);
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.ONE_MINUTE_LIMIT);
}
log.info("【策略模块-一分钟限流策略】 一分钟限流规则通过,可以发送!");
}
}

@ -1,8 +1,17 @@
package com.mashibing.strategy.filter.impl;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.constant.RabbitMQConstants;
import com.mashibing.common.enums.MobileOperatorEnum;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.common.util.OperatorUtil;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.MobileOperatorUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
@ -14,9 +23,60 @@ import org.springframework.stereotype.Service;
@Slf4j
public class PhaseStrategyFilter implements StrategyFilter {
/**
* 7
*/
private final int MOBILE_START = 0;
private final int MOBILE_END = 7;
/**
*
*/
private final int LENGTH = 2;
/**
*
*/
private final String SEPARATE = ",";
/**
*
*/
// private final String UNKNOWN = "未知 未知,未知";
@Autowired
private BeaconCacheClient cacheClient;
@Autowired
private MobileOperatorUtil mobileOperatorUtil;
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-号段补全】 补全ing…………");
log.info("【策略模块-号段补齐】 补全ing…………");
//1、根据手机号前7位查询手机号信息
String mobile = submit.getMobile().substring(MOBILE_START, MOBILE_END);
String mobileInfo = cacheClient.getString(CacheConstant.PHASE + mobile);
getMobileInfo:
if (StringUtils.isEmpty(mobileInfo)) {
//2、查询不到需要调用三方接口查询手机号对应信息
mobileInfo = mobileOperatorUtil.getMobileInfoBy360(mobile);
if (!StringUtils.isEmpty(mobileInfo)) {
//3、调用三方查到信息后发送消息到MQ并且同步到MySQL和Redis
rabbitTemplate.convertAndSend(RabbitMQConstants.MOBILE_AREA_OPERATIR, submit.getMobile());
break getMobileInfo;
}
mobileInfo = MobileOperatorEnum.UNKNOWN.getOperatorName();
}
//4、无论是Redis还是三方接口查询到之后封装到StandardSubmit对象中
String[] areaAndOperator = mobileInfo.split(SEPARATE);
if (areaAndOperator.length == LENGTH) {
submit.setArea(areaAndOperator[0]);
submit.setOperatorId(OperatorUtil.getOperatorIdByOperatorName(areaAndOperator[1]));
}
}
}

@ -1,10 +1,27 @@
package com.mashibing.strategy.filter.impl;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.constant.RabbitMQConstants;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import com.mashibing.strategy.util.ChannelTransferUtil;
import com.mashibing.strategy.util.ErrorSendMsgUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.QueueBuilder;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.Comparator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
/**
* @author dch
* @create 2024-03-21 10:21
@ -14,9 +31,99 @@ import org.springframework.stereotype.Service;
@Slf4j
public class RouteStrategyFilter implements StrategyFilter {
@Autowired
private BeaconCacheClient cacheClient;
@Autowired
private ErrorSendMsgUtil sendMsgUtil;
@Autowired
private AmqpAdmin amqpAdmin;
@Autowired
private RabbitTemplate rabbitTemplate;
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-通道选择】 通道选择ing…………");
log.info("【策略模块-路由策略】 校验ing…………");
//1、拿到客户id
Long clientId = submit.getClientId();
//2、基于redis获取当前客户绑定的所有通道信息
Set<Map> clientChannels = cacheClient.smemberMap(CacheConstant.CLIENT_CHANNEL + clientId);
//3、将获取到的客户通道信息根据权重做好排序
TreeSet<Map> clientWeightChannels = new TreeSet<>(new Comparator<Map>() {
@Override
public int compare(Map o1, Map o2) {
int o1Weight = Integer.parseInt(o1.get("clientChannelWeight") + "");
int o2Weight = Integer.parseInt(o2.get("clientChannelWeight") + "");
return o2Weight - o1Weight;
}
});
clientWeightChannels.addAll(clientChannels);
boolean ok = false;
Map channel = null;
Map clientChannel = null;
//4、基于排好序的通道选择权重更高的
for (Map clientWeightChannel : clientWeightChannels) {
//5、如果客户和通道的绑定关系可用直接去基于Redis查询具体的通道信息
if((int)(clientWeightChannel.get("isAvailable")) != 0){
// 当前关系不可用,直接进行下次循环,选择权重相对更低一点的
continue;
}
//6、如果通道信息查询后判断通道睡否可用其次运营商可以匹配。
channel = cacheClient.hGetAll(CacheConstant.CHANNEL + clientWeightChannel.get("channelId"));
if((int)(channel.get("isAvailable")) != 0){
// 当前通道不可用,选择权重更低的通道~
continue;
}
// 获取通道的通讯方式
Integer channelType = (Integer) channel.get("channelType");
if (channelType != 0 && submit.getOperatorId() != channelType){
// 通道不是全网通,并且和当前手机号运营商不匹配
continue;
}
//7、如果后期涉及到的通道的转换这里留一个口子
Map transferChannel = ChannelTransferUtil.transfer(submit, channel);
// 找到可以使用的通道了
ok = true;
clientChannel = clientWeightChannel;
break;
}
if(!ok){
log.info("【策略模块-路由策略】 没有选择到可用的通道!!");
submit.setErrorMsg(ExceptionEnums.NO_CHANNEL.getMsg());
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(ExceptionEnums.NO_CHANNEL);
}
//8、基于选择的通道封装submit的信息
submit.setChannelId(Long.parseLong(channel.get("id") + ""));
submit.setSrcNumber("" + channel.get("channelNumber") + clientChannel.get("clientChannelNumber"));
try {
//9、声明好队列名称并构建队列
String queueName = RabbitMQConstants.SMS_GATEWAY + submit.getChannelId();
amqpAdmin.declareQueue(QueueBuilder.durable(queueName).build());
//10、发送消息到声明好的队列中
rabbitTemplate.convertAndSend(queueName,submit);
} catch (AmqpException e) {
log.info("【策略模块-路由策略】 声明通道对应队列以及发送消息时出现了问题!");
submit.setErrorMsg(e.getMessage());
sendMsgUtil.sendWriteLog(submit);
sendMsgUtil.sendPushReport(submit);
throw new StrategyException(e.getMessage(),ExceptionEnums.UNKNOWN_ERROR.getCode());
}
}
}

@ -0,0 +1,47 @@
package com.mashibing.strategy.filter.impl;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import com.mashibing.strategy.filter.StrategyFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @author dch
* @create 2024-03-24 19:51
*/
@Service(value = "transfer")
@Slf4j
public class TransferStrategyFilter implements StrategyFilter {
// 代表携号转网了!
private final Boolean TRANSFER = true;
@Autowired
private BeaconCacheClient cacheClient;
@Override
public void strategy(StandardSubmit submit) {
log.info("【策略模块-携号转网策略】 ing…………");
//1、获取用户手机号
String mobile = submit.getMobile();
//2、直接基于Redis查询携号转网信息
String value = cacheClient.getString(CacheConstant.TRANSFER + mobile);
//3、如果存在携号转网设置运营商信息
if(!StringUtils.isEmpty(value)){
// 代表携号转网了
submit.setOperatorId(Integer.valueOf(value));
submit.setIsTransfer(TRANSFER);
log.info("【策略模块-携号转网策略】 当前手机号携号转网了!");
return;
}
log.info("【策略模块-携号转网策略】 当前手机号不涉及携号转网!");
}
}

@ -1,6 +1,7 @@
package com.mashibing.strategy.mq;
import com.mashibing.common.constant.RabbitMQConstants;
import com.mashibing.common.exception.StrategyException;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.filter.StrategyFilterContext;
import com.rabbitmq.client.Channel;
@ -34,9 +35,10 @@ public class PreSendListener {
filterContext.strategy(submit);
log.info("【策略模块-消费完毕】手动ack");
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
} catch (IOException e) {
e.printStackTrace();
log.error("【策略模块-消费失败】凉凉~~~");
} catch (StrategyException e) {
// e.printStackTrace();
log.info("【策略模块-消费失败】校验未通过msg={}",e.getMessage());
channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
}
}
}

@ -0,0 +1,17 @@
package com.mashibing.strategy.util;
import com.mashibing.common.model.StandardSubmit;
import java.util.Map;
/**
* ,
* @author dch
* @create 2024-03-25 0:41
*/
public class ChannelTransferUtil {
public static Map transfer(StandardSubmit submit,Map channel){
return channel;
}
}

@ -0,0 +1,18 @@
package com.mashibing.strategy.util;
/**
* @author dch
* @create 2024-03-24 23:35
*/
public class ClientBalanceUtil {
/**
*
*
* @param clientId
* @return
*/
public static Long getClientAmountLimit(Long clientId) {
return -10000L;
}
}

@ -0,0 +1,144 @@
package com.mashibing.strategy.util;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.strategy.client.BeaconCacheClient;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* @author dch
* @create 2024-03-23 1:43
*/
public class DFAUtil {
// 敏感词树
private static Map dfaMap = new HashMap<>();
private static final String IS_END = "isEnd";
private static final String NOT_END = "0";
private static final String ALREADY_END = "1";
/**
*
* autowired BeaconCacheClient
* Autowired members must be defined in valid Spring bean (@Component|@Service|...)
*/
static {
// 获取Spring容器中的cacheClient
BeaconCacheClient cacheClient = (BeaconCacheClient) SpringUtil.getBeanByClass(BeaconCacheClient.class);
// 获取存储在Redis中的全部敏感词
Set<String> dirtyWords = cacheClient.smember(CacheConstant.DIRTY_WORD);
// 调用create将dfaMap的敏感词树构建
create(dirtyWords);
}
public static void main(String[] args) {
// 敏感词库
Set<String> dirtyWords = new HashSet<>();
dirtyWords.add("三胖");
dirtyWords.add("山炮");
dirtyWords.add("三胖啊啊");
dirtyWords.add("瘦啊");
// 测试敏感词树的生成
create(dirtyWords);
// 测试效果
String text = "你三瘦啊山炮";
System.out.println(getDirtyWord(text));
}
/**
*
* @param dirtyWords
*/
public static void create(Set<String> dirtyWords) {
//1、 声明一个Map作为临时存储
Map nowMap;
//2、遍历敏感词库
for (String dirtyWord : dirtyWords) {
nowMap = dfaMap;
// 每个词,依次获取
for (int i = 0; i < dirtyWord.length(); i++) {
// 获取敏感词的每个字
String word = String.valueOf(dirtyWord.charAt(i));
// 判断当前的敏感词树中是否包含当前的字
Map map = (Map) nowMap.get(word);
if (map == null) {
// 当前敏感词树中没有这个字
map = new HashMap();
// 将当前的敏感词存入
nowMap.put(word, map);
}
// 操作当前key对应的value的map
nowMap = map;
// 如果当前的字已经有IS_END了并且值为1直接不管
if (nowMap.containsKey(IS_END) && nowMap.get(IS_END).equals(ALREADY_END)) {
continue;
}
// 如果当前的isEnd没有或者是0需要考虑需要改为1
if (i == dirtyWord.length() - 1) {
// 到最后一个字了。
nowMap.put(IS_END, ALREADY_END);
} else {
// isEnd之前就是0或者压根就没有isEnd
nowMap.putIfAbsent(IS_END, NOT_END);
}
}
}
}
/**
*
* @param text
* @return
*/
public static Set<String> getDirtyWord(String text) {
// 1、作为返回结果存储敏感词的位置
Set<String> dirtyWords = new HashSet<>();
// 2、循环遍历文本内容
for (int i = 0; i < text.length(); i++) {
// 临时存储索引位置的变量
int nextLength = 0;
int dirtyLength = 0;
// 获取最外层key的map
Map nowMap = dfaMap;
// 外层是索引向后动匹配最外层的key
// 内层是在匹配上一个后继续向内部匹配内部的key
for (int j = i; j < text.length(); j++) {
// 获取当前索引位置的字
String word = String.valueOf(text.charAt(j));
// 先匹配最外层的key
nowMap = (Map) nowMap.get(word);
// 判断
if (nowMap == null) {
// 没有这个字开头的敏感词
break;
} else {
// 敏感词长度从i开始算现在的是dirtyLength
dirtyLength++;
// 出口即是当前的map的isEnd是1代表结束了。已经找到完整的敏感词
if (ALREADY_END.equals(nowMap.get(IS_END))) {
// 代表敏感词匹配到一个完整的
nextLength = dirtyLength;
break;
}
}
}
// 判断是否匹配上了敏感词
if (nextLength > 0) {
// 匹配上了添加敏感词到set同时移动外层索引
dirtyWords.add(text.substring(i, i + nextLength));
// -1的原因是外层for循环会对i进行++
i = i + nextLength - 1;
}
}
// 返回
return dirtyWords;
}
}

@ -0,0 +1,65 @@
package com.mashibing.strategy.util;
import com.alibaba.cloud.commons.lang.StringUtils;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.common.constant.RabbitMQConstants;
import com.mashibing.common.constant.SmsConstant;
import com.mashibing.common.enums.ExceptionEnums;
import com.mashibing.common.model.StandardReport;
import com.mashibing.common.model.StandardSubmit;
import com.mashibing.strategy.client.BeaconCacheClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author dch
* @create 2024-03-24 17:37
*/
@Component
public class ErrorSendMsgUtil {
@Autowired
private RabbitTemplate rabbitTemplate;
@Autowired
private BeaconCacheClient cacheClient;
/**
*
* @param submit
*
*/
public void sendWriteLog(StandardSubmit submit) {
submit.setReportState(SmsConstant.REPORT_FAIL);
// 发送消息到写日志队列
rabbitTemplate.convertAndSend(RabbitMQConstants.SMS_WRITE_LOG,submit);
}
/**
*
*/
public void sendPushReport(StandardSubmit submit) {
// 查询当前客户的isCallback
Integer isCallback = cacheClient.hgetInteger(CacheConstant.CLIENT_BUSINESS + submit.getApikey(), "isCallback");
// 查看是否需要给客户一个回调
if(isCallback == 1){
// 如果需要回调,再查询客户的回调地址
String callbackUrl = cacheClient.hget(CacheConstant.CLIENT_BUSINESS + submit.getApikey(), "callbackUrl");
// 如果回调地址不为空。
if(!StringUtils.isEmpty(callbackUrl)){
// 封装客户的报告推送的信息开始封装StandardReport
StandardReport report = new StandardReport();
BeanUtils.copyProperties(submit,report);
report.setIsCallback(isCallback);
report.setCallbackUrl(callbackUrl);
// 发送消息到RabbitMQ
rabbitTemplate.convertAndSend(RabbitMQConstants.SMS_PUSH_REPORT,report);
}
}
}
}

@ -0,0 +1,35 @@
package com.mashibing.strategy.util;
import cn.hutool.dfa.WordTree;
import com.mashibing.common.constant.CacheConstant;
import com.mashibing.strategy.client.BeaconCacheClient;
import java.util.List;
import java.util.Set;
/**
* @author dch
* @create 2024-03-23 11:48
*/
public class HutoolDFAUtil {
private static WordTree wordTree = new WordTree();
/**
*
*/
static {
// 获取Spring容器中的cacheClient
BeaconCacheClient cacheClient = (BeaconCacheClient) SpringUtil.getBeanByClass(BeaconCacheClient.class);
// 获取存储在Redis中的全部敏感词
Set<String> dirtyWords = cacheClient.smember(CacheConstant.DIRTY_WORD);
// 调用WordTree的add方法将dfaMap的敏感词树构建
wordTree.addWords(dirtyWords);
}
public static List<String> getDirtyWord(String text){
return wordTree.matchAll(text);
}
}

@ -0,0 +1,61 @@
package com.mashibing.strategy.util;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.Map;
/**
* @author dch
* @create 2024-03-22 22:29
*
*/
@Component
public class MobileOperatorUtil {
@Autowired
private RestTemplate restTemplate;
@Autowired
private ObjectMapper objectMapper;
private final String urll = "https://cx.shouji.360.cn/phonearea.php?number=";
private final String CODE = "code";
private final String DATA = "data";
private final String PROVINCE = "province";
private final String CITY = "city";
private final String SP = "sp";
private final String SPACE = " ";
private final String SEPARATE = ",";
public String getMobileInfoBy360(String mobile) {
String url = urll;
//1.发送请求获取信息
String mobileInfoJSON = restTemplate.getForObject(url + mobile, String.class);
//2.解析json
Map map = null;
try {
map = objectMapper.readValue(mobileInfoJSON, Map.class);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
Integer code = (Integer) map.get(CODE);
if (code != 0) {
return null;
}
Map<String, String> areaAndOperator = (Map<String, String>) map.get(DATA);
String province = areaAndOperator.get(PROVINCE);
String city = areaAndOperator.get(CITY);
String sp = areaAndOperator.get(SP);
//3.封装为 省 市,运营商 的格式返回
return province + SPACE + city + SEPARATE + sp;
}
}

@ -0,0 +1,29 @@
package com.mashibing.strategy.util;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author dch
* @create 2024-03-23 10:50
*/
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringUtil.applicationContext = applicationContext;
}
public static Object getBeanByName(String beanName){
return SpringUtil.applicationContext.getBean(beanName);
}
public static Object getBeanByClass(Class clazz){
return SpringUtil.applicationContext.getBean(clazz);
}
}

@ -9,9 +9,9 @@ spring:
cloud:
nacos:
discovery:
server-addr: 172.20.10.2:8848
server-addr: 192.168.43.132:8848
# nacos配置中心地址:
config:
server-addr: 172.20.10.2:8848
server-addr: 192.168.43.132:8848
file-extension: yml
# beacon-strategy-dev.yml

@ -24,4 +24,11 @@ public interface CacheClient {
@PostMapping(value = "/cache/sadd/{key}")
void sadd(@PathVariable(value = "key")String key, @RequestBody Map<String,Object>... maps);
@PostMapping(value = "/cache/saddstr/{key}")
void saddStr(@PathVariable(value = "key")String key, @RequestBody String... value);
@PostMapping("/cache/pipeline/string")
void pipelineString(@RequestBody Map<String, String> map);
}

@ -0,0 +1,125 @@
package com.mashibing.test.entity;
/**
* @author dch
* @create 2024-03-24 23:52
*/
public class Channel {
private Long id;
private String channelName;
private Integer channelType;
private String channelArea;
private String channelAreaCode;
private Long channelPrice;
private Integer channelProtocal;
private String channelIp;
private Integer channelPort;
private String channelUsername;
private String channelPassword;
private String channelNumber;
private Integer isAvailable;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getChannelName() {
return channelName;
}
public void setChannelName(String channelName) {
this.channelName = channelName;
}
public Integer getChannelType() {
return channelType;
}
public void setChannelType(Integer channelType) {
this.channelType = channelType;
}
public String getChannelArea() {
return channelArea;
}
public void setChannelArea(String channelArea) {
this.channelArea = channelArea;
}
public String getChannelAreaCode() {
return channelAreaCode;
}
public void setChannelAreaCode(String channelAreaCode) {
this.channelAreaCode = channelAreaCode;
}
public Long getChannelPrice() {
return channelPrice;
}
public void setChannelPrice(Long channelPrice) {
this.channelPrice = channelPrice;
}
public Integer getChannelProtocal() {
return channelProtocal;
}
public void setChannelProtocal(Integer channelProtocal) {
this.channelProtocal = channelProtocal;
}
public String getChannelIp() {
return channelIp;
}
public void setChannelIp(String channelIp) {
this.channelIp = channelIp;
}
public Integer getChannelPort() {
return channelPort;
}
public void setChannelPort(Integer channelPort) {
this.channelPort = channelPort;
}
public String getChannelUsername() {
return channelUsername;
}
public void setChannelUsername(String channelUsername) {
this.channelUsername = channelUsername;
}
public String getChannelPassword() {
return channelPassword;
}
public void setChannelPassword(String channelPassword) {
this.channelPassword = channelPassword;
}
public String getChannelNumber() {
return channelNumber;
}
public void setChannelNumber(String channelNumber) {
this.channelNumber = channelNumber;
}
public Integer getIsAvailable() {
return isAvailable;
}
public void setIsAvailable(Integer isAvailable) {
this.isAvailable = isAvailable;
}
}

@ -0,0 +1,50 @@
package com.mashibing.test.entity;
public class ClientChannel {
private Long clientId;
private Long channelId;
private Integer clientChannelWeight;
private String clientChannelNumber;
private Integer isAvailable;
public Long getClientId() {
return clientId;
}
public void setClientId(Long clientId) {
this.clientId = clientId;
}
public Long getChannelId() {
return channelId;
}
public void setChannelId(Long channelId) {
this.channelId = channelId;
}
public Integer getClientChannelWeight() {
return clientChannelWeight;
}
public void setClientChannelWeight(Integer clientChannelWeight) {
this.clientChannelWeight = clientChannelWeight;
}
public String getClientChannelNumber() {
return clientChannelNumber;
}
public void setClientChannelNumber(String clientChannelNumber) {
this.clientChannelNumber = clientChannelNumber;
}
public Integer getIsAvailable() {
return isAvailable;
}
public void setIsAvailable(Integer isAvailable) {
this.isAvailable = isAvailable;
}
}

@ -0,0 +1,36 @@
package com.mashibing.test.entity;
/**
* @author dch
* @create 2024-03-22 21:27
*/
public class MobileArea {
private String mobileNumber;
private String mobileArea;
private String mobileType;
public String getMobileNumber() {
return mobileNumber;
}
public void setMobileNumber(String mobileNumber) {
this.mobileNumber = mobileNumber;
}
public String getMobileArea() {
return mobileArea;
}
public void setMobileArea(String mobileArea) {
this.mobileArea = mobileArea;
}
public String getMobileType() {
return mobileType;
}
public void setMobileType(String mobileType) {
this.mobileType = mobileType;
}
}

@ -0,0 +1,30 @@
package com.mashibing.test.entity;
/**
* @author dch
* @create 2024-03-22 21:27
*/
public class MobileBlack {
private String blackNumber;
private Integer clientId;
public String getBlackNumber() {
return blackNumber;
}
public void setBlackNumber(String blackNumber) {
this.blackNumber = blackNumber;
}
public Integer getClientId() {
return clientId;
}
public void setClientId(Integer clientId) {
this.clientId = clientId;
}
}

@ -0,0 +1,28 @@
package com.mashibing.test.entity;
/**
* @author dch
* @create 2024-03-24 19:27
*/
public class MobileTransfer {
private String transferNumber;
private Integer nowIsp;
public String getTransferNumber() {
return transferNumber;
}
public void setTransferNumber(String transferNumber) {
this.transferNumber = transferNumber;
}
public Integer getNowIsp() {
return nowIsp;
}
public void setNowIsp(Integer nowIsp) {
this.nowIsp = nowIsp;
}
}

@ -0,0 +1,16 @@
package com.mashibing.test.mapper;
import com.mashibing.test.entity.Channel;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author dch
* @create 2024-03-24 23:54
*/
public interface ChannelMapper {
@Select("select * from channel where is_delete = 0")
List<Channel> findAll();
}

@ -0,0 +1,17 @@
package com.mashibing.test.mapper;
import com.mashibing.test.entity.Channel;
import com.mashibing.test.entity.ClientChannel;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author dch
* @create 2024-03-24 23:54
*/
public interface ClientChannelMapper {
@Select("select * from client_channel where is_delete = 0")
List<ClientChannel> findAll();
}

@ -0,0 +1,18 @@
package com.mashibing.test.mapper;
import com.mashibing.test.entity.ClientTemplate;
import com.mashibing.test.entity.MobileArea;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author dch
* @create 2024-03-22 21:26
*/
public interface MobileAreaMapper {
@Select("select mobile_number,mobile_area,mobile_type from mobile_area")
List<MobileArea> findAll();
}

@ -0,0 +1,17 @@
package com.mashibing.test.mapper;
import com.mashibing.test.entity.MobileBlack;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author dch
* @create 2024-03-24 18:16
*/
public interface MobileBlackMapper {
@Select("select black_number,client_id from mobile_black where is_delete = 0")
List<MobileBlack> findAll();
}

@ -0,0 +1,16 @@
package com.mashibing.test.mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author dch
* @create 2024-03-23 0:05
*/
public interface MobileDirtyWordMapper {
@Select("select dirtyword from mobile_dirtyword")
List<String> findDirtyWord();
}

@ -0,0 +1,17 @@
package com.mashibing.test.mapper;
import com.mashibing.test.entity.MobileTransfer;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @author dch
* @create 2024-03-24 19:26
*/
public interface MobileTransferMapper {
@Select("select transfer_number,now_isp from mobile_transfer where is_transfer = 1 and is_delete = 0")
List<MobileTransfer> findAll();
}

@ -6,13 +6,13 @@ spring:
cloud:
nacos:
discovery:
server-addr: 172.20.10.2:8848
server-addr: 192.168.43.132:8848
# datasource
datasource:
driver-class-name: org.gjt.mm.mysql.Driver
url: jdbc:mysql://localhost:3306/beacon_cloud?characterEncoding=utf-8&useSSL=false
username: root
password: 123456
password: 1234
# 端口号
server:
port: 20000

@ -0,0 +1,43 @@
package com.mashibing.test.mapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
import com.mashibing.test.client.CacheClient;
import com.mashibing.test.entity.Channel;
import com.mashibing.test.entity.MobileBlack;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import javax.rmi.CORBA.ValueHandler;
import java.util.List;
import java.util.Map;
/**
* @author dch
* @create 2024-03-24 18:17
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class ChannelMapperTest {
@Autowired
private ChannelMapper mapper;
@Autowired
private CacheClient cacheClient;
@Test
public void findAll() throws JsonProcessingException {
List<Channel> list = mapper.findAll();
for (Channel channel : list) {
ObjectMapper objectMapper = new ObjectMapper();
Map map = objectMapper.readValue(objectMapper.writeValueAsString(channel),Map.class);
cacheClient.hmset("channel:"+channel.getId(),map);
}
}
}

@ -0,0 +1,41 @@
package com.mashibing.test.mapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.mashibing.test.client.CacheClient;
import com.mashibing.test.entity.Channel;
import com.mashibing.test.entity.ClientChannel;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import java.util.Map;
/**
* @author dch
* @create 2024-03-24 18:17
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class ClientChannelMapperTest {
@Autowired
private ClientChannelMapper mapper;
@Autowired
private CacheClient cacheClient;
@Test
public void findAll() throws JsonProcessingException {
List<ClientChannel> list = mapper.findAll();
for (ClientChannel clientChannel : list) {
ObjectMapper objectMapper = new ObjectMapper();
Map map = objectMapper.readValue(objectMapper.writeValueAsString(clientChannel),Map.class);
cacheClient.sadd("client_channel:"+clientChannel.getClientId(),map);
}
}
}

@ -0,0 +1,40 @@
package com.mashibing.test.mapper;
import com.mashibing.test.client.CacheClient;
import com.mashibing.test.entity.MobileArea;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.junit.Assert.*;
/**
* @author dch
* @create 2024-03-22 21:28
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class MobileAreaMapperTest {
@Autowired
private MobileAreaMapper mapper;
@Autowired
private CacheClient cacheClient;
@Test
public void findAll() {
List<MobileArea> list = mapper.findAll();
Map map = new HashMap(list.size());
for(MobileArea mobileArea : list){
map.put("phase:"+mobileArea.getMobileNumber(),mobileArea.getMobileArea()+","+mobileArea.getMobileType());
}
cacheClient.pipelineString(map);
}
}

@ -0,0 +1,41 @@
package com.mashibing.test.mapper;
import com.mashibing.test.client.CacheClient;
import com.mashibing.test.entity.MobileBlack;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* @author dch
* @create 2024-03-24 18:17
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class MobileBlackMapperTest {
@Autowired
private MobileBlackMapper mapper;
@Autowired
private CacheClient cacheClient;
@Test
public void findAll() {
List<MobileBlack> mobileBlackList = mapper.findAll();
for (MobileBlack mobileBlack : mobileBlackList) {
if(mobileBlack.getClientId() == 0){
// 平台级别的黑名单 black:手机号 作为key
cacheClient.set("black:" + mobileBlack.getBlackNumber(),"1");
}else{
// 客户级别的黑名单 black:clientId:手机号
cacheClient.set("black:" + mobileBlack.getClientId() + ":" +mobileBlack.getBlackNumber(),"1");
}
}
}
}

@ -0,0 +1,34 @@
package com.mashibing.test.mapper;
import com.mashibing.test.client.CacheClient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
import static org.junit.Assert.*;
/**
* @author dch
* @create 2024-03-23 0:05
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class MobileDirtyWordMapperTest {
@Autowired
private MobileDirtyWordMapper mapper;
@Autowired
private CacheClient cacheClient;
@Test
public void findAll() {
List<String> dirtyWords = mapper.findDirtyWord();
cacheClient.saddStr("dirty_word", dirtyWords.toArray(new String[]{}));
}
}

@ -0,0 +1,36 @@
package com.mashibing.test.mapper;
import com.mashibing.test.client.CacheClient;
import com.mashibing.test.entity.MobileTransfer;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.List;
/**
* @author dch
* @create 2024-03-24 19:33
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class MobileTransferMapperTest {
@Autowired
private MobileTransferMapper mapper;
@Autowired
private CacheClient cacheClient;
@Test
public void findAll() {
List<MobileTransfer> list = mapper.findAll();
for (MobileTransfer mobileTransfer : list) {
cacheClient.set("transfer:" + mobileTransfer.getTransferNumber(),mobileTransfer.getNowIsp());
}
}
}
Loading…
Cancel
Save