代碼“小白”的溫故而知新(一)-----OA管理系統

来源:http://www.cnblogs.com/xrk1203/archive/2017/06/27/6986447.html
-Advertisement-
Play Games

古人雲:溫故而知新。這是極好的,近來,作為一個小白,利用點空閑時間把之前幾個月自己寫過的一個作為練手的一個OA系統又重新拿來溫習一番,希望在鞏固基礎之上能得到新的啟示。現在回想起來,之前一個人,寫寫停停,不覺感嘆,平時工作中團隊的重要性以及個人力量的渺小。因為是練手的項目,整個系統從資料庫到前端都是 ...


      古人雲:溫故而知新。這是極好的,近來,作為一個小白,利用點空閑時間把之前幾個月自己寫過的一個作為練手的一個OA系統又重新拿來溫習一番,希望在鞏固基礎之上能得到新的啟示。現在回想起來,之前一個人,寫寫停停,不覺感嘆,平時工作中團隊的重要性以及個人力量的渺小。因為是練手的項目,整個系統從資料庫到前端都是自己設計,所以不免顯得有點寒磣,不喜勿噴,但該有的重點還是有的,至於美工,哈哈,簡潔也是一種美不是嗎,只能這樣安慰自己了。

     準備工作:

     1.進行初步的需求分析(有四大板塊:我的桌面,人力資源管理,考勤管理,工作流管理)

     2.每個大板塊下又分小塊

     (我的桌面---》每日考勤,提交申請,我的審批【高級員工】,我的申請;

        人力資源----》員工管理,部門管理,職位管理,角色管理;

       考勤管理----》工作日設置,工作時間設置,考勤記錄查詢;

       工作流管理----》流程管理)

    3.技術實現:ASP.NET  MVC,EF,Jquery,T4,log4Net,MD5,Jquery-easy-uI,Sqlser2008,Membercache,後期用到spring.net

 

先看看前期大概的一個頁面展示圖:

主頁面:

員工信息頁面:

添加員工:

編輯員工:

 

--------------------------------------------------------------------------------------------------------------------------------------------------------------

正文:

好了,閑話不多說,先設計資料庫吧,在設計資料庫之前,有幾點我們也需要註意,

1.對於表的命名一定要規範;

2.表的設計原則是一張表只記錄一件事,如果表與表有關係的,通過外鍵關聯。

在這裡面,建表需要註意的是對菜單表ActionInfo的設計,因為它分級別,有一級菜單,二級菜單,對於這種表的設計,

ActionId     標識列  主鍵---》(渲染到前端的是id)

Title   標題   nvarchar(20)---》(text)                    

Leval  1  2 int   決定將來顯示的層級圖標(1代表菜單,2代表菜單項)

URL:允許為空,一級沒有,二級有【通過這個url訪問】

PrentId  int   not null  對於一級菜單,取值為0【重要】

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

接下來就是搭建框架了,採用簡單抽象工廠三層的項目結構

