Android 上傳圖片到伺服器 okhttp一

来源:https://www.cnblogs.com/xqz0618/archive/2019/02/28/uploadPic01.html
-Advertisement-
Play Games

【目錄】 (一)上傳圖片到伺服器一 Android代碼 (二)上傳圖片到伺服器二 Android 系統7.0以上調用相機相容問題 (三)上傳圖片到伺服器三 後臺伺服器代碼 一、相關知識 ①Android許可權申請 ②網路訪問框架OKHttp ③記憶體溢出問題:圖片壓縮 ④Android 系統7.0以上調 ...


 【目錄】

 (一)上傳圖片到伺服器一 ---------------------------------Android代碼

 (二)上傳圖片到伺服器二---------------------------------Android 系統7.0以上調用相機相容問題

 (三)上傳圖片到伺服器三 -----------------------------------後臺伺服器代碼

 

一、相關知識

①Android許可權申請

②網路訪問框架OKHttp

③記憶體溢出問題:圖片壓縮

④Android 系統7.0以上調用系統相機無效

⑤有關圖片上傳過程中遇到的記憶體溢出問題

 

二、效果展示

 

 

二、代碼

①HTML

 1          <LinearLayout
 2                 android:layout_width="match_parent"
 3                 android:layout_height="wrap_content"
 4                 android:orientation="vertical"
 5                 android:background="@color/white"
 6                 >
 7                 <android.support.v7.widget.RecyclerView
 8                     android:id="@+id/rvPic"
 9                     android:layout_width="wrap_content"
10                     android:layout_height="match_parent"
11                     android:layout_gravity="center_horizontal">
12 
13                 </android.support.v7.widget.RecyclerView>
14 
15                 <TextView
16                     android:id="@+id/tvNum"
17                     android:layout_width="wrap_content"
18                     android:layout_height="wrap_content"
19                     android:text="0/8"
20                     android:textColor="#666666"
21                     android:layout_gravity="right|bottom"
22                     android:paddingRight="@dimen/dp_10"/>
23 
24 
25             </LinearLayout>
26      <Button
27 
28         android:id="@+id/btn_Enter"
29         android:layout_width="match_parent"
30         android:layout_height="@dimen/dp_45"
31         android:layout_alignParentBottom="true"
32         android:background="@drawable/selecter_button"
33         android:text="確認上傳"
34         android:textColor="@color/inButtonText"
35         android:textSize="@dimen/dp_18" />

 

 

②Java代碼

<基本功能>

 實體類

 1 public class LoadFileVo {
 2 
 3     File file;
 4 
 5     int pg; //圖片下方的進度條
 6 
 7     boolean isUpload = false; //標識該文件是否上傳
 8 
 9     Bitmap bitmap;
10 
11     public Bitmap getBitmap() {
12         return bitmap;
13     }
14 
15     public void setBitmap(Bitmap bitmap) {
16         this.bitmap = bitmap;
17     }
18 
19     public boolean isUpload() {
20         return isUpload;
21     }
22 
23     public void setUpload(boolean upload) {
24         isUpload = upload;
25     }
26 
27     public LoadFileVo() {
28     }
29 
30     public LoadFileVo(File file, int pg) {
31         this.file = file;
32         this.pg = pg;
33     }
34 
35     public LoadFileVo(File file, boolean isUpload, int pg,Bitmap bitmap) {
36         this.file = file;
37         this.pg = pg;
38         this.isUpload = isUpload;
39         this.bitmap = bitmap;
40     }
41 
42     public File getFile() {
43         return file;
44     }
45 
46     public void setFile(File file) {
47         this.file = file;
48     }
49 
50     public int getPg() {
51         return pg;
52     }
53 
54     public void setPg(int pg) {
55         this.pg = pg;
56     }
57 }

 

