lifuquan преди 2 години
ревизия
39e10b6740

+ 1 - 0
.gitignore

@@ -0,0 +1 @@
+target/

+ 17 - 0
doc/河北垃圾短信监控系统提供的文档/文档中存在的疑问20220725.md

@@ -0,0 +1,17 @@
+# 接口文档中的疑问
+
+1. `C-Octet String	以NULL结束的字符串` 和 `Octet String	无NULL结束` 这里的 C-Octet String 需要如何处理
+
+解答: 末尾添加\0(0x00)
+
+补充提问: `Authcode` 值为共享的认证密码(由垃圾短信监控系统与短信投诉处理系统分别共享)和当前日期经过SHA-1散列后的输出, 这个字段也要求是`20`字节的`C-Octet String`,但是sha1以后就是20字节了,0x00添加在哪儿?
+
+2. `SMIT_ACTIVE_TEST` 时间间隔是多少
+
+3. 解除黑名单请求定义中 `blk_Num` 如何区分 `点对点和网间用户` 和 `端口用户`
+
+4. 解除黑名单请求定义中 `blk_type` 如何区分 `主叫黑名单` 和 `被叫黑名单`  河北垃圾短信监控系统向投诉平台同步黑名单号码接口规范 这个规范里提供的字段不包括`主叫黑名单` 和 `被叫黑名单`
+
+主叫黑名单 是不是不能发短信,被叫黑名单是不是不能收短信?
+
+5. 解除黑名单请求定义中 `province_code` 我们的权限是否仅包含河北省(14), 这里的省份是号码归属省份还是仅仅是这个号码在河北省的黑名单中? 举例,一个山西的号码被添加了河北省黑名单,是不是就是这个山西用户在河北省内漫游时无法收发短信? 

BIN
doc/河北垃圾短信监控系统提供的文档/河北联通垃圾短信一键解黑接口规范.docx


BIN
doc/河北垃圾短信监控系统提供的文档/河北联通垃圾短信黑名单加解黑同步接口规范.doc


+ 27 - 0
doc/短信黑名单接口说明文档.md

@@ -0,0 +1,27 @@
+# 短信黑名单接口说明文档
+
+## 接口1: 黑名单查询接口
+
+```http
+POST HTTP://127.0.0.1:12086/sms/blacklist/api/query/
+Content-Type: application/json
+
+{
+    "phoneNumber": "13231899751",
+    "fromSystem": "test"
+}
+```
+
+
+## 接口2: 黑名单解除接口
+
+```http
+POST HTTP://127.0.0.1:12086/sms/blacklist/api/remove/
+Content-Type: application/json
+
+{
+    "phoneNumber": "13231899751",
+    "fromSystem": "test"
+}
+```
+

+ 50 - 0
pom.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>com.nokia</groupId>
+        <artifactId>hb_springboot_parent</artifactId>
+        <version>1.0</version>
+        <relativePath />
+    </parent>
+
+    <groupId>com.nokia</groupId>
+    <artifactId>smsBlacklistRemoveApi</artifactId>
+    <version>1.0</version>
+
+    <properties>
+        <skipTests>true</skipTests>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.snmp4j</groupId>
+            <artifactId>snmp4j</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <finalName>smsBlacklistRemoveApi</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 6 - 0
readme.md

@@ -0,0 +1,6 @@
+# 短信黑名单接口
+
+[短信黑名单接口说明文档](doc/%E7%9F%AD%E4%BF%A1%E9%BB%91%E5%90%8D%E5%8D%95%E6%8E%A5%E5%8F%A3%E8%AF%B4%E6%98%8E%E6%96%87%E6%A1%A3.md)
+
+## v1.0 20220725
+

+ 67 - 0
src/main/java/com/nokia/common/http/R.java

