【完整靠譜版】結合公司項目,仔細總結自己使用百度編輯器實現FTP上傳的完整過程

来源:http://www.cnblogs.com/sybboy/archive/2016/08/03/5733719.html
-Advertisement-
Play Games

說在前面 工作中會遇到很多需要使用富文本編輯器的地方,比如我現在發佈這篇文章離不開這個神器,而且現在網上編輯器太多了。記得之前,由於工作需要自己封裝過一個編輯器的公共插件,是用ckeditor改版的,目的是要相容公司所有項目,使用方便。廢話不多說,今天寫這篇文章,一是總結自己學習複習,二是關於FTP ...


說在前面

    工作中會遇到很多需要使用富文本編輯器的地方,比如我現在發佈這篇文章離不開這個神器,而且現在網上編輯器太多了。記得之前,由於工作需要自己封裝過一個編輯器的公共插件,是用ckeditor改版的,目的是要相容公司所有項目,使用方便。廢話不多說,今天寫這篇文章,一是總結自己學習複習,二是關於FTP上傳官方資料太少,也便於他人少趟坑,我在這裡會說的很細很明白,希望親們以後不要中槍了!

關於編輯器的簡單部署

     去官網下載後,我們需要把下載的編輯器文件夾,摘一部分放到項目中,下載之後的目錄,如下圖(我這裡用的是jsp簡化版 1.2.2)

 

        我在外面新建了個插件目錄umeditor,如下圖:

 

 

 

       除了jsp文件夾,其餘拷到項目靜態資源的目錄中,然後 我們來分析jsp文件夾都有哪些東東?

 

       這裡,我把那兩個jar包帶入到項目中,這裡我改了名字,方便導入,fileupload那個jar包項目之前就有。如下圖:

    

 

      接下來,就是頁面調用了,很簡單,首先將編輯器所需要的樣式和腳本文件引入:

/**以上省略,這裡引入到頁面頭部**/
<link href="${ctx}/static/umeditor/themes/default/css/umeditor.css" type="text/css" rel="stylesheet">
    <script type="text/javascript" charset="utf-8" src="${ctx}/static/umeditor/umeditor.config.js"></script>
    <script type="text/javascript" charset="utf-8" src="${ctx}/static/umeditor/umeditor.min.js"></script>
    <script type="text/javascript" src="${ctx}/static/umeditor/lang/zh-cn/zh-cn.js"></script>
</head>

      接下來,需要在頁面調用編輯器對象,官方用的是script標簽,我這裡用textarea來構造

<div class="controls">
            <form:textarea id="content" htmlEscape="true" path="articleData.content" rows="4" maxlength="200" class="input-xxlarge"/>
                
            <script type="text/javascript">
                //實例化編輯器
                var um = UM.getEditor('content'); //註意ID的一致
                um.setWidth(700); //設置編輯器寬度
            </script>
</div>

 

    至此基本的工作已做完,上述相信大部分搞開發的同胞們,都沒問題吧!效果圖如下:

 

 

