Pārlūkot izejas kodu

加入队列和重试

weijianghai 2 gadi atpakaļ
vecāks
revīzija
f4e6c590ac

+ 69 - 22
pom.xml

@@ -7,13 +7,18 @@
     <version>1.0</version>
 
     <parent>
-        <groupId>com.nokia</groupId>
-        <artifactId>hb_springboot_parent</artifactId>
-        <version>1.0</version>
-        <relativePath />
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.6.14</version>
+        <relativePath/> <!-- lookup parent from repository -->
     </parent>
 
     <properties>
+        <java.version>8</java.version>
+        <maven.compiler.source>${java.version}</maven.compiler.source>
+        <maven.compiler.target>${java.version}</maven.compiler.target>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>${project.build.sourceEncoding}</project.reporting.outputEncoding>
         <skipTests>true</skipTests>
     </properties>
 
@@ -22,14 +27,17 @@
         <dependency>
             <groupId>org.apache.mina</groupId>
             <artifactId>mina-core</artifactId>
+            <version>2.0.23</version>
         </dependency>
         <dependency>
             <groupId>commons-configuration</groupId>
             <artifactId>commons-configuration</artifactId>
+            <version>1.10</version>
         </dependency>
         <dependency>
             <groupId>org.mybatis.spring.boot</groupId>
             <artifactId>mybatis-spring-boot-starter</artifactId>
+            <version>2.2.2</version>
         </dependency>
         <dependency>
             <groupId>org.postgresql</groupId>
@@ -49,31 +57,70 @@
             <artifactId>lombok</artifactId>
             <scope>provided</scope>
         </dependency>
+        <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>2.0.22</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-configuration-processor</artifactId>
+            <optional>true</optional>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+            <version>5.8.10</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
     <build>
         <finalName>sms_server</finalName>
-        <resources>
-            <resource>
-                <directory>${project.basedir}/src/main/resources</directory>
-                <targetPath></targetPath>
-                <includes>
-                    <include>**/*.*</include>
-                </includes>
-            </resource>
-        </resources>
-        <testSourceDirectory>src/test</testSourceDirectory>
+<!--        <resources>-->
+<!--            <resource>-->
+<!--                <directory>${project.basedir}/src/main/resources</directory>-->
+<!--                <targetPath></targetPath>-->
+<!--                <includes>-->
+<!--                    <include>**/*.*</include>-->
+<!--                </includes>-->
+<!--            </resource>-->
+<!--        </resources>-->
+<!--        <testSourceDirectory>src/test</testSourceDirectory>-->
         <plugins>
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-compiler-plugin</artifactId>
-                <configuration>
-                    <source>1.8</source>
-                    <target>1.8</target>
-                </configuration>
-            </plugin>
+<!--            <plugin>-->
+<!--                <groupId>org.apache.maven.plugins</groupId>-->
+<!--                <artifactId>maven-compiler-plugin</artifactId>-->
+<!--                <configuration>-->
+<!--                    <source>1.8</source>-->
+<!--                    <target>1.8</target>-->
+<!--                </configuration>-->
+<!--            </plugin>-->
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>${project.parent.version}</version>
+                <executions>
+                    <execution>
+                        <id>repackage</id>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+                <configuration>
+                    <excludes>
+                        <exclude>
+                            <groupId>org.projectlombok</groupId>
+                            <artifactId>lombok</artifactId>
+                        </exclude>
+                        <exclude>
+                            <groupId>org.springframework.boot</groupId>
+                            <artifactId>spring-boot-configuration-processor</artifactId>
+                        </exclude>
+                    </excludes>
+                </configuration>
             </plugin>
         </plugins>
     </build>

+ 2 - 1
src/main/java/com/nokia/common/http/R.java

@@ -1,6 +1,7 @@
 package com.nokia.common.http;
 
 import lombok.Data;