框架搭完,先做主頁面,Home/Index    Home控制下的Index的html代碼  主頁面

  1 @using Model.Models
  2 @{
  3     Layout = null;
  4     EmployeeInfo emp = ViewData["user"] as EmployeeInfo;
  5    
  6 }
  7 
  8 <!DOCTYPE html>
  9 
 10 <html>
 11 <head>
 12     <meta name="viewport" content="width=device-width" />
 13     <title>通達OA</title>
 14     <script src="~/Scripts/jquery-1.7.1.js"></script>
 15     <script src="~/Scripts/MyAjaxForm.js"></script>
 16     <script src="~/Scripts/jquery.easyui.min.js"></script>
 17     <script src="~/Scripts/easyui-lang-zh_CN.js"></script>
 18     <link href="~/Content/easyui.css" rel="stylesheet" />
 19     <link href="~/Content/icon.css" rel="stylesheet" />
 20    <style type="text/css">
 21        a
 22        {
 23            text-decoration:none;
 24        }
 25        #emp
 26        {
 27            position:absolute;
 28            color:red;
 29            bottom:5px;
 30            left:5px;
 31 
 32        }
 33      
 34    </style>
 35 </head>
 36     
 37 <body class="easyui-layout" onselectstart=" return false;">
 38     <div data-options="region:'north',split:false" style="height: 110px; background: url(/Content/Images/OA2.png) no-repeat 0px -52px ;position:relative">
 39        <p id="emp">歡迎您的登錄:@emp.EmpName <a  href="/User/Login?state=false">[註銷用戶]</a></p>
 40     </div>
 41 
 42     <div data-options="region:'west',title:'導航菜單',split:false" style="width: 150px;  background: url(/Content/Images/OA.jpg) no-repeat -20px ">
 43         <ul id="tt">
 44         </ul>
 45     </div>
 46 
 47     <div data-options="region:'center',title:'主頁面'" style="padding: 5px; background: url(/Content/Images/OA3.jpg) no-repeat; opacity:0.88">
 48         <div id="p" style="padding: 10px;">
 49                      
 50         </div>  
 51     </div>
 52 
 53     @* 彈出的獨立視窗 *@
 54     <div id="editwin">
 55         <iframe id="editframe" width="100%" frameborder="0" scrolling="no">
 56             
 57         </iframe>
 58     </div>  
 59 
 60 
 61     <script type="text/javascript">
 62 
 63         //刷新頁面
 64         function afterSave() {
 65             $("#editwin").window("close");
 66             $("#editframe").attr("src", "null");
 67             $("#dg").datagrid("reload");
 68         };
 69 
 70 
 71         $('#tt').tree({
 72             url: "/Action/LoadData",
 73             checkbox: 'true',
 74             lines: 'true',
 75             dnd: 'false',
 76             animate: 'true',
 77             formatter: function (node) {
 78                 return ("[" + node.text + "]");
 79             },
 80             onClick: function (node) {
 81                 $('#p').panel({
 82                     fit:true,
 83                     title: node.text,
 84                     href:node.url
 85                    
 86                 });
 87             }
 88            
 89         });
 90    
 91         //彈窗
 92         function popEditWindow(caption,width,src)
 93         {    
 94                 $("#editwin").css("display", "block");
 95                 $('#editwin').window({
 96                     title: caption,
 97                     width: width,                    
 98                     resizable: false,
 99                     shadow:false,
100                     modal: true
101                 });
102              
103                 $("#editframe").attr("src", src);
104                 $("#editframe").load(function () {
105                     var mainheight = $(this).contents().find("body").height() + 30;
106                     $(this).height(mainheight);
107                 });
108          
109         }
110      
111 
112 
113     </script>
114 </body>
115 </html>
View Code

我整體的頁面佈局用的是Easy-UI,首頁內容使用的是panel組件,菜單欄使用的是tree組件。

需要註意的是:

1.panel組件可以通過設置href屬性從遠程載入頁面,但只會載入頁面的body內容,可是像添加員工,編輯員工這樣的,我們需要額外進行一些css樣式的改變時,他卻變得無效了,所以在面板之內,我添加了一個Iframe框架,Iframe  框架  有一個src屬性,這個屬性可以請求一個遠程界面(完整的,獨立的頁面),你可以在裡面做上你自己的css樣式進行改變。

2.iframe框架如何自適應高度?

解決方案:

 $("#editframe").load(function () {

    var mainheight = $(this).contents().find("body").height() + 30;

      $(this).height(mainheight);

                    });

3.如何在iframe框架內嵌的網頁中去訪問他所在的主頁面的資源?

解決方案:

在主頁面定義要使用的資源方法,然後再包含iframe的子頁面中調用window.parent.方法名()。

 -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Action/Index   ||菜單欄代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Script.Serialization;
using BLL;
using Model.Models;

namespace UI.Controllers
{
    public class ActionController :BaseController
    {
        //
        // GET: /Action/

        public ActionResult Index()
        {
            return View();
        }
        /// <summary>
        /// 一次性載入菜單數據
        /// </summary>
        /// 
        /// <returns>
        /// 符合tree樹形控制項的json格式的對象
        /// </returns>
        public ActionResult LoadData()
        {
            //沒有進行許可權分配,預設登錄後載入所有菜單列表
            List<ActionInfo> actionList = new ActionService().GetActionList(a => true);

            //調用存儲過程進行過濾
           // List<ActionInfo> actionList = new ActionService().GetActionListByEmp(this.user.EmpId);

            //採用EF查詢進行過濾
            //List<ActionInfo> actionList = new ActionService().GetActionByEmpId(this.user.EmpId);

            //構造符合tree樹形控制項的json格式的對象
            List<MenuItem> menulist = new List<MenuItem>();
            foreach (var item in actionList.Where(a=>a.Leval==1))
            {
                //第一級菜單
                MenuItem first = new MenuItem { id = item.ActionId, text = item.Title, state = "closed", url = null };
                List<MenuItem> second = new List<MenuItem>();
                List<ActionInfo> secondActionList = actionList.Where(a=>a.PrentId==item.ActionId).ToList();
                foreach (var i in secondActionList)
                {
                    second.Add(new MenuItem { id = i.ActionId, text = i.Title,state="open",url = i.URL });
                }
                first.children = second;
                menulist.Add(first);
            }
            //JSON序列化
            JavaScriptSerializer jss = new JavaScriptSerializer();
            string result = jss.Serialize(menulist);
            return Content(result);
        }


    }

