Android自定義控制項練手——簡單的時鐘

来源:https://www.cnblogs.com/SteinsGateZero/archive/2018/02/09/8436025.html
-Advertisement-
Play Games

首先這應該是一個老生常談的設計了,但是畢竟身為小白的自己都沒動手做過,不動手怎麼提高自己呢,所以在這梅林沉船閑暇之際,我就把我的設計流程與思路記錄下來。首先來看看效果圖吧: 如上圖就是一個簡單並沒有美化過的時鐘,接下來我就來講講我的設計流程與思路。 一.首先繼承view重寫裡面的onDraw方法。 ...


    首先這應該是一個老生常談的設計了,但是畢竟身為小白的自己都沒動手做過,不動手怎麼提高自己呢,所以在這梅林沉船閑暇之際,我就把我的設計流程與思路記錄下來。首先來看看效果圖吧:

    如上圖就是一個簡單並沒有美化過的時鐘,接下來我就來講講我的設計流程與思路。

一.首先繼承view重寫裡面的onDraw方法。

    我們要搭建好了畫布才能開始在裡面畫畫,而onDraw方法中的canvas當然就是起到畫布的作用。

 1 public class MyClockView extends View {
 2 
 3     public MyClockView(Context context) {
 4         super(context);
 5         init();//初始化的方法
 6     }
 7 
 8     public MyClockView(Context context, AttributeSet attrs) {
 9         super(context, attrs);
10         init();
11     }
12 
13     public MyClockView(Context context, AttributeSet attrs, int defStyleAttr) {
14         super(context, attrs, defStyleAttr);
15         init();
16     }
17 
18     public void init() {
19     
20     }
21 
22     @Override
23     protected void onDraw(Canvas canvas) {
24         super.onDraw(canvas);
25     }
26 
27 }

二.準備需要用到的工具。

    要畫一個時鐘當然首先得要有筆才行,第一步上面我們得到了畫布,現在我們還需要一個paint的畫筆。似乎繪圖用的工具就這麼多了,一張畫布,一支筆,那麼讓我們想想還需要用到些什麼變數,我就先把時鐘結構拆分成了,時、分、秒針,一個圓圈框和時鐘的刻度與數字,但是這些能代表些什麼deep♂dark♂fantastic的呢,再讓我們想想這裡一般繪圖當然要和坐標掛鉤,那就都變成二維坐標吧,時分秒針都是直線,就是畫線,圓框就是畫圓要知道圓心與半徑,刻度也是畫線,數字就是寫字,拆分為了,時分秒針兩端的坐標,圓心與半徑,刻度兩端的坐標,數字繪製開始的坐標

三.坐標繪製的演算法分析。

    我們應該是都知道要想根據坐標繪製就要先知道它的原點在哪,一般預設情況下它的原點定在屏幕左上角,並且y軸下半部為正半軸,上半部為負半軸。如圖:

 

   根據上面圖的坐標系,我們現在要畫一個圓形,裡面再畫刻度,再畫時分秒針,首先我們要確定圓心在哪,我按照習慣以控制項長寬最短的一邊為直徑來定圓心的坐標,我在剛纔繼承view之後重寫onSizeChanged方法(這個方法是當寬高放生變化和第一次會執行)做獲取半徑長:

 1 protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 2         mWidth = w;//獲得寬度
 3         mHeight = h;//獲得高度
 4 
 5         //以最短的一邊為所要繪製圓形的直徑
 6         if (mWidth > mHeight) {
 7             arcRa = mHeight / 2;//以最短的一邊算出半徑
 8         } else {
 9             arcRa = mWidth / 2;//以最短的一邊算出半徑
10         }
11         super.onSizeChanged(w, h, oldw, oldh);
12     }

   這樣在預設坐標系中,圓心坐標即為(arcRa,arcRa),這裡我用arcRa代表半徑。有了圓心和半徑,那就可以順利的用canvas.drawCircle畫出一個圓。接下來我們要構思畫刻度,刻度說白了就是把一個從圓心來等分,一個圓一圈是360度,也就是說把360度等分了,分多少呢,60秒等於1分鐘,60分鐘等於1小時,那就分60份咯,但是時鐘有長短刻度,小刻度是分成60份了,那代表小時的長刻度怎麼分,轉一圈是12小時,那就分成12份。

    具體刻度切分的思路就上面那麼多,那說了這麼多,到底要乾什麼?當然都是為了確定坐標。接下來交給三角函數演算法如下圖:

    我們知道了圓心(arcRa,arcRa)和半徑在坐標系中畫圓,x軸與圓圈相交於一點(arcRa,0),連接(arcRa,0)與圓心是一條直線如圖,並且這條直線垂直於x軸。我們要根據360度分出來的度數,來計算刻度坐標點所要在的位置,假設以圓心垂直於x軸的直線來切分,切分出為θ的角度,我們知道半徑arcRa,用三角函數公式可得到如圖所示的坐標點point。

    上面就是畫刻度與指針的演算法了,就是簡單的三角函數問題。我用的是三角函數演算法來繪製其實還有另外一種簡單方法,通過旋轉canvas畫布來繪製,網上也能夠查到,我這裡就用我當時順勢想出來的麻煩點蠢的方法來繪製。