+import org.slf4j.MDC;
 
 /**
  * 接口返回值的统一封装
@@ -41,7 +42,7 @@ public class R {
         R r = new R();
         r.setSuccess(false);
         r.setCode(500);
-        r.setMessage("失败");
+        r.setMessage("失败" + MDC.get("traceId"));
         return r;
     }
 

+ 17 - 0
src/main/java/com/nokia/sms/config/SchedulerConfig.java

@@ -0,0 +1,17 @@
+//package com.nokia.sms.config;
+//
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+//
+//@Configuration
+//public class SchedulerConfig {
+//    @Bean
+//    public ThreadPoolTaskScheduler scheduler() {
+//        ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
+//        scheduler.setThreadNamePrefix("scheduler-");
+//        scheduler.setPoolSize(100);
+//        scheduler.initialize();
+//        return scheduler;
+//    }
+//}

+ 14 - 0
src/main/java/com/nokia/sms/config/web/MyDispatcherServlet.java

@@ -0,0 +1,14 @@
+package com.nokia.sms.config.web;
+
+import org.springframework.web.servlet.DispatcherServlet;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class MyDispatcherServlet extends DispatcherServlet {
+    @Override
+    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
+        // 替换request和response
+        super.doDispatch(new MyHttpServletRequestWrapper(request), new MyHttpServletResponseWrapper(response));
+    }
+}

+ 54 - 0
src/main/java/com/nokia/sms/config/web/MyHttpServletRequestWrapper.java

@@ -0,0 +1,54 @@
+package com.nokia.sms.config.web;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.util.StreamUtils;
+
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import java.io.*;
+
+/**
+ * 解决流只能读取一次问题
+ */
+@Slf4j
+public class MyHttpServletRequestWrapper extends HttpServletRequestWrapper {
+    private byte[] bytes;
+
+    public MyHttpServletRequestWrapper(HttpServletRequest request) throws IOException {
+        super(request);
+        bytes = StreamUtils.copyToByteArray(request.getInputStream());
+    }
+
+    @Override
+    public ServletInputStream getInputStream() {
+        ByteArrayInputStream stream = new ByteArrayInputStream(bytes);
+        return new ServletInputStream() {
+            @Override
+            public boolean isFinished() {
+                return false;
+            }
+
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener) {
+                //
+            }
+
+            @Override
+            public int read() {
+                return stream.read();
+            }
+        };
+    }
+
+    @Override
+    public BufferedReader getReader() throws UnsupportedEncodingException {
+        return new BufferedReader(new InputStreamReader(getInputStream(), super.getCharacterEncoding()));
+    }
+}

+ 47 - 0
src/main/java/com/nokia/sms/config/web/MyHttpServletResponseWrapper.java

@@ -0,0 +1,47 @@
+package com.nokia.sms.config.web;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.WriteListener;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpServletResponseWrapper;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+
+/**
+ * 解决流只能读取一次问题
+ */
+public class MyHttpServletResponseWrapper extends HttpServletResponseWrapper {
+    private ByteArrayOutputStream byteArrayOutputStream;
+    private ServletOutputStream servletOutputStream;
+
+    public MyHttpServletResponseWrapper(HttpServletResponse response) {
+        super(response);
+        byteArrayOutputStream = new ByteArrayOutputStream();
+        servletOutputStream = new ServletOutputStream() {
+            @Override
+            public boolean isReady() {
+                return false;
+            }
+
+            @Override
+            public void setWriteListener(WriteListener writeListener) {
+                //
+            }
+
+            @Override
+            public void write(int b) throws IOException {
+                response.getOutputStream().write(b);
+                byteArrayOutputStream.write(b);
+            }
+        };
+    }
+
+    @Override
+    public ServletOutputStream getOutputStream() {
+        return servletOutputStream;
+    }
+
+    public byte[] toByteArray() {
+        return byteArrayOutputStream.toByteArray();
+    }
+}

+ 27 - 0
src/main/java/com/nokia/sms/config/web/MyWebMvcConfigurer.java

@@ -0,0 +1,27 @@
+package com.nokia.sms.config.web;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.DispatcherServlet;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+@Configuration
+public class MyWebMvcConfigurer implements WebMvcConfigurer {
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        // 添加请求日志拦截
+        registry.addInterceptor(new RequestLogHandlerInterceptor()).addPathPatterns("/**");
+    }
+
+    /**
+     * 使用自定义DispatcherServlet
+     */
+    @Bean
+    @Qualifier(DispatcherServletAutoConfiguration.DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
+    public DispatcherServlet dispatcherServlet() {
+        return new MyDispatcherServlet();
+    }
+}