@@ -0,0 +1,67 @@
+package com.nokia.common.http;
+
+import lombok.Data;
+
+/**
+ * 返回值的统一包装
+ */
+@Data
+public class R {
+    private Boolean success;
+    private Integer code;
+    private String message;
+
+    private Object data = null;
+
+    /**
+     * 私有化构造方法,不允许在外部实例化
+     */
+    private R() {
+    }
+
+    /**
+     * 成功的静态方法
+     *
+     * @return R实例
+     */
+    public static R ok() {
+        R r = new R();
+        r.setSuccess(true);
+        r.setCode(200);
+        r.setMessage("成功");
+        return r;
+    }
+
+    /**
+     * 失败的静态方法
+     *
+     * @return R实例
+     */
+    public static R error() {
+        R r = new R();
+        r.setSuccess(false);
+        r.setCode(500);
+        r.setMessage("失败");
+        return r;
+    }
+
+    public R success(Boolean success) {
+        this.setSuccess(success);
+        return this;
+    }
+
+    public R code(Integer code) {
+        this.setCode(code);
+        return this;
+    }
+
+    public R data(Object object) {
+        this.setData(object);
+        return this;
+    }
+
+    public R message(String message) {
+        this.setMessage(message);
+        return this;
+    }
+}

+ 11 - 0
src/main/java/com/nokia/sms/BlacklistRemoveApplication.java

@@ -0,0 +1,11 @@
+package com.nokia.sms;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class BlacklistRemoveApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(BlacklistRemoveApplication.class, args);
+    }
+}

+ 64 - 0
src/main/java/com/nokia/sms/blacklist/BlacklistTcpClient.java