四.開始draw啦。

    嗨呀,終於可以開始畫了,不過在開始繪製指針之前,先要獲取時間才行:

1 private void getCurrentTime() {
2         long time = System.currentTimeMillis();//獲取時間
3         Calendar mCalendar = Calendar.getInstance();
4         mCalendar.setTimeInMillis(time);
5         startHour = mCalendar.get(Calendar.HOUR);//獲取小時,12小時制
6         startMinute = mCalendar.get(Calendar.MINUTE);//獲取分鐘
7         startSecond = mCalendar.get(Calendar.SECOND);//獲取秒
8     }

    這裡我們獲取到的時間其實就是所占的份數,分鐘與秒都是總共60份,小時為12份。

    先畫圓與刻度:

 1 //畫圓,通過獲取寬高算出最短一邊作為直徑,坐標原點預設在手機屏幕左上角
 2         canvas.drawCircle(arcRa, arcRa, arcRa, paint);
 3 
 4         //圍繞圓形繪製刻度,坐標原點預設在手機屏幕左上角
 5         for (int i = 0; i < 60; i++) {///2π圓形分成60份,一秒鐘與一分鐘,所以要繪製60次,這裡是從0到59
 6             float x1, y1, x2, y2;//刻度的兩端的坐標即起始於結束的坐標
 7             float scale;//每個刻度離圓心的最近端坐標點到圓心的距離
 8             Double du = rr * i;//當前所占的角度
 9             Double sinx = Math.sin(du);//該角度的sin值
10             Double cosy = Math.cos(du);//該角度的cos值
11             x1 = (float) (arcRa + arcRa * sinx);//以預設坐標系通過三角函數算出刻度離圓心最遠的端點的x軸坐標
12             y1 = (float) (arcRa - arcRa * cosy);//以預設坐標系通過三角函數算出刻度離圓心最遠的端點的y軸坐標
13             if (i % 5 == 0) {//篩選刻度長度
14                 scale = 5 * arcRa / 6;//長刻度繪製,刻度離圓心的最近端坐標點到圓心的距離,這裡取半徑的五分之六的長度,可以通過情況來定
15             } else {
16                 scale = 9 * arcRa / 10;//短刻度繪製,這裡取半徑的十分之六九的長度,可以通過情況來定
17             }
18             x2 = (float) (arcRa + scale * sinx);//以預設坐標系通過三角函數算出該刻度離圓心最近的端點的x軸坐標
19             y2 = (float) (arcRa - scale * cosy);//以預設坐標系通過三角函數算出該刻度離圓心最近的端點的y軸坐標
20             canvas.drawLine(x1, y1, x2, y2, paint);//通過兩端點繪製刻度
21         }

    然後開始繪製時分秒指針:

 1  //利用三角函數計算分別計算出,時分秒三針所在的坐標點,坐標原點預設在手機屏幕左上角
 2         float sencondScale = 5 * arcRa / 6;//秒針長度
 3         float minuteScale = 3 * arcRa / 4;//分針長度
 4         float hourScale = arcRa / 2;//時針長度
 5         secondStartPoint.x = (float) (arcRa + sencondScale * Math.sin(secondAngle));
 6         secondStartPoint.y = (float) (arcRa - sencondScale * Math.cos(secondAngle));
 7         minuteStartPoint.x = (float) (arcRa + minuteScale * Math.sin(minuteAngle));
 8         minuteStartPoint.y = (float) (arcRa - minuteScale * Math.cos(minuteAngle));
 9         hourStartPoint.x = (float) (arcRa + hourScale * Math.sin(hourAngle));