    //構造符合tree組件的實體類
    public class MenuItem
    {
        public int id { get; set; }
        public string  text { get; set; }
        public string state { get; set; }
        public string  url { get; set; }
        public List<MenuItem>  children { get; set; }
    }
}
View Code

Employee     ||控制器下代碼

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using Model.Models;
using BLL;
using UI.Models;
using System.Web.Script.Serialization;
using Newtonsoft.Json;

namespace UI.Controllers
{
    public class EmployeeController : BaseController
    {
        //
        // GET: /Employee/

        public ActionResult List()
        {
            return View();
        }

        public ActionResult LoadData(int page, int rows)
        {

            int totalCount = 0;
            List<EmployeeInfo> emplist = new EmployeeService().GetEmpListByPage(page, rows, ref totalCount);
            //解決方案二:使用Newtonsoft程式集
            var result = JsonConvert.SerializeObject(new { total = totalCount, rows = emplist });          
            return Content(result);

        }

        [HttpGet]
        public ActionResult AddEmp(int? id)
        {
            string url = "/Employee/AddEmp";
            List<DepartmentInfo> depList = new DepartmentService().GetDepList(d => true);
            List<PositionInfo> posList = new PositionService().GetPosList(p => true);
            EmployeeInfo emp;
            ViewEmpModel model = new ViewEmpModel();
            if (id != null)
            {
                url = "/Employee/Update";
                emp = new EmployeeService().GetDepByEmp(e => e.EmpId == id).SingleOrDefault();
                model = new ViewEmpModel { EmpName = emp.EmpName, EmpBirthday = emp.EmpBirthday.ToString(), EmpEmail = emp.EmpEmail, EmpTelephone = emp.EmpTelephone, EmpUrl = url, LoginId = emp.LoginId, EmpGender = emp.EmpGender, DepId = emp.DepId, EmpId = emp.EmpId, PosId = emp.PosId, LoginPwd = emp.LoginPwd, DelFlag = emp.DelFlag };
                ViewData["DepId"] = new SelectList(depList, "DepId", "DepName", emp.DepId);
                ViewData["PosId"] = new SelectList(posList, "PosId", "PosName", emp.PosId);
            }
            else
            {
                ViewData["DepId"] = new SelectList(depList, "DepId", "DepName");
                ViewData["PosId"] = new SelectList(posList, "PosId", "PosName");
                ViewData["deplist"] = depList;
                ViewData["poslist"] = posList;
            }
            ViewData.Model = model;
            return View();
        }

        [HttpPost]
        public ActionResult AddEmp(EmployeeInfo emp)
        {
            emp.DelFlag = false;
            emp.LoginPwd = "888888";
            bool flag = new EmployeeService().AddEmp(emp);
            return flag ? Content("ok") : Content("fail");
        }

        //展示員工詳細信息
        public ActionResult ShowEmp(int id)
        {
            EmployeeInfo emp = new EmployeeService().GetDepByEmp(e => e.EmpId == id).SingleOrDefault();

          List<AdjustPosition> adplist = new AdjustPositionService().GetAdpList(a => a.EmpId == emp.EmpId);
          List<AdjustDepartment> addlist = new AdjustDepartmentService().GetAddList(a => a.EmpId == emp.EmpId);


            string gender = emp.EmpGender ? "" : "";
            ViewData["gender"] = gender;
            ViewData["adp"] = adplist;
            ViewData["add"]=addlist;
            return View(emp);
        }

        //修改員工
        [HttpPost]
        public ActionResult Update(EmployeeInfo emp)
        {
            bool falg = new EmployeeService().UpdateEmp(emp);
            return falg ? Content("ok") : Content("fail");
        }
        /// <summary>
        /// 刪除員工
        /// </summary>
        /// <param name="idlist"></param>
        /// <returns></returns>
        public ActionResult Delete(string idlist)
        {
            bool falg = new EmployeeService().DeleteEmpList(idlist);
            return falg ? Content("ok") : Content("fail");
        }