適配器

  1 /*
  2  *Create By 小群子    2018/12/10
  3  */
  4 
  5 public class LoadPicAdapter extends RecyclerView.Adapter<LoadPicAdapter.MyViewHolder> {
  6 
  7     Context context;
  8     List<LoadFileVo> fileList = null;
  9     View view;
 10     int picNum = 8;//列表的圖片個數最大值
 11 
 12     public LoadPicAdapter(Context context, List<LoadFileVo> fileList) {
 13         this.context = context;
 14         this.fileList = fileList;
 15     }
 16 
 17     public LoadPicAdapter(Context context, List<LoadFileVo> fileList, int picNum) {
 18         this.context = context;
 19         this.fileList = fileList;
 20         this.picNum = picNum;
 21     }
 22 
 23     public interface OnItemClickListener {
 24         void click(View view, int positon);
 25 
 26         void del(View view);
 27     }
 28 
 29     OnItemClickListener listener;
 30 
 31     public void setListener(OnItemClickListener listener) {
 32         this.listener = listener;
 33     }
 34 
 35     @Override
 36     public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 37 
 38         view = LayoutInflater.from(context).inflate(R.layout.load_item_pic, parent, false);
 39         return new MyViewHolder(view);
 40     }
 41 
 42     @Override
 43     public void onBindViewHolder(MyViewHolder holder, final int position) {
 44 
 45         //通過預設設置第一個為空文件為添加退保,且在文件個數小於最大限制值的情況。當圖片個數等於最大限制值,第一個則不是添加按鈕
 46         if (position == 0&&fileList.get(position).getBitmap()==null) {
 47             holder.ivPic.setImageResource(R.drawable.addpic);//加號圖片
 48             holder.ivPic.setOnClickListener(new View.OnClickListener() {
 49                 @Override
 50                 public void onClick(View view) {
 51                     listener.click(view, position);
 52                 }
 53             });
 54             holder.ivDel.setVisibility(View.INVISIBLE);
 55             holder.bg_progressbar.setVisibility(View.GONE);
 56 
 57         } else {
 58 //            Uri uri = Uri.parse(fileList.get(position).getFile().getPath());
 59 //            holder.ivPic.setImageURI(uri);
 60 
 61             holder.ivPic.setImageBitmap(fileList.get(position).getBitmap());
 62             //使用壓縮後的圖片進行填充到界面上
 63            
64 65 66 holder.ivDel.setVisibility(View.VISIBLE); 67 holder.bg_progressbar.setVisibility(View.VISIBLE); 68 holder.bg_progressbar.setProgress(fileList.get(position).getPg()); 69 } 70 71 72 holder.ivDel.setOnClickListener(new View.OnClickListener() { 73 @Override 74 public void onClick(View view) { 75 //判斷圖片是否上傳,上傳後將無法刪除 76 if (fileList.get(position).isUpload()) { 77 Toast.makeText(context, "該圖片已上傳!", Toast.LENGTH_SHORT).show(); 78 } else { 79 fileList.remove(position); 80 if (fileList.size()==picNum-1&&fileList.get(0).getBitmap()!=null){ 81 fileList.add(0,new LoadFileVo()); 82 }//如果數量達到最大數時,前面的加號去掉,然後再減去時,則添加前面的加號 83 notifyDataSetChanged(); 84 if (listener!=null){ 85 listener.del(view);//傳遞介面,計算圖片個數顯示在界面中 86 } 87 88 } 89 } 90 }); 91 92 93 } 94 95 @Override 96 public int getItemCount() { 97 return fileList.size(); 98 } 99 100 101 static class MyViewHolder extends RecyclerView.ViewHolder { 102 @BindView(R.id.ivPic) 103 ImageView ivPic; 104 @BindView(R.id.ivDel) 105 ImageView ivDel; 106 @BindView(R.id.bg_progressbar) 107 ProgressBar bg_progressbar; 108 109 View view; 110 111 112 MyViewHolder(View view) { 113 super(view); 114 this.view = view; 115 ButterKnife.bind(this, view); 116 } 117 } 118 }

 

item 佈局//佈局自行優化

 1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
 2     android:layout_width="@dimen/dp_110"
 3     android:layout_height="@dimen/dp_115"
 4 
 5     >
 6 
 7     <LinearLayout
 8         android:layout_width="match_parent"
 9         android:layout_height="match_parent"
10         android:orientation="vertical"
11         android:padding="@dimen/dp_5">
12 
13         <ImageView
14             android:id="@+id/ivPic"
15             android:layout_width="match_parent"
16             android:layout_height="@dimen/dp_100"
17             android:scaleType="centerCrop"
18             android:src="@drawable/ic_pick"
19             />
20 
21         <ProgressBar
22             android:id="@+id/bg_progressbar"
23             style="@style/StyleProgressBarMini"
24             android:layout_width="match_parent"
25             android:layout_height="@dimen/dp_5"
26             android:background="@drawable/shape_progressbar_mini"
27             android:max="100"
28             android:progress="60" />
29     </LinearLayout>
30     <ImageView
31         android:id="@+id/ivDel"
32         android:layout_width="@dimen/dp_25"
33         android:layout_height="@dimen/dp_25"
34         android:src="@drawable/delete_round"
35         android:layout_alignParentRight="true"/>
36 
37 </RelativeLayout>

 

 1 List<LoadFileVo> fileList = new ArrayList<>();
 2 LoadPicAdapter adapter = null;
 3 
 4   //這裡使用ButterKnife
 5     @BindView(R.id.rvPic)
 6       RecyclerView rvPic;
 7 
 8     @BindView(R.id.tvNum)
 9        TextView tvNum;
10 
11 
12     //初始化Adapter
13     //設置圖片選擇的介面
14     private void initAdapter() {
15         fileList.add(new LoadFileVo());
16         adapter = new LoadPicAdapter(this, fileList,8);
17         rvPic.setAdapter(adapter);
18         rvPic.setLayoutManager(new GridLayoutManager(this, 3));
19         adapter.setListener(new LoadPicAdapter.OnItemClickListener() {
20             @Override
21             public void click(View view, int positon) {
22                 if (fileList.size()>8){
23                     showShortToast("一次最多上傳8張圖片!");
24                 }else {
25                     selectPic();  //選擇添加圖片方法
26                 }
27 
28             }
29 
30             @Override
31             public void del(View view) {
32                 tvNum.setText((fileList.size()-1)+"/8");
33             }
34         });
35     }

 

《核心代碼》

 1 String mPhtotPath;
 2 Uri uriImage;
 3 File mPhotoFile = null;
 4 
 5 
 6 //選擇圖片
 7 private void selectPic() {
 8 
 9 //動態請求許可權,除此之外還需進行Androidmanifest.xml中進行請求
10 
11         if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA)
12                 != PackageManager.PERMISSION_GRANTED || ContextCompat.checkSelfPermission(this,
13                 Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED
14                 || ContextCompat.checkSelfPermission(this,
15                 Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
16             ActivityCompat.requestPermissions(this,
17                     new String[]{Manifest.permission.CAMERA,
18                             Manifest.permission.READ_EXTERNAL_STORAGE,
19                             Manifest.permission.WRITE_EXTERNAL_STORAGE},
20                     1);
21         }
22 
23 
24         final CharSequence[] items = {"相冊", "拍照"};
25         AlertDialog.Builder dlg = new AlertDialog.Builder(EndLoadMstActivity.this);
26         dlg.setTitle("添加圖片");
27         dlg.setItems(items, new DialogInterface.OnClickListener() {
28             public void onClick(DialogInterface dialog, int item) {
29                 // 這裡item是根據選擇的方式,
30                 if (item == 0) {
31                     Intent intent = new Intent(Intent.ACTION_PICK);
32                     intent.setType("image/*");
33                     startActivityForResult(intent, 0);
34                 } else {
35                     try {
36                         Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
37                         mPhtotPath = getSDPath() + "/" + getPhotoFileName();
38                         mPhotoFile = new File(mPhtotPath);
39                         if (!mPhotoFile.exists()) {
40                             mPhotoFile.createNewFile();
41                         }
42 //                        uriImage = FileProvider.getUriForFile(EndLoadMstActivity.this, getPackageName() + ".provider", createImageFile());
43 
44                         uriImage = FileProvider.getUriForFile(EndLoadMstActivity.this, "com.ahbcd.app.tms.provider", mPhotoFile);
45                         Log.i("TAG", "onClick: "+mPhtotPath+"---------" + getPackageName() + ".provider");
46                         // uriImage = Uri.fromFile(mPhotoFile);以上一句代替解決相機相容問題
47                         intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
48                         intent.putExtra(MediaStore.EXTRA_OUTPUT, uriImage);
49 
50                         startActivityForResult(intent, 1);
51 
52                     } catch (Exception e) {
53                         e.printStackTrace();
54                     }
55                 }
56             }
57         }).create();
58         dlg.show();
59     }
60 
61 public String getSDPath() {
62         File sdDir = null;
63         boolean sdCardExsit = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);
64         if (sdCardExsit) {
65             sdDir = Environment.getExternalStorageDirectory();
66         }
67         return sdDir.toString();
68     }
69 
70     private String getPhotoFileName() {
71         Date date = new Date(System.currentTimeMillis());
72         SimpleDateFormat dateFormat = new SimpleDateFormat("'IMG'_yyyyMMdd_HHmmss");
73         return dateFormat.format(date) + ".jpg";
74     }

 

註:這裡需要在Android中配置一個proveder 具體請參考 Android 系統7.0以上調用相機相容問題

《獲取返回的圖片》

 1 //重寫onActivityResult方法
 2 @Override
 3     protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 4         super.onActivityResult(requestCode, resultCode, data);
 5         if (requestCode == 1) {
 6             BitmapFactory.Options options = new BitmapFactory.Options();
 7             options.inSampleSize = 2; //圖片寬高都為原來的二分之一,即圖片為原來的四分之一
 8             Bitmap bitmap = BitmapFactory.decodeFile(mPhtotPath, options);
 9             if (bitmap != null) {
10                 if (uriImage != null) {
11                     saveUritoFile(uriImage,1);
12                 }
13 
14                 if (!bitmap.isRecycled()) {
15                     bitmap.recycle(); //回收圖片所占的記憶體
16                     System.gc(); //提醒系統及時回收
17                 }
18             }
19         }
20         if (requestCode == 0) {
21             if (data != null) {
22                 Uri uri = data.getData();
23                 saveUritoFile(uri,0);
24             }
25         }
26 
27     }
28 
29 //將Uri圖片類型轉換成File,BitMap類型
30 //在界面上顯示BitMap圖片,以防止記憶體溢出
31 //上傳可選擇File文件上傳
32 
33     private void saveUritoFile(Uri uriImage,int type) {
34         Bitmap photoBmp = null;
35 
36         if (uriImage != null) {
37             try {
38 //                photoBmp = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uriImage);
39 //                ByteArrayOutputStream fos = new ByteArrayOutputStream();
40 //                photoBmp.compress(Bitmap.CompressFormat.JPEG, 80, fos);
41                 //以上代碼壓縮不行,還是會造成記憶體溢出
42 
43                 BitmapFactory.Options options = new BitmapFactory.Options();
44                 options.inSampleSize = 2; //圖片寬高都為原來的二分之一,即圖片為原來的四分之一
45                 photoBmp = BitmapFactory.decodeStream(this.getContentResolver()
46                         .openInputStream(uriImage), null, options);
47 
48                 File file = new File("");
49                 if (type==0){
50                     file = FileParseUtils.getFileByUri(this, uriImage);
51 
52                 }else {
53                     if (mPhotoFile!=null){
54                         file = mPhotoFile;
55                     }
56 
57                 }
58 //                File file = new File("");
59 //                try {
60 //                    file = new File(new URI(uriImage.toString()));
61 //                } catch (URISyntaxException e) {
62 //                    e.printStackTrace();
63 //                }
64                 fileList.add(new LoadFileVo(file, false, 0, photoBmp));
65                 tvNum.setText((fileList.size()-1)+"/8");
66                 if (fileList.size()>8){    //判斷時候達到最大數量,如果達到最大數量,則去掉前面的加號
67                     fileList.remove(0);
68                 }
69 
70                 adapter.notifyDataSetChanged();
71 
72             } catch (IOException e) {
73                 e.printStackTrace();
74                 Log.i("TAG", "saveUritoFile: ---------壓縮圖片異常!");
75             }
76 
77 
78         }
79 
80     }

 

圖片上傳到後臺OKhttp

  1 //一張張圖片輪流上傳
  2 public void netUpload(int i, final String joData) {//用jsonOject方式轉string傳遞其他參數
  3         try {
  4 
  5             if (!isRequestHttp) {
  6                 isRequestHttp = true;
  7                 final int finalI = i;
  8                 enterEnable(false);
  9 
 10                 if (fileList.get(finalI).isUpload()) {
 11                     netUpload(finalI + 1, joData);
 12                 } else {
 13 
 14         RequestBody requestBody = new MultipartBody.Builder()
 15                 .setType(MultipartBody.FORM)
 16                 .addFormDataPart("mstjson",msg)  //其他信息
 17                 .addFormDataPart("file", file.getName(),
 18                         RequestBody.create(MediaType.parse("application/octet-stream"), file))//文件
 19                 .build();
 20         Request request = new Request.Builder()
 21                 .url(uploadPic---這裡是圖片上傳的地址).post(requestBody)
 22                 .build();
 23         okHttpClient.newCall(request).enqueue(new UICallBack() {
 24                         @Override
 25                         public void onFailureUI(Call call, IOException e) {
 26                             showShortToast("連接伺服器失敗");
 27                             isRequestHttp = true;
 28                             enterEnable(true);
 29 
 30                         }
 31 
 32                         @Override
 33                         public void onResponseUI(Call call, Response response) {
 34                             try {
 35 
 36                                 isRequestHttp = false;
 37 
 38                                 String result = response.body().string();
 39                                 Utils.log("上傳圖片結果:" + result);
 40 
 41 
 42                                 if (!response.isSuccessful()) {
 43                                     Utils.log("響應失敗:" + response.code());
 44                                     showShortToast("響應失敗:" + response.code());
 45                                     enterEnable(true);
 46 
 47                                     return;
 48                                 }
 49                                 if (result.equals("{}")) {
 50                                     showShortToast("獲取服務端數據為空");
 51                                     enterEnable(true);
 52 
 53                                     return;
 54                                 }
 55                                 JSONObject jsonObject = new JSONObject(result);
 56                                 i

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

-Advertisement-
Play Games
更多相關文章
  • 同一個賬號,不同客戶端登錄,可以根據user()來記錄IP、判斷是誰在操作。 ...
  • 設計SQL後,應使用explain命令檢查SQL,看是否使用到索引,是否存在filesort,重點檢查檢索的行數(rows)是否太大。 一般來說. 1.rows<1000,是在可接受的範圍內的。 2.rows在1000~1w之間,在密集訪問時可能導致性能問題,但如果不是太頻繁的訪問(頻率低於1分鐘一 ...
  • 資料庫索引,到底是什麼做的? 問題1. 資料庫為什麼要設計索引? 圖書館存了1000W本圖書,要從中找到《架構師之路》,一本本查,要查到什麼時候去? 於是,圖書管理員設計了一套規則: (1)一樓放歷史類,二樓放文學類,三樓放IT類… (2)IT類,又分軟體類,硬體類… (3)軟體類,又按照書名音序排 ...
  • 1. redis事務 使用方法:方法為先發送multi命令告訴redis,下麵所有的命令屬於同一個事務,先不要執行,而是把他們暫時存起來,redis返回OK,然後後面執行需要放在同一個事務里的命令,可以看到每個命令都會返回QUEUED表示這幾條命令已經進入等待執行的事務隊列中了,當需要在同一個事務中 ...
  • 可以使用EXTRACT() 函數。(oracle和mysql都有該函數)語法: EXTRACT(unit FROM date)date 參數是合法的日期表達式。unit 參數可以是下列的值:YEAR\MONTH\WEEK\DAY\HOUR\MINUTE\SECOND (這裡只列出部分常用值)上面依次 ...
  • 摘要: 下文將分享三種不同的數據去重方法數據去重:需根據某一欄位來界定,當此欄位出現大於一行記錄時,我們就界定為此行數據存在重覆。 數據去重方法1: 當表中最在最大流水號時候,我們可以通過關聯的方式為每條重覆的記錄獲取唯一值數據去重方法2:為表中記錄,按照指定欄位進行群組,並獲取最大流水號,然後再進 ...
  • MySql中處理字元串時間,會預設把第一個數字當成年份處理。 在C#伺服器中,使用Date.Now.ToString()生成的字元串時間,如果不指定字元串格式,C#會按照系統語言輸出不同的字元串格式,如: a. 美國: 06/01/2019 01:59:00 PM b.中國: 2019/06/01 ...
  • 大家都知道,評論和評分是決定app在appstore中排名的重要因素,但是大部分用戶下載安裝APP後卻不會去點評,所以添加提示用戶去點評的功能是很必要的。 目前,AppStore點贊評分有兩種方法,一種是跳出應用,跳轉到AppStore;進行評分.另一種是在應用內,內置AppStore進行評分. 序 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...