10         hourStartPoint.y = (float) (arcRa - hourScale * Math.cos(hourAngle));
11  //繪製時、分、秒針,坐標原點預設在手機屏幕左上角
12         canvas.drawLine(arcRa, arcRa, secondStartPoint.x, secondStartPoint.y, paint);
13         canvas.drawLine(arcRa, arcRa, minuteStartPoint.x, minuteStartPoint.y, paint);
14         canvas.drawLine(arcRa, arcRa, hourStartPoint.x, hourStartPoint.y, paint);

   其實上面都是一個畫線條的過程,也就是知道兩點坐標drawLine的過程。接下來繪製數字,找到需要繪製地點的坐標,我們在長刻度上繪製小時數,一圈12個小時,那就在剛纔上面繪製長刻度裡面加上:

 1  //繪製長刻度上的數字1~12
 2                 String number = itime + "";//當前數字變為String類型
 3                 itime++;//數字加1
 4                 if (itime > 12) {//如果大於數字12,重置為1
 5                     itime = 1;
 6                 }
 7                 float numScale = 4 * arcRa / 5;//數字離圓心的距離,這裡取半徑的五分之四的長度,可以通過情況來定
 8                 float x3 = (float) (arcRa + numScale * sinx);//以預設坐標系通過三角函數算出x軸坐標
 9                 float y3 = (float) (arcRa - numScale * cosy);//以預設坐標系通過三角函數算出x軸坐標
10                 paint.getTextBounds(number, 0, number.length(), textBound);//獲取每個數字被全部包裹的最小的矩形邊框數值
11 
12                 //繪製數字,通過x3,y3根據文字最小包裹矩形邊框數值進行繪製點調整
13                 canvas.drawText(number, x3 - textBound.width() / 2, y3 + textBound.height() / 2, paint);

   繪製文字我以為只要drawText出來就行了,沒想到錯位了,我就思考怎麼會這樣,後來發現drawText的參數設定:

/** 
* text:繪製的文字 
* x:繪製原點x坐標 
* y:繪製原點y坐標(基線)
* paint:用來做畫的畫筆 
*/  
public void drawText(String text, float x, float y, Paint paint) 

這裡y是繪製的基線並不是文字中心點,基線這裡我用網上找到的圖來展示一下:

   所以還是得我們自己調整下文字的繪製位置,Paint畫筆預設繪製文字(SetTextAlign)是按照左下角紅點開始繪製:

   

    所以我就通過獲得paint.getTextBounds(number,0,number.length(),textBound);獲取每個數字被全部包裹的最小的矩形邊框數值,通過坐標移動將它移動到相應位置。

    最後繪製完畢了!   (╯‵□′)╯︵┻━┻怎麼放上去不動,不要唬我!那是忘記進行刷新操作,最後在onDraw方法中繪製完畢最後加上這個:

 postInvalidateDelayed(1000);//每秒刷新一次

     結束放上源碼與神秘鏈接:

GitHub:https://github.com/SteinsGateZero/MyclockViewtest.git

  1 public class MyClockView extends View {
  2     private Paint paint;//畫筆
  3     private int mainColor = Color.parseColor("#000000");//畫筆顏色
  4     private float mWidth, mHeight;//視圖寬高
  5     private float arcRa = 0;//圓半徑
  6     private Double rr = 2 * Math.PI / 60;//2π即360度的圓形分成60份,一秒鐘與一分鐘
  7     private Double rr2 = 2 * Math.PI / 12;//2π圓形分成12份,圓形顯示12個小時的刻度
  8     private PointF secondStartPoint, minuteStartPoint, hourStartPoint;//秒,分,時的坐標點
  9     private int startSecond, startMinute, startHour;//初始化時秒,分,時獲取的系統時間
 10     private Rect textBound = new Rect();//字體被全部包裹的最小的矩形邊框
 11 
 12     public MyClockView(Context context) {
 13         super(context);
 14         init();
 15     }
 16 
 17     public MyClockView(Context context, AttributeSet attrs) {
 18         super(context, attrs);
 19         init();
 20     }
 21 
 22     public MyClockView(Context context, AttributeSet attrs, int defStyleAttr) {
 23         super(context, attrs, defStyleAttr);
 24         init();
 25     }
 26 
 27     @Override
 28     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
 29         mWidth = w;//獲得寬度
 30         mHeight = h;//獲得高度
 31 
 32         //以最短的一邊為所要繪製圓形的直徑
 33         if (mWidth > mHeight) {
 34             arcRa = mHeight / 2;//以最短的一邊算出半徑
 35         } else {
 36             arcRa = mWidth / 2;//以最短的一邊算出半徑
 37         }
 38         super.onSizeChanged(w, h, oldw, oldh);
 39     }
 40 
 41     public void init() {
 42         paint = new Paint();//初始化畫筆
 43         paint.setColor(mainColor);//設置顏色
 44         //  paint.setAntiAlias(true);//抗鋸齒(性能影響)
 45         paint.setStyle(Paint.Style.STROKE);//設置畫筆
 46         paint.setTextSize(45);//設置字體大小
 47         secondStartPoint = new PointF(arcRa, 0);//初始化坐標點
 48         hourStartPoint = new PointF(arcRa, 0);
 49         minuteStartPoint = new PointF(arcRa, 0);
 50     }
 51 
 52     @Override
 53     protected void onDraw(Canvas canvas) {
 54         super.onDraw(canvas);
 55 
 56         //①獲取系統時間
 57         getCurrentTime();
 58 
 59         //②當前時間時分秒分別所占的份數(角度),即為上面rr,rr2所得到的每份的角度乘以獲得的時間
 60         Double secondAngle = rr * startSecond;
 61         Double minuteAngle = rr * startMinute;
 62         Double hourAngle = rr2 * startHour;
 63 
 64         //③利用三角函數計算分別計算出,時分秒三針所在的坐標點,坐標原點預設在手機屏幕左上角
 65         float sencondScale = 5 * arcRa / 6;//秒針長度
 66         float minuteScale = 3 * arcRa / 4;//分針長度
 67         float hourScale = arcRa / 2;//時針長度
 68         secondStartPoint.x = (float) (arcRa + sencondScale * Math.sin(secondAngle));
 69         secondStartPoint.y = (float) (arcRa - sencondScale * Math.cos(secondAngle));
 70         minuteStartPoint.x = (float) (arcRa + minuteScale * Math.sin(minuteAngle));
 71         minuteStartPoint.y = (float) (arcRa - minuteScale * Math.cos(minuteAngle));
 72         hourStartPoint.x = (float) (arcRa + hourScale * Math.sin(hourAngle));
 73         hourStartPoint.y = (float) (arcRa - hourScale * Math.cos(hourAngle));
 74 
 75         //④畫圓,通過獲取寬高算出最短一邊作為直徑,坐標原點預設在手機屏幕左上角
 76         canvas.drawCircle(arcRa, arcRa, arcRa, paint);
 77 
 78         //⑤圍繞圓形繪製刻度,坐標原點預設在手機屏幕左上角
 79         int itime = 12;//長的刻度要顯示的數字,這裡從12點刻度開始順時針繪製
 80         for (int i = 0; i < 60; i++) {///2π圓形分成60份,一秒鐘與一分鐘,所以要繪製60次,這裡是從0到59
 81             float x1, y1, x2, y2;//刻度的兩端的坐標即起始於結束的坐標
 82             float scale;//每個刻度離圓心的最近端坐標點到圓心的距離
 83             Double du = rr * i;//當前所占的角度
 84             Double sinx = Math.sin(du);//該角度的sin值
 85             Double cosy = Math.cos(du);//該角度的cos值
 86             x1 = (float) (arcRa + arcRa * sinx);//以預設坐標系通過三角函數算出刻度離圓心最遠的端點的x軸坐標
 87             y1 = (float) (arcRa - arcRa * cosy);//以預設坐標系通過三角函數算出刻度離圓心最遠的端點的y軸坐標
 88             if (i % 5 == 0) {//篩選刻度長度
 89                 scale = 5 * arcRa / 6;//長刻度繪製,刻度離圓心的最近端坐標點到圓心的距離,這裡取半徑的五分之六的長度,可以通過情況來定
 90 
 91                 //繪製長刻度上的數字1~12
 92                 String number = itime + "";//當前數字變為String類型
 93                 itime++;//數字加1
 94                 if (itime > 12) {//如果大於數字12,重置為1
 95                     itime = 1;
 96                 }
 97                 float numScale = 4 * arcRa / 5;//數字離圓心的距離,這裡取半徑的五分之四的長度,可以通過情況來定
 98                 float x3 = (float) (arcRa + numScale * sinx);//以預設坐標系通過三角函數算出x軸坐標
 99                 float y3 = (float) (arcRa - numScale * cosy);//以預設坐標系通過三角函數算出x軸坐標
100                 paint.getTextBounds(number, 0, number.length(), textBound);//獲取每個數字被全部包裹的最小的矩形邊框數值
101 
102                 //繪製數字,通過x3,y3根據文字最小包裹矩形邊框數值進行繪製點調整
103                 canvas.drawText(number, x3 - textBound.width() / 2, y3 + textBound.height() / 2, paint);
104 
105             } else {
106                 scale = 9 * arcRa / 10;//短刻度繪製,這裡取半徑的十分之六九的長度,可以通過情況來定
107             }
108             x2 = (float) (arcRa + scale * sinx);//以預設坐標系通過三角函數算出該刻度離圓心最近的端點的x軸坐標
109             y2 = (float) (arcRa - scale * cosy);//以預設坐標系通過三角函數算出該刻度離圓心最近的端點的y軸坐標
110             canvas.drawLine(x1, y1, x2, y2, paint);//通過兩端點繪製刻度
111         }
112 
113         //⑥繪製時、分、秒針,坐標原點預設在手機屏幕左上角
114         canvas.drawLine(arcRa, arcRa, secondStartPoint.x, secondStartPoint.y, paint);
115         canvas.drawLine(arcRa, arcRa, minuteStartPoint.x, minuteStartPoint.y, paint);
116         canvas.drawLine(arcRa, arcRa, hourStartPoint.x, hourStartPoint.y, paint);
117 
118         postInvalidateDelayed(1000);//每秒刷新一次
119     }
120 
121     private void getCurrentTime() {
122         long time = System.currentTimeMillis();//獲取時間
123         Calendar mCalendar = Calendar.getInstance();
124         mCalendar.setTimeInMillis(time);
125         startHour = mCalendar.get(Calendar.HOUR);//獲取小時,12小時制
126         startMinute = mCalendar.get(Calendar.MINUTE);//獲取分鐘
127         startSecond = mCalendar.get(Calendar.SECOND);//獲取秒
128     }
129 }

 


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