+ 70 - 0
src/main/java/com/nokia/sms/config/web/RequestLogHandlerInterceptor.java

@@ -0,0 +1,70 @@
+package com.nokia.sms.config.web;
+
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.MDC;
+import org.springframework.lang.Nullable;
+import org.springframework.util.StopWatch;
+import org.springframework.util.StreamUtils;
+import org.springframework.util.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.nio.charset.Charset;
+import java.util.UUID;
+
+/**
+ * 请求日志拦截器
+ */
+@Slf4j
+public class RequestLogHandlerInterceptor implements HandlerInterceptor {
+    /**
+     * 计时器线程变量
+     */
+    private static final ThreadLocal<StopWatch> STOP_WATCH_THREAD_LOCAL = new ThreadLocal<>();
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        StopWatch stopWatch = new StopWatch();
+        stopWatch.start();
+        // 计时器放入线程变量
+        STOP_WATCH_THREAD_LOCAL.set(stopWatch);
+        // 日志添加跟踪id
+        MDC.put("traceId", UUID.randomUUID().toString().replace("-", ""));
+        log.info("请求地址: {} {}", request.getRequestURL().toString(), request.getMethod());
+//        // 请求头参数
+//        Map<String, String> headers = new HashMap<>();
+//        Enumeration<String> headerNames = request.getHeaderNames();
+//        while (headerNames.hasMoreElements()) {
+//            String k	= headerNames.nextElement();
+//            String v = request.getHeader(k);
+//            headers.put(k, v);
+//        }
+//        log.info("请求头参数: {}", JSON.toJSONString(headers));
+//        // 查询参数
+//        Map<String, String> parameters = new HashMap<>();
+//        Enumeration<String> parameterNames = request.getParameterNames();
+//        while (parameterNames.hasMoreElements()) {
+//            String k	= parameterNames.nextElement();
+//            String v = request.getParameter(k);
+//            parameters.put(k, v);
+//        }
+//        log.info("查询参数: {}", JSON.toJSONString(parameters));
+        // 请求体参数
+        String body = StreamUtils.copyToString(request.getInputStream(), Charset.forName(request.getCharacterEncoding()));
+        log.info("请求参数: {}", StringUtils.trimAllWhitespace(body));
+        return true;
+    }
+
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
+                                @Nullable Exception ex) throws Exception {
+        MyHttpServletResponseWrapper wrapper = (MyHttpServletResponseWrapper) response;
+        String responseString = new String(wrapper.toByteArray(), Charset.forName(request.getCharacterEncoding()));
+        log.info("返回 {}: {}", wrapper.getStatus(), responseString);
+        StopWatch stopWatch = STOP_WATCH_THREAD_LOCAL.get();
+        stopWatch.stop();
+        log.info("耗时 {} ms", stopWatch.getTotalTimeMillis());
+        STOP_WATCH_THREAD_LOCAL.remove();
+    }
+}

+ 5 - 14
src/main/java/com/nokia/sms/controller/SmsController.java

@@ -1,24 +1,21 @@
 package com.nokia.sms.controller;
 
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-
 import com.nokia.common.http.R;
 import com.nokia.sms.pojo.Sms;
 import com.nokia.sms.service.SgipSmsService;
 import com.nokia.sms.service.UserService;
 import com.nokia.sms.vo.MultiNumberSms;
 import com.nokia.sms.vo.SingleNumberSms;
-
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
 
 @Slf4j
 @RestController
 @RequestMapping("/api/sms")
 public class SmsController {
-
     private final SgipSmsService smsService;
     private final UserService userService;
 
@@ -82,12 +79,6 @@ public class SmsController {
     }
 
     private R send(Sms sms) {
-        String result = smsService.sendMessage(sms);
-        log.debug("发送结果----{}", result);
-        if ("成功".equals(result)) {
-            return R.ok();
-        } else {
-            return R.error().message(sms.getStatus());
-        }
+        return smsService.offer(sms);
     }
 }