        //員工調整
        [HttpGet]
        public ActionResult AdjustEmp(int id)
        {           
            List<DepartmentInfo> depList = new DepartmentService().GetDepList(d => true);
            List<PositionInfo> posList = new PositionService().GetPosList(p => true);
            EmployeeInfo emp = new EmployeeInfo();
            emp = new EmployeeService().GetDepByEmp(e => e.EmpId == id).SingleOrDefault();
            //如何將查詢到的數據綁定到視圖中的下拉列表框,第四個參數是選中的值
            ViewData["DepId"] = new SelectList(depList, "DepId", "DepName", emp.DepId);
            ViewData["PosId"] = new SelectList(posList, "PosId", "PosName", emp.PosId);
            ViewData["deplist"] = depList;
            ViewData["poslist"] = posList;
            ViewData.Model = emp;

            ViewData["EmpId"]=emp.EmpId;
            ViewData["OldDepartmentId"]=emp.DepId;
            ViewData["OldPositionId"] = emp.PosId;
            return View();
        }

        [HttpPost]
        public ActionResult Adjust(EmployeeInfo emp,AdjustDepartment add,AdjustPosition adp)
        {
            //接收原來部門的編號
            int OldDepartmentId = Convert.ToInt32(Request["OldDepartmentId"]);
            //接收原來職位的編號
            int OldPositionId = Convert.ToInt32(Request["OldPositionId"]);

            AdjustManagerService am = new AdjustManagerService();
            adp.NewPositionId = emp.PosId;
            add.NewDepartmentId = emp.DepId;
            adp.AdjustTime = DateTime.Now;
            add.AdjustTime = DateTime.Now;
            bool falg;
            //職位調整並且部門沒調整
            if (add.NewDepartmentId == add.OldDepartmentId&&adp.NewPositionId != adp.OldPositionId)
            {
              
                falg = am.Add(adp);
            }
            //部門調整並且職位沒調整
            else if (add.NewDepartmentId != add.OldDepartmentId && adp.NewPositionId == adp.OldPositionId)
            {
                falg = am.Add(add);
            }
             //部門和職位都調整了
            else if (add.NewDepartmentId != add.OldDepartmentId && adp.NewPositionId != adp.OldPositionId)
            {
                falg = am.Add(add,adp);
            }                        
            falg = new EmployeeService().UpdateEmp(emp);       
            return falg ? Content("ok") : Content("fail");


        }
    }
}
View Code