-Advertisement-
Play Games
更多相關文章
  • ViewPager中切換界面Fragment被銷毀的問題分析 使用ViewPager+Fragment實現界面切換,當界面數量大於3時,出現二次滑動後數據消失的情況,下麵由Fragment生命周期進行分析 簡單解析: 使用pager=3進行測試,當界面由2切換到1的時候,3界面對應的Fragment ...
  • 今天同事誤上傳一個庫,然後又刪除了。。。 我剛好把他上傳的庫給down下來了。。。然後項目一直報錯,clean。。。重新編譯。。。刪build文件。。。。全都不管用 好幾個人研究了好久,只能猜測是緩存問題。。。把項目的緩存全刪了沒用。。。。那應該是gradle緩存的問題。。。 可以我電腦上的grad ...
  • There may be a situation, when you need to execute a block of code several number of times. In general, statements are executed sequentially: The firs ...
  • 目錄: 一、Viewpager的簡單介紹 二、簡單的Viewpager使用 三、簡單顯示圖片的Viewpager實現 四、廣告圖的實現及Viewpager指示器(小圓點)的實現 五、APP引導頁的實現 一、ViewPager介紹 官方文檔解釋: Layout manager that allows ...
  • 一、核心動畫概念 -導入QuartzCore.framework框架 1⃣ 開發步驟1.初始化一個動畫對象(CAAnimation)並且設置一些動畫相關屬性 2.CALayer中很多屬性都可以通過CAAnimation實現動畫效果,包括:opacity、position、transform、boun ...
  • 翻轉的動畫 旋轉動畫 偏移動畫 翻頁動畫 縮放動畫 取反的動畫效果是根據當前的動畫取他的相反的動畫 ...
  • 前言 剛接手電筒子書項目時,和安卓開發者pt Cai老師【aipiti Cai,一個我很敬佩很資深的開發工程師,設計領域:c++、Java、安卓、QT等】共同商議了一下,因為項目要做要同步,移動端【手機端】和PC【電腦端】的同步問題,讓我們無法決定該用那種方式去呈現電子書,因為PC要展示的電子書有網路 ...
  • 介紹 Runloop是一種事件監聽迴圈,可以理解成一個while死迴圈,監聽到事件就起來,沒有就休息。 Runloop可以在不同模式下進行切換,iOS有五種模式,其中UIInitializationRunLoopModel應用程式啟動時會使用,啟動完成後將不再使用;GSEventReceiveRun ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...