+ 4 - 3
src/main/java/com/nokia/sms/pojo/Sms.java

@@ -1,12 +1,12 @@
 package com.nokia.sms.pojo;
 
-import java.util.Date;
-
 import com.nokia.sms.vo.MultiNumberSms;
 import com.nokia.sms.vo.SingleNumberSms;
-
 import lombok.Data;
 
+import java.util.Date;
+import java.util.concurrent.atomic.AtomicInteger;
+
 @Data
 public class Sms {
 
@@ -21,6 +21,7 @@ public class Sms {
     private String result;
     private Date sendTime;
     private String status;
+    private AtomicInteger count = new AtomicInteger(0);
 
     public Sms() {
     }

+ 87 - 16
src/main/java/com/nokia/sms/service/SgipSmsService.java

@@ -1,33 +1,60 @@
 package com.nokia.sms.service;
 
-import java.util.Arrays;
-import java.util.Date;
-import java.util.UUID;
-
-import org.springframework.stereotype.Service;
-
+import com.alibaba.fastjson2.JSON;
+import com.nokia.common.http.R;
 import com.nokia.sms.dao.SmsDao;
 import com.nokia.sms.pojo.Sms;
 import com.nokia.sms.sgip.message.SendResult;
 import com.nokia.sms.sgip.mt.client.MTClient;
-
+import lombok.Data;
 import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import java.util.Arrays;
+import java.util.Date;
+import java.util.UUID;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.LinkedBlockingQueue;
 
 @Slf4j
 @Service
+@Data
+@ConfigurationProperties("sms")
 public class SgipSmsService {
-
+    static final LinkedBlockingQueue<Sms> QUEUE = new LinkedBlockingQueue<>();
     private final SmsDao smsDao;
 
+    /**
+     * 最大重试次数
+     */
+    private Integer maxRetry;
+
     public SgipSmsService(SmsDao smsDao) {
         this.smsDao = smsDao;
     }
 
-    public String sendMessage(Sms sms) {
-        log.debug("准备发送短信: {}", sms);
-        sms.setId(UUID.randomUUID().toString());
-        sms.setSendTime(new Date());
+    /**
+     * 短信放入队列
+     *
+     * @param sms 短信
+     * @return {@link R}
+     */
+    public R offer(Sms sms) {
+        if (QUEUE.offer(sms)) {
+            return R.ok();
+        } else {
+            log.error("入队失败");
+            return R.error();
+        }
+    }
+
+    public void sendMessage(Sms sms) {
         try {
+            log.debug("准备发送短信: {}", JSON.toJSONString(sms));
+            sms.setId(UUID.randomUUID().toString());
+            sms.setSendTime(new Date());
             // 获取单例的MTClient
             MTClient client = MTClient.getInstance();
             // 发送短信
@@ -36,15 +63,59 @@ public class SgipSmsService {
             // 销毁应用
             client.dispose();
             sms.setResult(Arrays.toString(results));
+//            if (ThreadLocalRandom.current().nextBoolean()) {
+//                throw new RuntimeException("异常测试");
+//            }
             sms.setStatus("已发送到短信网关");
-            return "成功";
+            log.info("短信发送成功: {}", JSON.toJSONString(sms));
         } catch (Exception e) {
-            log.error("短信发送失败, 短信: {}, 错误信息: {}", sms, e.getMessage());
             sms.setStatus("发送到短信网关失败");
-            e.printStackTrace();
-            return sms.getStatus();
+            log.error("短信发送失败, 短信: {}, 错误信息: {}", sms, e.getMessage());
+            log.error(e.getMessage(), e);
+            // 重试次数小于最大重试次数进行重试
+            if (sms.getCount().getAndIncrement() < maxRetry) {
+                retry(sms);
+            }
         } finally {
             smsDao.insert(sms);
+            log.debug("insert: {}", JSON.toJSONString(sms));
+        }
+    }
+
+    /**
+     * 消费队列发送短信
+     */
+    @PostConstruct
+    public void consumer() {
+        CompletableFuture.runAsync(() -> {
+            while (true) {
+                Sms sms = null;
+                try {
+                    sms = QUEUE.take();
+                } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
+                    log.error(e.getMessage(), e);
+                }
+                if (sms == null) {
+                    continue;
+                }
+                sendMessage(sms);
+            }
+        });
+    }
+
+    /**
+     * 重试
+     *
+     * @param sms 短信
+     */
+    void retry(Sms sms) {
+//        Instant startTime = Instant.now().plusSeconds(retryDelay);
+//        scheduler.schedule(() -> sendMessage(sms), startTime);
+        if (QUEUE.offer(sms)) {
+            log.info("重新入队: {}", JSON.toJSONString(sms));
+        } else {
+            log.error("重新入队失败: {}", JSON.toJSONString(sms));
         }
     }
 }

+ 10 - 6
src/main/java/com/nokia/sms/sgip/message/DeliverMessage.java

@@ -1,13 +1,14 @@
 package com.nokia.sms.sgip.message;
 
+import com.nokia.sms.sgip.codec.MessageUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.mina.core.buffer.IoBuffer;
+
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.nio.charset.CharsetDecoder;
 
-import org.apache.mina.core.buffer.IoBuffer;
-
-import com.nokia.sms.sgip.codec.MessageUtil;
-
+@Slf4j
 public class DeliverMessage extends SgipMessage {
     public static final int COMMAND_ID = 4;
     private String userNumber;
@@ -19,6 +20,7 @@ public class DeliverMessage extends SgipMessage {
     private String messageContent;
     private String reserve;
 
+    @Override
     public IoBuffer getBuffer() {
         IoBuffer buffer = IoBuffer.allocate(200).setAutoExpand(true);
         buffer.position(20);
@@ -41,7 +43,7 @@ public class DeliverMessage extends SgipMessage {
                 content = this.messageContent.getBytes("GBK");
             }
         } catch (UnsupportedEncodingException e) {
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
         }
         this.messageLength = content.length;
         buffer.putInt(this.messageLength);
@@ -64,6 +66,7 @@ public class DeliverMessage extends SgipMessage {
         return buffer.flip();
     }
 
+    @Override
     public void parseBody(IoBuffer ioBuffer)
             throws IOException {
         this.userNumber = ioBuffer.getString(21, MessageUtil.gbkDecoder);
@@ -96,7 +99,7 @@ public class DeliverMessage extends SgipMessage {
                 bytes = this.messageContent.getBytes("GBK");
             }
         } catch (UnsupportedEncodingException e) {
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
         }
         return bytes;
     }
@@ -165,6 +168,7 @@ public class DeliverMessage extends SgipMessage {
         this.reserve = reserve;
     }
 
+    @Override
     public String toString() {
         return "DeliverMessage [head=" + this.head + ", messageContent=" + this.messageContent + ", messageLength="
                 + this.messageLength + ", reserve=" + this.reserve + ", spNumber=" + this.spNumber + ", tppid="

+ 9 - 5
src/main/java/com/nokia/sms/sgip/message/SubmitMessage.java

@@ -1,13 +1,14 @@
 package com.nokia.sms.sgip.message;
 
+import com.nokia.sms.sgip.codec.MessageUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.mina.core.buffer.IoBuffer;
+
 import java.io.IOException;
 import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 
-import org.apache.mina.core.buffer.IoBuffer;
-
-import com.nokia.sms.sgip.codec.MessageUtil;
-
+@Slf4j
 public class SubmitMessage extends SgipMessage {
     public static final int COMMAND_ID = 3;
     private String spNumber;
@@ -33,6 +34,7 @@ public class SubmitMessage extends SgipMessage {
     private byte[] messageContent;
     private String reserve;
 
+    @Override
     public IoBuffer getBuffer() {
         IoBuffer buffer = IoBuffer.allocate(200).setAutoExpand(true);
         buffer.position(20);
@@ -102,6 +104,7 @@ public class SubmitMessage extends SgipMessage {
         return buffer.flip();
     }
 
+    @Override
     public void parseBody(IoBuffer ioBuffer)
             throws IOException {
         this.spNumber = ioBuffer.getString(21, MessageUtil.gbkDecoder);
@@ -308,6 +311,7 @@ public class SubmitMessage extends SgipMessage {
         this.reserve = reserve;
     }
 
+    @Override
     public String toString() {
         String content = null;
         try {
@@ -319,7 +323,7 @@ public class SubmitMessage extends SgipMessage {
                 content = new String(this.messageContent, "UTF-8");
             }
         } catch (UnsupportedEncodingException e) {
-            e.printStackTrace();
+            log.error(e.getMessage(), e);
         }
         return "SubmitMessage [head=" + this.head + ",spNumber=" + this.spNumber + ",chargeNumber=" + this.chargeNumber
                 + ",userCount=" + this.userCount + ",userNumber=" + Arrays.toString(this.userNumber) + ",corpId="

+ 12 - 13
src/main/java/com/nokia/sms/sgip/mo/server/MOServer.java

@@ -1,25 +1,23 @@
 package com.nokia.sms.sgip.mo.server;
 
-import java.io.IOException;
-import java.net.InetSocketAddress;
-import java.util.concurrent.ThreadPoolExecutor;
-
+import com.nokia.sms.sgip.SgipConfig;
+import com.nokia.sms.sgip.codec.SgipCodecFactory;
+import com.nokia.sms.sgip.filter.SGIPLoggingFilter;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.configuration.CompositeConfiguration;
 import org.apache.mina.core.filterchain.IoFilter;
 import org.apache.mina.core.service.IoAcceptor;
 import org.apache.mina.core.session.IdleStatus;
-import org.apache.mina.filter.logging.LogLevel;
-import org.apache.mina.filter.logging.LoggingFilter;
-import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
 import org.apache.mina.filter.codec.ProtocolCodecFilter;
 import org.apache.mina.filter.executor.ExecutorFilter;
 import org.apache.mina.filter.executor.UnorderedThreadPoolExecutor;
+import org.apache.mina.filter.logging.LogLevel;
+import org.apache.mina.filter.logging.LoggingFilter;
+import org.apache.mina.transport.socket.nio.NioSocketAcceptor;
 
-import com.nokia.sms.sgip.SgipConfig;
-import com.nokia.sms.sgip.codec.SgipCodecFactory;
-import com.nokia.sms.sgip.filter.SGIPLoggingFilter;
-
-import lombok.extern.slf4j.Slf4j;
+import java.io.IOException;
+import java.net.InetSocketAddress;
+import java.util.concurrent.ThreadPoolExecutor;
 
 @Slf4j
 public class MOServer {
@@ -74,7 +72,8 @@ public class MOServer {
             try {
                 Thread.sleep(100L);
             } catch (InterruptedException e) {
-                log.error("", e);
+                Thread.currentThread().interrupt();
+                log.error(e.getMessage(), e);
             }
             ThreadPoolExecutor service = (ThreadPoolExecutor) exceutor.getExecutor();
             service.shutdownNow();

+ 24 - 26
src/main/java/com/nokia/sms/sgip/mt/client/MTClient.java

@@ -1,16 +1,15 @@
 package com.nokia.sms.sgip.mt.client;
 
-import java.io.UnsupportedEncodingException;
-import java.net.InetSocketAddress;
-import java.text.DateFormat;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.FutureTask;
-import java.util.concurrent.ThreadPoolExecutor;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
+import com.nokia.sms.sgip.RespCaller;
+import com.nokia.sms.sgip.SgipConfig;
+import com.nokia.sms.sgip.codec.MessageUtil;
+import com.nokia.sms.sgip.codec.SgipCodecFactory;
+import com.nokia.sms.sgip.filter.SGIPLoggingFilter;
+import com.nokia.sms.sgip.message.BindMessage;
+import com.nokia.sms.sgip.message.SendResult;
+import com.nokia.sms.sgip.message.SubmitMessage;
+import com.nokia.sms.sgip.message.UnBindMessage;
+import lombok.extern.slf4j.Slf4j;
 import org.apache.commons.configuration.CompositeConfiguration;
 import org.apache.mina.core.RuntimeIoException;
 import org.apache.mina.core.filterchain.IoFilter;
@@ -19,23 +18,18 @@ import org.apache.mina.core.future.WriteFuture;
 import org.apache.mina.core.service.IoConnector;
 import org.apache.mina.core.session.IdleStatus;
 import org.apache.mina.core.session.IoSession;
-import org.apache.mina.filter.logging.LogLevel;
-import org.apache.mina.transport.socket.nio.NioSocketConnector;
 import org.apache.mina.filter.codec.ProtocolCodecFilter;
 import org.apache.mina.filter.executor.ExecutorFilter;
 import org.apache.mina.filter.executor.UnorderedThreadPoolExecutor;
+import org.apache.mina.filter.logging.LogLevel;
+import org.apache.mina.transport.socket.nio.NioSocketConnector;
 
-import com.nokia.sms.sgip.RespCaller;
-import com.nokia.sms.sgip.SgipConfig;
-import com.nokia.sms.sgip.codec.MessageUtil;
-import com.nokia.sms.sgip.codec.SgipCodecFactory;
-import com.nokia.sms.sgip.filter.SGIPLoggingFilter;
-import com.nokia.sms.sgip.message.BindMessage;
-import com.nokia.sms.sgip.message.SubmitMessage;
-import com.nokia.sms.sgip.message.UnBindMessage;
-import com.nokia.sms.sgip.message.SendResult;
-
-import lombok.extern.slf4j.Slf4j;
+import java.io.UnsupportedEncodingException;
+import java.net.InetSocketAddress;
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.concurrent.*;
 
 @Slf4j
 public class MTClient {
@@ -94,7 +88,8 @@ public class MTClient {
                     try {
                         Thread.sleep(1000L);
                     } catch (InterruptedException e) {
-                        e.printStackTrace();
+                        Thread.currentThread().interrupt();
+                        log.error(e.getMessage(), e);
                     }
                     connectResult = connect();
                     if (connectResult == 0) {
@@ -140,6 +135,7 @@ public class MTClient {
                     result = ((Byte) task.get(SgipConfig.getConfig().getLong("submit_time_out", 20L), TimeUnit.SECONDS))
                             .byteValue();
                 } catch (InterruptedException e) {
+                    Thread.currentThread().interrupt();
                     this.session.removeAttribute("Call" + flowId);
                     this.session.removeAttribute("Future" + flowId);
                     log.error("", e);
@@ -195,6 +191,7 @@ public class MTClient {
                 result = ((Byte) task.get(SgipConfig.getConfig().getLong("submit_time_out", 20L), TimeUnit.SECONDS))
                         .byteValue();
             } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
                 session.removeAttribute("Call" + flowId);
                 session.removeAttribute("Future" + flowId);
                 log.error("", e);
@@ -363,7 +360,8 @@ public class MTClient {
         try {
             Thread.sleep(100L);
         } catch (InterruptedException e) {
-            log.error("", e);
+            Thread.currentThread().interrupt();
+            log.error(e.getMessage(), e);
         }
         if (exceutor != null) {
             ThreadPoolExecutor service = (ThreadPoolExecutor) exceutor.getExecutor();

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

@@ -1,10 +1,11 @@
 server.port=12080
 
 logging.level.com.nokia=debug
-logging.file.name=logs/sms_server.log
+#logging.file.name=logs/sms_server.log
 
 # 正式环境数据源GP数据库配置
 spring.datasource.driver-class-name=org.postgresql.Driver
 spring.datasource.url=jdbc:postgresql://192.168.70.109:5432/sqmmt
 spring.datasource.username=sqmdb
 spring.datasource.password=sqmdb_1QAZ
+sms.max-retry=1

+ 50 - 0
src/main/resources/logback-spring.xml

@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <property name="PATH" value="./log"/>
+    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+        <encoder>
+            <Pattern>%d{HH:mm:ss.SSS} %highlight(%-5level) %yellow(%X{traceId}) %magenta([%thread]) %cyan(%logger:%line) %msg%n</Pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+    <appender name="TRACE_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${PATH}/trace.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- rollover daily -->
+            <fileNamePattern>${PATH}/trace.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
+            <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>60</maxHistory>
+            <totalSizeCap>20GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <Pattern>%d %-5level %X{traceId} [%thread] %logger:%line %msg%n</Pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+    </appender>
+    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${PATH}/error.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
+            <!-- rollover daily -->
+            <fileNamePattern>${PATH}/error.%d{yyyy-MM-dd_HH}.%i.log</fileNamePattern>
+            <!-- each file should be at most 100MB, keep 60 days worth of history, but at most 20GB -->
+            <maxFileSize>50MB</maxFileSize>
+            <maxHistory>60</maxHistory>
+            <totalSizeCap>20GB</totalSizeCap>
+        </rollingPolicy>
+        <encoder>
+            <Pattern>%d %-5level %X{traceId} [%thread] %logger:%line %msg%n</Pattern>
+            <charset>UTF-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>ERROR</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <root level="INFO">
+        <appender-ref ref="STDOUT"/>
+        <appender-ref ref="TRACE_FILE"/>
+        <appender-ref ref="ERROR_FILE"/>
+    </root>
+</configuration>

+ 39 - 0
src/test/com/nokia/sms/service/OtherTest.java

@@ -0,0 +1,39 @@
+package com.nokia.sms.service;
+
+import cn.hutool.core.util.IdUtil;
+import cn.hutool.core.util.RandomUtil;
+import com.alibaba.fastjson2.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.client.RestTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import java.util.stream.Stream;
+
+@Slf4j
+class OtherTest {
+    @Test
+    void test() {
+        String url = "http://localhost:12080/api/sms/sendByPhoneNumber";
+        CompletableFuture.allOf(Stream.iterate(1L, n -> n + 1).limit(10).map(t ->
+                CompletableFuture.runAsync(() -> {
+                    RestTemplate template = new RestTemplate();
+                    Map<Object, Object> m = new HashMap<>();
+                    m.put("fromSystem", "test");
+                    m.put("smsType", "test");
+                    m.put("internalId", "000001");
+                    m.put("phoneNumber", RandomUtil.randomLong(13000000000L, 13999999999L));
+                    m.put("content", "测试" + IdUtil.fastSimpleUUID());
+                    log.info("m: {}", JSON.toJSONString(m));
+                    try {
+                        ResponseEntity<Object> r = template.postForEntity(url, m, Object.class);
+                        log.info("{} -> {}", r.getStatusCodeValue(), r.getBody());
+                    } catch (Exception e) {
+                        log.error(e.getMessage(), e);
+                    }
+                })).toArray(CompletableFuture[]::new)).join();
+    }
+}

+ 4 - 5
src/test/com/nokia/sms/service/SmsServiceTest.java

@@ -1,12 +1,11 @@
 package com.nokia.sms.service;
 
-import java.util.Date;
-
+import com.nokia.sms.pojo.Sms;
 import org.junit.jupiter.api.Test;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.boot.test.context.SpringBootTest;
 
-import com.nokia.sms.pojo.Sms;
+import java.util.Date;
 
 @SpringBootTest
 public class SmsServiceTest {
@@ -19,7 +18,7 @@ public class SmsServiceTest {
         Sms sms = new Sms();
         sms.setPhoneNumbers(new String[] { "13231899751", "18631181961", "18031151219", "15633560090", "15996582933" });
         sms.setContent("这是一条测试短信--" + new Date());
-        System.out.println(service.sendMessage(sms));
+        service.sendMessage(sms);
     }
 
     // 测试定时发送
@@ -31,6 +30,6 @@ public class SmsServiceTest {
         sms.setContent("这是一条测试短信--" + new Date());
         // 5分钟后发送
         sms.setScheduleTime(new Date(System.currentTimeMillis() + 5 * 60 * 1000));
-        System.out.println(service.sendMessage(sms));
+        service.sendMessage(sms);
     }
 }