關於編輯器的後臺實現

        官方下載給的後臺處理文件除了必要的jar外有三個文件:

       (1) Uploader.java 文件

       該文件主封裝了一個文件上傳對象,包括上傳後需要返回的參數、狀態、URL,除此還有一個上傳的處理函數,當然只是普通的文件存儲,不符合我們的需求,但是我們可以知道前端需要的一些返回值。

       (2) imageUp.jsp 文件

       上傳圖片預設配置後臺處理文件,主要調用Upload上傳類,完成上傳 並把上傳結果 以json字元串發往前臺,其中包括重要的state、url等參數

       (3) getContent.jsp 文件 (和上傳沒關係,略過)

         以上分析過官方給的簡單後臺處理邏輯,我們不難知道實際上就是需要我們提供一個上傳處理函數並返回包含必要參數的JSON串

        那好,接下來我們開始寫自己的後臺上傳處理函數了。

        第一步 後臺控制器處理函數(重要程度:☆☆☆☆☆  

 1 /**
 2      * 編輯器上傳圖片  
 3      */
 4     @RequiresPermissions("cms:article:view")
 5     @RequestMapping(value={"/upload"})
 6     @ResponseBody()
 7     public String upload(HttpServletRequest request,HttpServletResponse response){
 8         
 9         //request.getParameter("path");
10         String[] allowExtName = {".jpg",".png",".gif",".bmp",".jpeg"};//圖片格式限制
11         List<MultipartFile> multipartFiles = getFileSet(request, 1024 * 1024 * 10, allowExtName);  //上傳的圖片大小可以放到配置中讀取,這裡設置10M
12         Map<String,Object> map = new HashMap<String,Object>();
13         try {
14             if(multipartFiles.size() > 0){
15                 MultipartFile file = multipartFiles.get(0);
16                 InputStream is = file.getInputStream();
17                 String tempFileName = file.getOriginalFilename();
18                 if(is != null&&StringUtils.isNotBlank(tempFileName)){
19                     
20                     //生成文件名
21                     String uuid = IdGen.uuid(); //生成的一個隨機字元串,用於圖片名
22                     String fileName = uuid+tempFileName.substring(tempFileName.indexOf("."));
23                     //生成文件路徑
24                     boolean ftpWaterRs=true;
25                     FTPUtils ftpUtils = FTPUtils.getInstance();
26                     SimpleDateFormat sf = new SimpleDateFormat("yyyy/MM/");
27                     String ss = sf.format(new Date()); //以當前時間,生成存放目錄,格式/yyyy/MM
28                     String storePath = ftpUtils.getSaveFilePath() + ss; //讀取配置的存儲目錄 比如 /upload/image/
29                     //圖片加水印 getResourceRootRealPath ; 若圖片大小小於logo大小則不加水印
30                     if(file.getSize()>1200){  //這裡給圖片增加水印功能
31                         String waterName= uuid + "_water"+tempFileName.substring(tempFileName.indexOf("."));
32                         //緩存文件類型轉換
33                         CommonsMultipartFile cf= (CommonsMultipartFile)file; 
34                         DiskFileItem fi = (DiskFileItem)cf.getFileItem(); 
35                         File tempFile = fi.getStoreLocation();
36                         String waterTempPath = SpringContextHolder.getRootRealPath()+"/"+waterName;
37                         String logoPath=SpringContextHolder.getRootRealPath()+"/static/images/shuiyin.png";   //水印圖片路徑              
38                            ImageUtils.markImageByIcon(logoPath, tempFile, waterTempPath, 45); //添加水印
39                         File waterFile = new File(waterTempPath);
40                         //上傳水印圖片
41                         ftpWaterRs = ftpUtils.storeFile(storePath,waterName,new FileInputStream(waterFile));
42                         if(ftpWaterRs){
43                             FileUtils.deleteFile(waterTempPath);
44                             is.close();
45                             map.clear();
46                             map.put("state","SUCCESS"); //註意:返回的參數state 成功必須是 SUCCESS,否則需要到image.js中改,失敗可以自定義
47                             //map.put("url",ftpUtils.getSiteName().trim()+storePath.trim() + waterName);
48                             map.put("url",storePath.trim() + waterName);
//url 這裡有個坑,絕對完整地址圖片不會顯示
//我現在返回的是不包含功能變數名稱的路徑 如 /upload/images/2016/08/03/a23ssds6s6d56ds656a6a5652636.jpg
//功能變數名稱部分路徑也就是http://static.xx.com/ 需要到前端配置,具體是 在umeditor.config.js 配置參數 imagePath 所謂的圖片修正地址嘍
49 return JsonMapper.toJsonString(map); 50 } 51 } 52 53 //上傳源文件 54 boolean ftpFileRs = ftpUtils.storeFile(storePath, fileName, is); 55 is.close(); 56 if(ftpFileRs){ //這裡水印圖片上傳失敗 會採用原圖 57 map.clear(); 58 map.put("state","SUCCESS"); 59 map.put("url",storePath.trim() + fileName); 60 return JsonMapper.toJsonString(map); 61 } 62 } 63 } 64 else{ 65 map.clear(); 66 map.put("state","請檢查圖片格式或尺寸,圖片必須小於10M"); 67 return JsonMapper.toJsonString(map); 68 } 69 } catch (Exception e) { 70 e.printStackTrace(); 71 } 72 map.clear(); 73 map.put("state","上傳請求異常"); 74 return JsonMapper.toJsonString(map); 75 }

           

          第二步 處理函數用到上傳圖片驗證函數包含大小和格式(重要程度:☆☆☆  

 1 /** 
 2      * @descrption 根據HttpServletRequest對象獲取MultipartFile集合 
 3      * @author zp 
 4      * @param request 
 5      * @param maxLength 
 6      *            文件最大限制 
 7      * @param allowExtName 
 8      *            不允許上傳的文件擴展名 
 9      * @return MultipartFile集合 
10      */  
11     public static List<MultipartFile> getFileSet(HttpServletRequest request,  
12             long maxLength, String[] allowExtName) {  
13         MultipartHttpServletRequest multipartRequest = null;  
14         try {  
15             multipartRequest = (MultipartHttpServletRequest) request;  
16         } catch (Exception e) {  
17             return new LinkedList<MultipartFile>();  
18         }  
19   
20         List<MultipartFile> files = new LinkedList<MultipartFile>();  
21         files = multipartRequest.getFiles("upfile");  //upfile 是編輯器預設的上傳圖片表單name,在文件umeditor.config.js 可自定義配置參數 imageFieldName
22         // 移除不符合條件的  
23         for (int i = 0; i < files.size(); i++) {  
24             if (!validateFile(files.get(i), maxLength, allowExtName)) {  
25                 files.remove(files.get(i));  
26                 if (files.size() == 0) {  
27                     return files;  
28                 }  
29             }  
30         }  
31         return files;  
32     } 
33     
34     /** 
35      * @descrption 驗證文件格式,這裡主要驗證尾碼名 
36      * @author zp 
37      * @param file 
38      *            MultipartFile對象 
39      * @param maxLength 
40      *            文件最大限制 
41      * @param allowExtName 
42      *            不允許上傳的文件擴展名 
43      * @return 文件格式是否合法 
44      */  
45     private static boolean validateFile(MultipartFile file, long maxLength,  
46             String[] allowExtName) {  
47         if (file.getSize() < 0 || file.getSize() > maxLength)  
48             return false;  
49         String filename = file.getOriginalFilename();  
50   
51         // 處理不選擇文件點擊上傳時,也會有MultipartFile對象,在此進行過濾  
52         if (filename == "") {  
53             return false;  
54         }  
55         String extName = filename.substring(filename.lastIndexOf("."))  
56                 .toLowerCase();  
57         if (allowExtName == null || allowExtName.length == 0  
58                 || Arrays.binarySearch(allowExtName, extName) != -1) {  
59             return true;  
60         } else {  
61             return false;  
62         }  
63     }  

 

           第三步 FTP上傳處理類,絕對福利..好多人想要哦 0.0(重要程度:☆☆☆

  1 package com.xx.utils;
  2 
  3 import java.io.File;
  4 import java.io.FileInputStream;
  5 import java.io.IOException;
  6 import java.io.InputStream;
  7 
  8 import org.apache.commons.net.ftp.FTPClient;
  9 import org.apache.commons.net.ftp.FTPFile;
 10 import org.apache.commons.net.ftp.FTPReply;
 11 
 12 import com.xx.Global;
 13   
 14 /** 
 15  * FTP伺服器工具類 
 16  */  
 17 public class FTPUtils {  
 18       
 19     private static FTPUtils ftpUtils;  
 20     private FTPClient ftpClient;  
 21     //private FTPFile ftpFile;
 22     private String port; // 伺服器埠  
 23     private String username; // 用戶登錄名  
 24     private String password; // 用戶登錄密碼  
 25     private String serverName; // 服務名 
 26     private int localPasv;//開啟本地被動模式
 27     private String siteName; // 站點功能變數名稱
 28     private String saveFilePath;//存儲路徑
 29     
 30       
 31     private InputStream is; // 文件下載輸入流  
 32       
 33     /** 
 34      * 私有構造方法 
 35      */  
 36     private FTPUtils() {  
 37         initConfig();  
 38         if (null == ftpClient) {  
 39             ftpClient = new FTPClient();  
 40         }  
 41     }   
 42 
 43     /** 
 44      * 獲取FTPUtils對象實例 
 45      * @return 
 46      *      FTPUtils對象實例 
 47      */  
 48     public synchronized static FTPUtils getInstance () {  
 49         if (null == ftpUtils) {  
 50             ftpUtils = new FTPUtils();  
 51         }  
 52         return ftpUtils;  
 53     }  
 54       
 55     /** 
 56      * 初始化FTP伺服器連接屬性 
 57      */  
 58 //    public void initConfig () {  
 59 //        // 構造Properties對象  
 60 //        Properties properties = new Properties();  
 61 //          
 62 //        // 定義配置文件輸入流  
 63 //        InputStream is = null;  
 64 //        try {  
 65 //            // 獲取配置文件輸入流  
 66 //            is = FTPUtils.class.getResourceAsStream("/ftp.properties");  
 67 //            // 載入配置文件  
 68 //            properties.load(is);  
 69 //            // 讀取配置文件  
 70 //            port = (String) properties.get("port"); // 設置埠  
 71 //            username = (String) properties.get("username1"); // 設置用戶名  
 72 //            password = (String) properties.get("password1"); // 設置密碼  
 73 //            serverName = (String) properties.get("serverName"); // 服務名  
 74 //            localPasv = Integer.valueOf(String.valueOf(properties.get("localPasv")));
 75 //        } catch (IOException e) {  
 76 //            e.printStackTrace();  
 77 //        } finally {  
 78 //            // 判斷輸入流是否為空  
 79 //            if (null != is) {  
 80 //                try {  
 81 //                    // 關閉輸入流  
 82 //                    is.close();  
 83 //                } catch (IOException e) {  
 84 //                    e.printStackTrace();  
 85 //                }  
 86 //            }  
 87 //        }  
 88 //    }  
 89       
 90     public void initConfig () { 
 91         serverName = Global.getConfig("ftp.serverName");
 92 //                SystemConfig.getInstance().getApplication().get("ftp.serverName");  
 93         port = Global.getConfig("ftp.port");
 94 //                SystemConfig.getInstance().getApplication().get("ftp.port");
 95         username = Global.getConfig("ftp.username1");
 96 //                SystemConfig.getInstance().getApplication().get("ftp.username1");
 97         password =Global.getConfig("ftp.password1");
 98 //                portSystemConfig.getInstance().getApplication().get("ftp.password1"); 
 99         localPasv = Integer.valueOf(Global.getConfig("ftp.localPasv"));
100 //                Integer.valueOf(SystemConfig.getInstance().getApplication().get("ftp.localPasv")); 
101         siteName = Global.getConfig("ftp.readPath"); //讀取配置 訪問路徑
102         saveFilePath = Global.getConfig("ftp.upLoadPath"); //讀取配置 上傳路徑
103         
104     }    
105     /** 
106      * 連接(配置通用連接屬性)至伺服器 
107      *  
108      * @param serverName 
109      *      伺服器名稱 
110      * @param remotePath 
111      *      當前訪問目錄 
112      * @return 
113      *      <b>true</b>:連接成功 
114      *      <br/> 
115      *      <b>false</b>:連接失敗 
116      */  
117     public boolean connectToTheServer (String remotePath) {  
118         // 定義返回值  
119         boolean result = false;  
120         try {  
121             // 連接至伺服器,埠預設為21時,可直接通過URL連接  
122             ftpClient.connect(serverName, Integer.parseInt(port));  
123             // 登錄伺服器  
124             ftpClient.login(username, password);  
125             // 判斷返回碼是否合法  
126             if (!FTPReply.isPositiveCompletion(ftpClient.getReplyCode())) {  
127                 // 不合法時斷開連接  
128                 ftpClient.disconnect();  
129                 // 結束程式  
130                 return result;  
131             }
132             if(localPasv==1)
133             ftpClient.enterLocalPassiveMode();
134             // 設置文件操作目錄  
135             result = createDirAndToDir(remotePath);
136             System.out.println("result===="+result);
137             // 設置文件類型,二進位  
138             result = ftpClient.setFileType(FTPClient.BINARY_FILE_TYPE);  
139             // 設置緩衝區大小  
140             ftpClient.setBufferSize(3072);  
141             // 設置字元編碼  
142             ftpClient.setControlEncoding("UTF-8");  
143         } catch (IOException e) {  
144             e.printStackTrace();  
145         }  
146         return result;  
147     }  
148       
149     /** 
150      * 上傳文件至FTP伺服器 
151      *  
152      * @param serverName 
153      *      伺服器名稱 
154      * @param storePath 
155      *      上傳文件存儲路徑 
156      * @param fileName 
157      *      上傳文件存儲名稱 
158      * @param is 
159      *      上傳文件輸入流 
160      * @return 
161      *      <b>true</b>:上傳成功 
162      *      <br/> 
163      *      <b>false</b>:上傳失敗 
164      */  
165     public boolean storeFile (String storePath, String fileName, InputStream is) {  
166         boolean result = false;  
167         try {  
168             // 連接至伺服器  
169             result = connectToTheServer(storePath);  
170             // 判斷伺服器是否連接成功  
171             if (result) {  
172                 // 上傳文件  
173                 result = ftpClient.storeFile(fileName, is);  
174             }  
175             // 關閉輸入流  
176             is.close();  
177         } catch (IOException e) {  
178             e.printStackTrace();  
179         } finally {  
180             // 判斷輸入流是否存在  
181             if (null != is) {  
182                 try {  
183                     // 關閉輸入流  
184                     is.close();  
185                 } catch (IOException e) {  
186                     e.printStackTrace();  
187                 }  
188             }  
189             // 登出伺服器並斷開連接  
190             ftpUtils.logout();  
191         }  
192         return result;  
193     }  
194       
195     /** 
196      * 下載FTP伺服器文件至本地<br/> 
197      * 操作完成後需調用logout方法與伺服器斷開連接 
198      *      伺服器名稱 
199      * @param remotePath 
200      *      下載文件存儲路徑 
201      * @param fileName 
202      *      下載文件存儲名稱 
203      * @return 
204      *      <b>InputStream</b>:文件輸入流 
205      */  
206     public InputStream retrieveFile (String remotePath, String fileName) {  
207         try {  
208             boolean result = false;  
209             // 連接至伺服器  
210             result = connectToTheServer(remotePath);  
211             // 判斷伺服器是否連接成功  
212             if (result) {  
213                 // 獲取文件輸入流  
214                 is = ftpClient.retrieveFileStream(fileName);  
215             }  
216         } catch (IOException e) {  
217             e.printStackTrace();  
218         }  
219         return is;  
220     }  
221       
222     /** 
223      * 刪除FTP伺服器文件 
224      *  
225      * @param serverName 
226      *      伺服器名稱 
227      * @param remotePath 
228      *      當前訪問目錄 
229      * @param fileName 
230      *      文件存儲名稱 
231      * @return 
232      *      <b>true</b>:刪除成功 
233      *      <br/> 
234      *      <b>false</b>:刪除失敗 
235      */  
236     public boolean deleteFile (String serverName, String remotePath, String fileName) {  
237         boolean result = false;  
238         // 連接至伺服器  
239         result = connectToTheServer(remotePath);  
240         // 判斷伺服器是否連接成功  
241         if (result) {  
242             try
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 瀏覽器到 http://nginx.org/en/download.html 下載 stable version的nginx 如nginx-1.10.1.tar.gz,這是一個nginx源碼包,需要經過編譯和安裝才能使用。 解壓命令: tar –zxvf nginx-1.10.1.tar.gz cd... ...
  • 1. 實現思路 首先在實現這個效果之前 先來描述一下這個效果 A) 返回頂部的按鈕 一般會在屏幕的第二屏才會出現。 所以我們需要來判斷是否到達第二屏。 B) 其次 滑鼠移動上去會顯示返回頂部的字樣 C) 點擊 返回按鈕之後 會以慢慢返回上面 不會勻速 2. HTML 和 CSS 首先 div 表示中 ...
  • 問題 什麼是構造函數?構造函數與普通函數區別是什麼?用new關鍵字的時候到底做了什麼?構造函數有返回值怎麼辦?構造函數能當普通函數調用嗎? thisthis永遠指向當前正在被執行的函數或方法的owner。例如: 1 2 3 4 5 function test(){ console.log(this) ...
  • (1)子頁面調用父頁面的方法或者變數: window.parent.方法()或者變數名window.parent相當於定位到父頁面 之後的操作和在父頁面中寫代碼一樣寫 (2)父頁面調取子頁面 主要是通過contentWindow定位到子頁面 ...
  • 自己遇到的使用window.open打開新視窗被攔截的幾種情況(使用的chrome瀏覽器,其他瀏覽器未測): 第一次:window.open("www.baidu.com"),打開了新視窗,但是頁面並沒有載入出來,需要回車才能出來 解決方法:頁面地址需要加上協議名稱http://或者https:// ...
  • 1. Object.createde 方法 是ES5中引入的方法,語法: 功能:實現繼承,創建一個 原型繼承 自參數對象,但是缺點是,不能實現復用 例如: 2. 對象的原型鏈 凡是對象就有原型,那麼原型又是對象,因此凡是定義一個對象,那麼就可以找到他的原型,原型還有原型, 那麼如此下去,就構成一個對 ...
  • <新人報到,歡迎拍磚#- -> 一、後代選擇器 說起CSS的後代選擇器。它屬於派生選擇器中的一種,兩者附屬關係如下: -->派生選擇器 CSS 後代選擇器 CSS 子元素選擇器 CSS 相鄰兄弟選擇器 那麼問題來了,什麼時候需要用到後代選擇器嘞?假設你需要為p元素中的span元素(.A類)設置特殊樣 ...
  • $(function(){ $("#userCenterProject").addClass("cur"); $(".hd ul li").click(function(){ var index=$(this).index(); $(this).addClass("on").siblings().r ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...