@@ -0,0 +1,64 @@
+package com.nokia.sms.blacklist;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ * 连接河北联通垃圾短信黑名单系统的socket客户端
+ * 
+ * 接口协议详见 河北联通垃圾短信一键解黑接口规范.doc
+ */
+public class BlacklistTcpClient {
+    // ip和端口号用户名密码 由 河北联通垃圾短信黑名单系统 提供
+    private static String hostIp = "localhost";
+    private static int hostPort = 50000;
+    private static String systemId = "smstousu";
+    private static String password = "123456";
+
+    /**
+     * 解除黑名单
+     * 
+     * @param phoneNumber
+     */
+    public void removeBlacklist(String phoneNumber) {
+        // 获取socket连接
+        Socket client = getSocketConnect();
+        // 发送解除黑名单请求
+        sendMessage(client, getRemoveBlacklistMessage());
+        // 解析解除黑名单请求回应
+    }
+
+    private byte[] getRemoveBlacklistMessage() {
+        return null;
+    }
+
+    /**
+     * 获取socket连接
+     * 
+     * @return
+     */
+    private Socket getSocketConnect() {
+        // 创建socket客户端
+        try (Socket client = new Socket(hostIp, hostPort);
+                OutputStream outputStream = client.getOutputStream();
+                InputStream inputStream = client.getInputStream()) {
+            // 向服务器发送连接请求
+            sendMessage(client, new byte[0]);
+            // 解析服务器返回消息
+
+            // 返回socket连接
+
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    private byte[] sendMessage(Socket socket, byte[] message) {
+
+        return null;
+    }
+
+}

+ 113 - 0
src/main/java/com/nokia/sms/blacklist/RequestMessageUtil.java

@@ -0,0 +1,113 @@
+package com.nokia.sms.blacklist;
+
+import java.nio.ByteBuffer;
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Date;
+
+import org.snmp4j.smi.OctetString;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * 构建由客户端发送给服务器的各类消息
+ * 
+ * 协议参考 河北联通垃圾短信一键解黑接口规范.docx
+ * 
+ * 这里需要注意一下,规范中是c-octet string 需要在末尾加上 0x00
+ */
+@Slf4j
+public class RequestMessageUtil {
+    private static DateFormat dateFormat = new SimpleDateFormat("yyyyMMdd");
+
+    /**
+     * 协议中SMIT_BIND 绑定请求消息
+     * 
+     * @throws NoSuchAlgorithmException
+     */
+    public static byte[] getSmitBindMessage(String username, String password) throws NoSuchAlgorithmException {
+        // header 4+4+4 body 16+20
+        int messageLength = 48;
+        byte[] message = new byte[messageLength];
+        Arrays.fill(message, (byte) 0);
+        // 填充header
+        // 前4个(0-3)字节是 Unsigned Integer 消息长度
+        message[3] = (byte) messageLength;
+        // 4-7字节是消息类型 Command ID SMIT_BIND 绑定请求为 0x00000001
+        message[7] = (byte) 1;
+        // 8-11字节是消息序列号 从0到0XFFFFFFFF之间 请求的应该从0开始
+
+        // 填充body 16+20
+        // system_id 登录用户id username
+        byte[] byteArraySystemId = new OctetString(username).toByteArray();
+        // 把username的字节复制到message 从12开始到27结束 27位应为0x00
+        // 用户名转化成octet字符串后可能小于16位 因此开始位数应该是 28 - byteArraySystemId.length
+        System.arraycopy(byteArraySystemId, 0, message, 27 - byteArraySystemId.length,
+                byteArraySystemId.length);
+        // authcode 28位开始 共 20位
+        byte[] octetAuthcode = new OctetString(password + dateFormat.format(new Date())).toByteArray();
+        MessageDigest digest = MessageDigest.getInstance("SHA-1");
+        // sha1后正好20位
+        octetAuthcode = digest.digest(octetAuthcode);
+        System.arraycopy(octetAuthcode, 0, message, 28, 20);
+        log.debug("已完成SMIT_BIND消息组装: {}", Arrays.toString(message));
+        return message;
+    }
+
+    /**
+     * 协议中SMIT_ACTIVE_TEST 链路检测请求 消息
+     */
+    public static byte[] getSmitAciveTestMessage(long messageCount) {
+        // header 4+4+4 body为空
+        int messageLength = 12;
+        byte[] message = new byte[messageLength];
+        Arrays.fill(message, (byte) 0);
+        // 填充header
+        // 前4个(0-3)字节是 Unsigned Integer 消息长度
+        message[3] = (byte) messageLength;
+        // 4-7字节是消息类型 SMIT_ACTIVE_TEST 0x0000000f 链路检测
+        message[7] = (byte) 15;
+        // 8-11字节是消息序列号 从0到0XFFFFFFFF之间 请求的应该从0开始
+        ByteBuffer byteBuffer = ByteBuffer.allocate(8);
+        byteBuffer.putLong(0, messageCount);
+        // java中没有unsigned integer 用long表示以后需要截取后4位byte
+        System.arraycopy(byteBuffer.array(), 4, message, 8, 4);
+        return message;
+    }
+
+    /**
+     * 协议中的 SMIT_DELBLK 0x00000003 解除黑名单请求 消息
+     */
+    public static byte[] getSmitDelblkMessage(long messageCount, String phoneNumber, boolean isMo) {
+        // header 4+4+4 body为21+1+1+1
+        int messageLength = 36;
+        byte[] message = new byte[messageLength];
+        Arrays.fill(message, (byte) 0);
+
+        // 填充header
+        // 前4个(0-3)字节是 Unsigned Integer 消息长度
+        message[3] = (byte) messageLength;
+        // 4-7字节是消息类型 SMIT_DELBLK 0x00000003 解除黑名单请求
+        message[7] = (byte) 3;
+        // 8-11字节是消息序列号 从0到0XFFFFFFFF之间 请求的应该从0开始
+        ByteBuffer byteBuffer = ByteBuffer.allocate(8);
+        byteBuffer.putLong(0, messageCount);
+        // java中没有unsigned integer 用long表示以后需要截取后4位byte
+        System.arraycopy(byteBuffer.array(), 4, message, 8, 4);
+
+        // 填充body
+        // 11-32字节 blk_num 21字节 点对点和网间用户黑名单号码带86,端口用户黑名单号码不带86
+        byte[] blk_num = new OctetString(phoneNumber).toByteArray();
+        System.arraycopy(blk_num, 0, message, 33 - blk_num.length, blk_num.length);
+        // 33字节 blk_type 1 黑名单号码 2 黑名单
+        message[33] = (byte) 1;
+        // 34字节
+        message[34] = (byte) (isMo ? 1 : 2);
+        // 35字节
+        message[35] = (byte) 14;
+        return message;
+    }
+}

+ 31 - 0
src/main/java/com/nokia/sms/blacklist/ResponMessageUtil.java

@@ -0,0 +1,31 @@
+package com.nokia.sms.blacklist;
+
+import java.nio.ByteBuffer;
+
+/**
+ * 构建由客户端发送给服务器的各类消息
+ * 
+ * 协议参考 河北联通垃圾短信一键解黑接口规范.docx
+ */
+public class ResponMessageUtil {
+
+    /**
+     * 从buffer的从offset开始的4个字节中读取一个无符号整数,以long的类型返回
+     * 
+     * @param buffer 字节数组
+     * @param offset 起始位置
+     * @return long类型表示的一个无符号整数
+     */
+    private static long getUnsignedIntegerFromBytes(byte[] buffer, int offset) {
+        // 识别
+        byte[] byteArr = new byte[8];
+        int size = buffer.length - offset;
+        if (size >= 4) {
+            System.arraycopy(buffer, offset, byteArr, 4, 4);
+        } else {
+            System.arraycopy(buffer, offset, byteArr, 8 - size, size);
+        }
+
+        return ByteBuffer.wrap(byteArr).getLong();
+    }
+}

+ 47 - 0
src/main/java/com/nokia/sms/controller/BlacklistController.java

@@ -0,0 +1,47 @@
+package com.nokia.sms.controller;
+
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import com.nokia.common.http.R;
+import com.nokia.sms.service.BlacklistService;
+import com.nokia.sms.vo.RequestParms;
+
+/**
+ * 黑名单查询及解除接口类
+ */
+@RestController
+@RequestMapping("/sms/blacklist/api/")
+public class BlacklistController {
+
+    private final BlacklistService blacklistService;
+
+    public BlacklistController(BlacklistService blacklistService) {
+        this.blacklistService = blacklistService;
+    }
+
+    /**
+     * 查询结构
+     */
+    public R query(@RequestBody RequestParms parms) {
+        // 查询结果
+        
+        // 根据结果进行返回
+        return R.ok();
+    }
+
+    /**
+     * 黑名单解除接口
+     */
+    public R remove(@RequestBody RequestParms parms) {
+        // 尝试解除黑名单
+        boolean result = blacklistService.remove(parms);
+        if (result) {
+            return R.ok().message("成功解除黑名单");
+        } else {
+            return R.error().message("解除黑名单失败");
+        }
+
+    }
+}

+ 22 - 0
src/main/java/com/nokia/sms/service/BlacklistService.java

@@ -0,0 +1,22 @@
+package com.nokia.sms.service;
+
+import org.springframework.stereotype.Service;
+
+import com.nokia.sms.vo.RequestParms;
+
+/**
+ * 黑名单查询及解除业务层
+ */
+@Service
+public class BlacklistService {
+
+    /**
+     * 解除黑名单
+     * 
+     * @param parms
+     * @return
+     */
+    public boolean remove(RequestParms parms) {
+        return false;
+    }
+}

+ 10 - 0
src/main/java/com/nokia/sms/vo/RequestParms.java

@@ -0,0 +1,10 @@
+package com.nokia.sms.vo;
+
+import lombok.Data;
+
+@Data
+public class RequestParms {
+
+    private String phoneNumber;
+    private String fromSystem;
+}

+ 1 - 0
src/main/resources/application.properties

@@ -0,0 +1 @@
+server.port=12086

+ 26 - 0
src/test/java/com/nokia/sms/blacklist/RequestMessageUtilTest.java

@@ -0,0 +1,26 @@
+package com.nokia.sms.blacklist;
+
+import java.security.NoSuchAlgorithmException;
+import java.util.Arrays;
+
+import org.junit.jupiter.api.Test;
+
+public class RequestMessageUtilTest {
+    @Test
+    void testGetSmitBindMessage() throws NoSuchAlgorithmException {
+        byte[] message = RequestMessageUtil.getSmitBindMessage("username", "123456");
+        System.out.println(Arrays.toString(message));
+    }
+
+    @Test
+    void testGetSmitAciveTestMessage() {
+        byte[] message = RequestMessageUtil.getSmitAciveTestMessage(2);
+        System.out.println(Arrays.toString(message));
+    }
+
+    @Test
+    void testGetSmitDelblkMessage() {
+        byte[] message = RequestMessageUtil.getSmitDelblkMessage(3, "13231899751", true);
+        System.out.println(Arrays.toString(message));
+    }
+}