Java開源生鮮電商平臺-通知模塊設計與架構(源碼可下載)

来源:https://www.cnblogs.com/jurendage/archive/2018/05/27/9095078.html
-Advertisement-
Play Games

Java開源生鮮電商平臺-通知模塊設計與架構(源碼可下載) 說明:對於一個生鮮的B2B平臺而言,通知對於我們實際的運營而言來講分為三種方式: 1. 消息推送:(採用極光推送) 2. 主頁彈窗通知。(比如:現在有什麼新的活動,有什麼新的優惠等等) 3. 簡訊通知.(對於簡訊通知,這個大家很熟悉,我們就 ...


Java開源生鮮電商平臺-通知模塊設計與架構(源碼可下載)

說明:對於一個生鮮的B2B平臺而言,通知對於我們實際的運營而言來講分為三種方式:

          1. 消息推送:(採用極光推送)

          2. 主頁彈窗通知。(比如:現在有什麼新的活動,有什麼新的優惠等等)

          3. 簡訊通知.(對於簡訊通知,這個大家很熟悉,我們就說下我們如何從代碼層面對簡訊進行分層的分析與架構)

 

1. 消息推送

   說明:目前市場上的推送很多,什麼極光推送,環信,網易雲等等,都可以實現秒級別的推送,我們經過了市場調研與穩定性考察,最終選擇了極光推送。

             極光推送,市面上有很大的文檔與實例,我這邊就不詳細講解了,因為文檔很清晰,也的確很簡單。

    相關的核心功能與代碼如下:

        1. 功能劃分

             1.1向所有的人推送同一個消息。

             1.2 具體的某個人,或者某類人推送消息,自己簡單的進行了一個SDK等封裝

 

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.Options;
import cn.jpush.api.push.model.Platform;
import cn.jpush.api.push.model.PushPayload;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
/**
 * 激光推送
 */
public class Jdpush {

    private static final Logger log = LoggerFactory.getLogger(Jdpush.class);
    
    // 設置好賬號的app_key和masterSecret 
    public static final String APPKEY = "";
    
    public static final String MASTERSECRET = "";
       
        /**
         * 推送所有
         */
        public static PushPayload buildPushObjectAndroidIosAllAlert(String message){
            return PushPayload.newBuilder()
                    .setPlatform(Platform.android_ios())
                    .setAudience(Audience.all())//推送所有;
                    .setNotification(Notification.newBuilder()
                            .addPlatformNotification(AndroidNotification.newBuilder()
                                    .addExtra("type", "infomation")
                                    .setAlert(message)
                                    .build())
                            .addPlatformNotification(IosNotification.newBuilder().setSound("callu")
                                    .addExtra("type", "infomation")
                                    .setAlert(message)
                                    .build())
                            .build())
                    .setOptions(Options.newBuilder()
                            .setApnsProduction(false)//true-推送生產環境 false-推送開發環境(測試使用參數)
                            .setTimeToLive(90)//消息在JPush伺服器的失效時間(測試使用參數)
                            .build())
                    .build();
        }
        
        
        /**
         * 推送 指定用戶集合;
         */
        public static PushPayload buildPushObjectAndroidIosAliasAlert(List<String> userIds,String message){
            return PushPayload.newBuilder()
                    .setPlatform(Platform.android_ios())
                    .setAudience(Audience.alias(userIds))//推送多個;
                    .setNotification(Notification.newBuilder()
                            .addPlatformNotification(AndroidNotification.newBuilder()
                                    .addExtra("type", "infomation")
                                    .setAlert(message)
                                    .build())
                            .addPlatformNotification(IosNotification.newBuilder().setSound("callu")
                                    .addExtra("type", "infomation")
                                    .setAlert(message)
                                    .build())
                            .build())
                    .setOptions(Options.newBuilder()
                            .setApnsProduction(false)//true-推送生產環境 false-推送開發環境(測試使用參數)
                            .setTimeToLive(90)//消息在JPush伺服器的失效時間(測試使用參數)
                            .build())
                    .build();
        }
        
        /**
         * 推送單個人;
         */
        public static PushPayload buildPushObjectAndroidIosAliasAlert(String userId,String message){
            return PushPayload.newBuilder()
                    .setPlatform(Platform.android_ios())
                    .setAudience(Audience.alias(userId))//推送單個;
                    .setNotification(Notification.newBuilder()
                            .addPlatformNotification(AndroidNotification.newBuilder()
                                    .addExtra("type", "infomation")
                                    .setAlert(message)
                                    .build())
                            .addPlatformNotification(IosNotification.newBuilder().setSound("callu")
                                    .addExtra("type", "infomation")
                                    .setAlert(message)
                                    .build())
                            .build())
                    .setOptions(Options.newBuilder()
                            .setApnsProduction(false)//true-推送生產環境 false-推送開發環境(測試使用參數)
                            .setTimeToLive(90)//消息在JPush伺服器的失效時間(測試使用參數)
                            .build())
                    .build();
        }
        
        /**
         * 推送所有
         */
        public static PushResult pushAlias(String alert){
            ClientConfig clientConfig = ClientConfig.getInstance();
            JPushClient jpushClient = new JPushClient(MASTERSECRET, APPKEY, null, clientConfig);
            PushPayload payload = buildPushObjectAndroidIosAllAlert(alert);
            try {
                return jpushClient.sendPush(payload);
            } catch (APIConnectionException e) {
                log.error("Connection error. Should retry later. ", e);
                return null;
            } catch (APIRequestException e) {
                log.error("Error response from JPush server. Should review and fix it. ", e);
                log.info("HTTP Status: " + e.getStatus());
                log.info("Error Code: " + e.getErrorCode());
                log.info("Error Message: " + e.getErrorMessage());
                log.info("Msg ID: " + e.getMsgId());
                return null;
            }    
        }
        
        /**
         * 推送 指定用戶集合;
         */
        public static PushResult pushAlias(List<String> userIds,String alert){
            ClientConfig clientConfig = ClientConfig.getInstance();
            JPushClient jpushClient = new JPushClient(MASTERSECRET, APPKEY, null, clientConfig);
            PushPayload payload = buildPushObjectAndroidIosAliasAlert(userIds,alert);
            try {
                return jpushClient.sendPush(payload);
            } catch (APIConnectionException e) {
                log.error("Connection error. Should retry later. ", e);
                return null;
            } catch (APIRequestException e) {
                log.error("Error response from JPush server. Should review and fix it. ", e);
                log.info("HTTP Status: " + e.getStatus());
                log.info("Error Code: " + e.getErrorCode());
                log.info("Error Message: " + e.getErrorMessage());
                log.info("Msg ID: " + e.getMsgId());
                return null;
            }    
        }
        
        /**
         * 推送單個人;
         */
        public static PushResult pushAlias(String userId,String alert){
            ClientConfig clientConfig = ClientConfig.getInstance();
            JPushClient jpushClient = new JPushClient(MASTERSECRET, APPKEY, null, clientConfig);
            PushPayload payload = buildPushObjectAndroidIosAliasAlert(userId,alert);
            try {
                return jpushClient.sendPush(payload);
            } catch (APIConnectionException e) {
                log.error("Connection error. Should retry later. ", e);
                return null;
            } catch (APIRequestException e) {
                log.error("Error response from JPush server. Should review and fix it. ", e);
                log.info("HTTP Status: " + e.getStatus());
                log.info("Error Code: " + e.getErrorCode());
                log.info("Error Message: " + e.getErrorMessage());
                log.info("Msg ID: " + e.getMsgId());
                return null;
            }    
        }
        
        
}

2. 業務通知

    說明:有些事情,我們希望用戶打開APP就知道某些事情,這個時候我們就需要做一個首頁通知機制,由於這種機制是用戶主動接受,因此,我們需要進行系統設計與架構

 

2.1 存儲用戶的推送消息。

2.2 統計那些用戶看了與沒看。

 

資料庫設計如下:

CREATE TABLE `buyer_notice` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自動增加ID',
  `buyer_id` bigint(20) DEFAULT NULL COMMENT '買家ID',
  `content` varchar(60) DEFAULT NULL COMMENT '內容',
  `status` int(11) DEFAULT NULL COMMENT '狀態,0為未讀,1為已讀',
  `create_time` datetime DEFAULT NULL COMMENT '創建時間',
  `update_time` datetime DEFAULT NULL COMMENT '最後更新時間,已讀時間',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=262 DEFAULT CHARSET=utf8 COMMENT='買家通知';

 

說明:欄位相對比較簡單,就是買家ID,內容,讀取狀態等等,

           業務邏輯為:當用戶進入系統,我們系統代碼查詢業務邏輯的時候,也查詢 下這個表是否存在通知,如果已經有的,就不用彈窗,沒有就彈窗,強迫用戶選擇已讀或者未讀。

相對而言業務比較簡單

 

/***
 * 買家進入首頁,看到的通知
 */
@RestController
@RequestMapping("/buyer")
public class NoticeController extends BaseController{

    private static final Logger logger = LoggerFactory.getLogger(MyController.class);
    
    public static final String CONTENT="平臺下單時間調整為上午10:00到晚上23:59";
    
    @Autowired
    private NoticeService noticeService;
    
    /**
     * 查詢消息
     */
    @RequestMapping(value = "/notice/index", method = { RequestMethod.GET, RequestMethod.POST })
    public JsonResult noticeIndex(HttpServletRequest request, HttpServletResponse response,Long buyerId){
        try
        {
            if(buyerId==null)
            {
                return new JsonResult(JsonResultCode.FAILURE, "請求參數有誤,請重新輸入","");
            }
            
            Notice notice=this.noticeService.getNoticeByBuyerId(buyerId);
            
            if(notice==null)
            {
                
                int result=this.noticeService.insertNotice(buyerId, CONTENT);
                
                if(result>0)
                {
                    notice=this.noticeService.getNoticeByBuyerId(buyerId);
                }
            }
            return new JsonResult(JsonResultCode.SUCCESS, "查詢信息成功", notice);
            
        }catch(Exception ex){
            logger.error("[NoticeController][noticeIndex] exception :",ex);
            return new JsonResult(JsonResultCode.FAILURE, "系統錯誤,請稍後重試","");
        }
    }
    
    
    /**
     * 更新消息
     */
    @RequestMapping(value = "/notice/update", method = { RequestMethod.GET, RequestMethod.POST })
    public JsonResult noticeUpdate(HttpServletRequest request, HttpServletResponse response,Long buyerId){
        try
        {
            if(buyerId==null)
            {
                return new JsonResult(JsonResultCode.FAILURE, "請求參數有誤,請重新輸入","");
            }
            
            int result=this.noticeService.updateBuyerNotice(buyerId);
            
            if(result>0)
            {
                return new JsonResult(JsonResultCode.SUCCESS, "更新成功","");
            }else
            {
                return new JsonResult(JsonResultCode.FAILURE, "更新失敗","");
            }
        }catch(Exception ex){
            logger.error("[NoticeController][noticeUpdate] exception :",ex);
            return new JsonResult(JsonResultCode.FAILURE, "系統錯誤,請稍後重試","");
        }
    }
}

 

3. 簡訊通知模塊的設計

   說明:市面上簡訊供應商很多,可能大家就是關註一個價格與及時性的問題,目前我們找的一個稍微便宜點的供應商:http://api.sms.cn/

   內容其實就是簡訊的發送而言。

    介面文檔很簡單:

     

參數名    參數欄位    參數說明
ac    介面功能    介面功能,傳入值請填寫 send
format    返回格式    可選項,有三參數值:json,xml,txt 預設json格式
uid    用戶賬號    登錄名
pwd    用戶密碼    32位MD5加密md5(密碼+uid)
如登錄密碼是:123123 ,uid是:test;
pwd=md5(123123test)
pwd=b9887c5ebb23ebb294acab183ecf0769
encode    字元編碼    可選項,預設接收數據是UTF-8編碼,如提交的是GBK編碼字元,需要添加參數 encode=gbk
mobile    接收號碼    同時發送給多個號碼時,號碼之間用英文半形逗號分隔(,);小靈通需加區號
如:13972827282,13072827282
mobileids    消息編號    可選項
該參數用於發送簡訊收取狀態報告用,格式為消息編號+逗號;與接收號碼一一對應,可以重覆出現多次。
消息編號:全部由數字組成接收狀態報告的時候用到,該消息編號的格式可就為目標號碼+當前時間戳整數,精確到毫秒,確保唯一性。供收取狀態報告用 如: 1590049111112869461937;

content    簡訊內容    變數模板發送,傳參規則{"key":"value"}JSON格式,key的名字須和申請模板中的變數名一致,多個變數之間以逗號隔開。示例:針對模板“簡訊驗證碼{$code},您正在進行{$product}身份驗證,請在10分鐘內完成操作!”,傳參時需傳入{"code":"352333","product":"電商平臺"}
template    模板簡訊ID    發送變數模板簡訊時需要填寫對應的模板ID號,進入平臺-》簡訊設置-》模板管理

 

對此,我們如何進行業務研究與處理呢?

            1. 簡訊驗證碼的長度與演算法。

            2. 代碼的模板進行封裝。

            3. 簡訊工具類的使用方便

 

1. 簡訊驗證碼生成演算法:

   

import org.apache.commons.lang3.RandomStringUtils;

/**
 * 簡訊驗證碼
 * 
 */
public final class SmsCode {

    /**
     * 預設產生的驗證碼數目
     */
    private static int DEFAULT_NUMBER = 6;

    /**
     * 產生的隨機號碼數目
     * 
     * @param number
     * @return
     */
    public static String createRandomCode(int number) {
        int num = number <= 3 ? DEFAULT_NUMBER : number;
        return RandomStringUtils.randomNumeric(num);
    }
}

簡單粗暴的解決問題:

 

2. 簡訊內容的封裝:

/***
 * 簡訊消息對象
 */
public class SmsMessage 
{
    /**
     * 賬號,目前就是手機號碼,採用的是手機號碼登陸
     */
    private String account;
    
    /*
     * 產生的驗證碼 
     */
    private String code;
    
    /**
     * 對應的簡訊模板,目前簡訊驗證碼是401730
     */
    private String template;
    
    public SmsMessage() {
        super();
    }

    public SmsMessage(String account, String code, String template) {
        super();
        this.account = account;
        this.code = code;
        this.template = template;
    }

    public String getAccount() {
        return account;
    }

    public void setAccount(String account) {
        this.account = account;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getTemplate() {
        return template;
    }

    public void setTemplate(String template) {
        this.template = template;
    }

    @Override
    public String toString() {
        return "{\"username\":\""+account+"\",\"code\":\""+code+"\"}";
    }

3.簡訊發送結果的封裝:

/**
 * 簡訊發送結果
 */
public class SmsResult implements java.io.Serializable{

    private static final long serialVersionUID = 1L;

    private boolean success=false;
    
    private String message;
    
    public SmsResult() {
        super();
    }
    
    public SmsResult(String message) 
    {
        super();
        this.success=false;
        this.message=message;
    }
    
    public SmsResult(boolean success, String message) {
        super();
        this.success = success;
        this.message = message;
    }

    public boolean isSuccess() {
        return success;
    }

    public void setSuccess(boolean success) {
        this.success = success;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String toString() {
        StringBuilder builder = new StringBuilder();
        builder.append("SmsResult [success=");
        builder.append(success);
        builder.append(", message=");
        builder.append(message);
        builder.append("]");
        return builder.toString();
    }
}

 

4. 簡訊發送工具類的封裝

   

/**
 * 簡訊工具
 */
@Component
public class SmsUtil {
    
    private static final Logger logger=LoggerFactory.getLogger(SmsUtil.class);
    
    @Value("#{applicationProperties['environment']}")
    private String environment;
    
    /**
     * 預設編碼的格式
     */
    private static final String CHARSET="GBK";
    
    /**
     * 請求的網關介面
     */
    private static final String URL = "http://api.sms.cn/sms/";
    
    public boolean sendSms(SmsMessage smsMessage)
    {
        boolean result=true;
        
        logger.debug("[SmsUtil]當前的運行環境為:"+environment);

        //開發環境就直接返回成功
        if("dev".equalsIgnoreCase(environment))
        {
            return result;
        }
        
        Map<String, String> map=new HashMap<String,String>();
        
        map.put("ac","send");
        map.put("uid","");
        map.put("pwd","");
        map.put("template",smsMessage.getTemplate());
        map.put("mobile",smsMessage.getAccount());
        map.put("content",smsMessage.toString());
        
        try
        {
            String responseContent=HttpClientUtil.getInstance().sendHttpPost(URL, map,CHARSET);
            
            logger.info("SmsUtil.sendSms.responseContent:" + responseContent);
            
            JSONObject json = JSONObject.fromObject(responseContent);
            
            logger.info("SmsUtil.sendSms.json:" + json);
            
            String stat=json.getString("stat");
            
            if(!"100".equalsIgnoreCase(stat))
            {
                result=false;
            }
            
        }catch(Exception ex)
        {
            result=false;
            logger.error("[SmsUtil][sendSms] exception:",ex);
        }
        return result;
    }
}

 

補充說明;其實我可以用一個工具類來解決所有問題,為什麼我沒採用呢?

               1 。代碼耦合度高,不變管理與擴展.(業務分析,其實就是三種情況,1,發送,2,內容,3,返回結果)

               2.   我採用代碼拆分,一個類只做一件事情,幾個類分別協同開發,達到最高程度的解耦,代碼清晰,維護度高。

 

總結:關於這個消息的推送,我們也可以採用微信來通知,比如:你的訂單到了,你的訂單已經接受,錢已經到賬等等,還有業務線上的推送等等,我這邊

只是根據實際的運行情況,起到一個拋磚引玉的作用,目的只有一個原因,讓大家有獨立思考與分析業務的能力。

 

Java開源生鮮電商平臺-通知模塊設計與架構(源碼可下載),如果需要下載的話,可以在我的github下麵進行下載。 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 針對web應用的攻擊模式 主動攻擊,攻擊者通過直接訪問web資源把攻擊代碼傳入的攻擊模式,需要攻擊者能夠訪問伺服器上的資源,常見有SQL註入攻擊和OS命令註入攻擊; 被動攻擊,利用圈套策略執行攻擊代碼的模式,攻擊者不直接攻擊web應用,常見有XSS和CSRF; SQL註入 把SQL命令插入到表單提交 ...
  • 個人學習Java的第一個完成的項目,分享給大家。有不好的地方,請多指教。 ...
  • 前幾天開發了一款手機端h5仿微信聊天,人唯有不停學習才能進步,這段時間倒騰著整理了下之前項目,又重新在原先的那版基礎上開發了一款仿微信聊天電腦端web版本,聊天頁面又重新優化了多圖預覽、視頻播放,右鍵菜單menu,聊天底部編輯器模塊重新優化源碼,彈窗則是繼續使用之前自己開發的wcPop.js,具體看 ...
  • 一、關於position流定位:不能通過left/top屬性來進行定位(那用什麼定位),上下排列的元素縱向邊距會被合併,左右元素橫向邊距不會合併。浮動定位:脫離文本流,就好像不在父元素中,像是浮在父元素的上方。相對定位:相對自身位置定位,不會脫離文本流,相當於是個參照物,給子代元素作為參照。絕對定位 ...
  • 1 const readline = require('readline-sync')//引用readline-sync 2 let arr = [['zhang', '123', 2000], ['yang', '123456', 3000]]; 3 //登陸 4 let add = functi... ...
  • 一、 基本選擇器 二、 後代選擇器、子元素選擇器 三、 兄弟選擇器 四、 交集選擇器與並集選擇器 五、 序列選擇器 六、 屬性選擇器 七、 偽類選擇器 八、 偽元素選擇器 九、 CSS三大特性 一、 基本選擇器 1、id選擇器 <!DOCTYPE html> <html> <head> <meta ...
  • 大家都知道,使用vue-cli可以快速的初始化一個基於Vue.js的項目,全局安裝腳手架之後,你可以通過vue list命令看到官方提供的5個模板 vue list 當開發一個獨立項目的時候,使用官方提供的template確實很方便,省去了繁瑣的依賴配置,webpack等配置問題,甚至連項目目錄結構 ...
  • 引言 之前就瞭解過kafka,看的似懂非懂,最近項目組中引入了 "kafka" ,剛好接著這個機會再次學習下。 Kafka在很多公司被用作分散式高性能消息隊列,kafka之前我只用過redis的list來做簡單的隊列處理,也還算好用,可能數據量比較小,也是單機運行,未出現過問題,用作輕量級消息隊列還 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...