給出Employee的List的視圖代碼,後面部門類似參考

  1 @{
  2     Layout = null;
  3 }
  4 <!DOCTYPE html>
  5 <html>
  6 <head>
  7     <meta name="viewport" content="width=device-width" />
  8     <title>員工界面</title>
  9 </head>
 10 <body>
 11     <table id="dg">
 12     </table>
 13     <script type="text/javascript">
 14         var fieldName;
 15         $("#editwin").css("display", "none");
 16         $('#dg').datagrid({
 17             url: '/Employee/LoadData',
 18             pagination: true,//page=1&rows=10
 19             pageList: [10, 15, 20],
 20             columns: [[
 21                 { field: 'check', checkbox: true, width: 50 },
 22                 { field: 'EmpId', title: '員工編號', width: 50 },
 23                 { field: 'EmpName', title: '員工姓名', width: 100 },
 24                 {
 25                     field: 'EmpGender', title: '員工性別', width: 100, formatter: function (value, row, index) {
 26                         return value ? "" : "";
 27                     }
 28                 },
 29                 { field: 'EmpBirthday', title: '員工生日', width: 100 },
 30                 { field: 'EmpTelephone', title: '員工電話', width: 100 },
 31                 { field: 'EmpEmail', title: '郵件地址', width: 200 },
 32                 {
 33                     field: 'Operator', title: '員工操作', width: 300,
 34                     formatter: function () {
 35                         return "<a href='#' class='editemp'>編輯員工</a> |  <a href='#' class='detail' onclick='showEmp(this);'>詳細信息</a> |<a href='#' class='adjustemp' onclick='AdjustEmp(this)'>員工調整</a> |<a href='#' class='setAction' onclick='SetAction(this)'>分配許可權</a>  ";
 36                     }
 37                 }
 38 
 39             ]],
 40             toolbar: [{
 41                 iconCls: 'icon-add',
 42                 text: '添加員工',
 43                 handler: function () {
 44                     //調用在主頁面Index中封裝的彈窗函數
 45                     popEditWindow("添加員工", 400, "/Employee/AddEmp");                  
 46                 }
 47             }, '-', {
 48                 iconCls: 'icon-cancel',
 49                 text: '刪除員工',
 50                 handler: function () {
 51                     var rows = $("#dg").datagrid('getSelections');
 52                     if (rows.length == 0) {
 53                         $.messager.alert("提示", "請選擇刪除行!");
 54                         return;
 55                     }
 56                     $.messager.confirm('確認', '確定刪除嗎?', function (r) {
 57                         if (r) {
 58                             //獲取編號id,並以一定的規則做成字元串
 59                             var idlist = "";
 60                             for (var i = 0; i < rows.length; i++) {
 61                                 idlist = idlist + rows[i]["EmpId"] + ",";
 62                             }
 63                             //截取
 64                             idlist = idlist.substr(0, idlist.length - 1);
 65                             //非同步請求發送要刪除的字元串
 66                             $.ajax({
 67                                 url: "/Employee/Delete",
 68                                 type: "post",
 69                                 data: { "idlist": idlist },
 70                                 dataType: "text",
 71                                 success: function (res) {
 72                                     if (res == "ok") {
 73                                         $("#dg").datagrid("reload"	   

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

-Advertisement-
Play Games
更多相關文章
  • 環境:筆記本 + 家用WIFI + 公司WIFI + VMware + CentOS6.8 + Xshell 問題描述:初學Linux時,用筆記本裝了虛擬機(單網卡),想實現linux在家和公司都能夠無線連網,但又不想上網地點變動之後每次手動輸入IP登錄Xshell。 解決思路:增加一塊網卡(eth ...
  • 一、簡介 1、認識 加密網頁(https): tcp:443 明文網頁(http): tcp:80 survey.netcraft.net --這個網站上可以查到最新的網站伺服器的使用率 超文本傳輸協議(HTTP,HyperText Transfer Protocol)是互聯網上應用最為廣泛的一種網 ...
  • select系統調用的的用途是:在一段指定的時間內,監聽用戶感興趣的文件描述符上可讀、可寫和異常等事件。 select 機制的優勢 為什麼會出現select模型? 先看一下下麵的這句代碼: 這是用來接收數據的,在預設的阻塞模式下的套接字里,recv會阻塞在那裡,直到套接字連接上有數據可讀,把數據讀到 ...
  • 在ASP.NET MVC中來實現主題的切換一般有兩種方式,一種是通過切換皮膚的css和js引用,一種就是通過重寫視圖引擎。通過重寫視圖引擎的方式更加靈活,因為我不僅可以在不同主題下麵佈局和樣式不一樣,還可以讓不同的主題下麵顯示的數據條目不一致,就是說可以在某些主題下麵添加一下個性化的東西。 本篇我將 ...
  • 本文版權歸博客園和作者吳雙本人共同所有 轉載和爬蟲請註明原文地址 www.cnblogs.com/tdws 一.寫在前面 適配器模式(Adapter) 可用來在現有介面和不相容的類之間進行適配。有助於避免大規模改寫現有客戶代碼,其工作機制是對現有類的介面進行包裝,這樣客戶程式就能使用這個並非為其量身 ...
  • 寫在前面整個項目都托管在了 Github 上:https://github.com/ikesnowy/Algorithms-4th-Edition-in-Csharp這一節內容可能會用到的庫文件有 Geometry 和 Commercial,同樣在 Github 上可以找到。善用 Ctrl + F ... ...
  • 引言 Postman 是一個用來測試Web API的Chrome 外掛軟體,可由google store 免費取得並安裝於Chrome里,對於有在開發Web API的開發者相當有用,省掉不少寫測試頁面呼叫的工作,通常我們看到的使用情境多數是直接呼叫Web API而未隨著Request發送相關所需參數 ...
  • 一、Chart(Winform) 使用圖表控制項(chart)首先要理解圖表區域(ChartArea)、XY軸(AxisX、AxisY)、數據點(Series)、標題(Title)、圖例(Legend)這幾個之間的層次關係。 圖1:柱形圖 從圖1可以中內容,可以對Chart控制項的組成有了一個簡單的瞭解 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...