MVC 三層架構案例詳細講解

来源:https://www.cnblogs.com/TheMagicalRainbowSea/archive/2023/05/17/17409206.html
-Advertisement-
Play Games

MVC 三層架構案例詳細講解 @ 每博一文案 多讀書,書中有,你對生活,困難所解不開的答案 比如:《殺死一隻是更鳥》中提到的 對應我們:我們努力中考,高考,升本,考研,每天都在努力學習,但是某天突然想到萬一沒有考上的話,那現在的努力又有什麼意義呢? 答案:在《殺死一隻是更鳥》里有這樣一段話: > 勇 ...


MVC 三層架構案例詳細講解

在這裡插入圖片描述

@

目錄

每博一文案

多讀書,書中有,你對生活,困難所解不開的答案
比如:《殺死一隻是更鳥》中提到的
對應我們:我們努力中考,高考,升本,考研,每天都在努力學習,但是某天突然想到萬一沒有考上的話,那現在的努力又有什麼意義呢?
答案:在《殺死一隻是更鳥》里有這樣一段話:
> 勇敢是,當你還未開始,你就知道自己會輸,可你依然要去做,而且無論如何都要把它堅持到底,你很少能贏,但有時也會。努力的這個過程本身就是有意義,能夠獲得理想的結果當然很好,但如果失敗了也沒關係。因為你的勇敢,從未辜負你的青春,而黎明的光亮,總有一刻,會照亮穿梭於黑暗之中的自己。況且,你還不一定會輸呢。

1. MVC 概述

MVC開始是存在於桌面程式中的,M是指業務模型,V是指用戶界面,C則是控制器,使用MVC的目的是將M和V的實現代碼分離,從而使同一個程式可以使用不同的表現形式。比如一批統計數據可以分別用柱狀圖餅圖來表示。C存在的目的則是確保M和V的同步,一旦M改變,V應該同步更新。 [1-2]

模型-視圖-控制器(MVC)是[Xerox PARC](https://baike.baidu.com/item/Xerox PARC/10693263?fromModule=lemma_inlink)在二十世紀八十年代為編程語言Smalltalk-80發明的一種軟體設計模式,已被廣泛使用。後來被推薦為Oracle旗下Sun公司[Java EE](https://baike.baidu.com/item/Java EE/2180381?fromModule=lemma_inlink)平臺的設計模式,並且受到越來越多的使用ColdFusionPHP的開發者的歡迎。模型-視圖-控制器模式是一個有用的工具箱,它有很多好處,但也有一些缺點。

2. MVC設計思想

MVC(Model View Controller)是軟體工程中的一種軟體架構模式,它把軟體系統分為模型視圖控制器三個基本部分。用一種業務邏輯、數據、界面顯示分離的方法組織代碼,將業務邏輯聚集到一個部件裡面,在改進和個性化定製界面及用戶交互的同時,不需要重新編寫業務邏輯。

img

MVC 主要的核心就是:分層:希望專人乾專事,各司其職,職能分工要明確,這樣可以讓代碼耦合度降低,擴展力增強,組件的可復用性增強

MVC 從字面意思我們就可以看到:是分為了三層的,M(Mode 模型),V(View 視圖),C(Controller 控制器)

img

M即model模型:是指模型表示業務規則。在MVC的三個部件中,模型擁有最多的處理任務。被模型返回的數據是中立的,模型與數據格式無關,這樣一個模型能為多個視圖提供數據,由於應用於模型的代碼只需寫一次就可以被多個視圖重用,所以減少了代碼的重覆性

V即View視圖:是指用戶看到並與之交互的界面。比如由html元素組成的網頁界面,或者軟體的客戶端界面。MVC的好處之一在於它能為應用程式處理很多不同的視圖。在視圖中其實沒有真正的處理髮生,它只是作為一種輸出數據並允許用戶操作的方式。

C即controller控制器:是指控制器接受用戶的輸入並調用模型和視圖去完成用戶的需求,控制器本身不輸出任何東西和做任何處理。它只是接收請求並決定調用哪個模型構件去處理請求,然後再確定用哪個視圖來顯示返回的數據。

M(Model :數據/業務) V (View :視圖/展示) C (Controller : 控制層)

C(是核心,是控制器,是司令官)

M(處理業務/處理數據的一個秘書)

V(負責頁面展示的一個秘書)

MVC(一個司令官,調度兩個秘書,去做這件事),僅僅只做事務上的調度,而不做其他的操作

在這裡插入圖片描述

JavaBean

優點:

  1. 耦合性低,方便維護,可以利於分工協作
  2. 重用性高

缺點:

  1. 使得項目架構變得複雜,對開發人員要求高

3. 三層架構

三層架構(3-tier architecture) 通常意義上的三層架構就是將整個業務應用劃分為:界面層[表示層](User Interface layer)、業務邏輯層(Business Logic Layer)、數據訪問層(Data access layer)。

區分層次的目的即為了“高內聚低耦合” 的思想。在軟體體系架構設計中,分層式結構是最常見,也是最重要的一種結構。

在這裡插入圖片描述

在這裡插入圖片描述
在這裡插入圖片描述

三層架構每層之間的邏輯關係:

在這裡插入圖片描述

三層架構的優點

  1. 開發人員可以只關註整個結構中的其中某一層;
  2. 可維護性高,可擴展性高
  3. 可以降低層與層之間的依賴;
  4. 有利於標準化;
  5. 利於各層邏輯的復用

三層架構的缺點:

  1. 降低了系統的性能。如果不採用分層式結構,很多業務可以直接造訪資料庫,以此獲取相應的數據,如今卻必須通過中間層來完成
  2. 有時會導致級聯的修改,這種修改尤其體現在自上而下的方向。如果在表示層中需要增加一個功能,為保證其設計符合分層式結構,可能需要在相應的業務邏輯層和數據訪問層中都增加相應的代碼
  3. 增加了開發成本

4. MVC 與 三層架構的關係:

MVC的也可以被說成是 MVC三層架構,說白了,它們其實都是一個東西,只是在一些細節上有稍微的不同,大致設計思想都是一樣的:“高內聚,低耦合”。

在這裡插入圖片描述

其實,無論是MVC還是三層架構,都是一種規範,都是奔著"高內聚,低耦合"的思想來設計的。三層中的UI和Servlet來分別對應MVC中的View和Controller,業務邏輯層是來組合數據訪問層的原子性功能的。

5. 案例舉例:用戶賬戶轉賬

如下我們,實現一個用戶賬戶轉賬操作的一個案例:

準備工作:創建表,創建數據



CREATE DATABASE mvc;

USE mvc;

SHOW TABLES;

CREATE TABLE t_act (
   id BIGINT PRIMARY KEY AUTO_INCREMENT,
   actno VARCHAR(255) NOT NULL,
   balance DECIMAL(10,2) 
);



INSERT INTO t_act(actno,balance)
VALUES('act001',50000.00),('act002',0.00);

SELECT *
FROM t_act;

5.1 M(Model :數據/業務處理層)

javaBean :Account 封裝數據

賬戶實體類,封裝賬戶信息的

  • 一般是一張表一個。
  • pojo 對象
  • 有的人也會把這種專門封裝數據的對象,稱為:"bean對象" (javabean對象,咖啡豆)
  • 有的人也會把這種專門封裝數據的對象,稱為領域模型對象,domain對象
  • 不同的程式員不同的習慣
package com.RainbowSea.bank.mvc;

import java.io.Serializable;
import java.util.Objects;


/**
 * 賬戶實體類,封裝賬戶信息的
 * 一般是一張表一個。
 * pojo 對象
 * 有的人也會把這種專門封裝數據的對象,稱為:"bean對象" (javabean對象,咖啡豆)
 * 有的人也會把這種專門封裝數據的對象,稱為領域模型對象,domain對象
 * 不同的程式員不同的習慣。
 */
public class Account implements Serializable {  // 這種普通的簡單的對象被成為pojo對象
    // 註意我們這裡定義的數據類型,使用引用數據類型
    // 因為我們資料庫中可能存在 null 值,而基本數據類型是不可以存儲 null值的

    private Long id = null;  // id
    private String actno;  // 賬號
    private Double balance; // 餘額

    // 反序列化
    private static final long serialVersionUID = 1L;

    public Account() {
    }


    public Account(Long id, String actno, Double balance) {
        this.id = id;
        this.actno = actno;
        this.balance = balance;
    }


    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getActno() {
        return actno;
    }

    public void setActno(String actno) {
        this.actno = actno;
    }

    public Double getBalance() {
        return balance;
    }

    public void setBalance(Double balance) {
        this.balance = balance;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Account)) return false;
        Account account = (Account) o;
        return Objects.equals(getId(), account.getId()) && Objects.equals(getActno(), account.getActno()) && Objects.equals(getBalance(), account.getBalance());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getId(), getActno(), getBalance());
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", actno='" + actno + '\'' +
                ", balance=" + balance +
                '}';
    }
}

DB連接資料庫的工具:

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/mvc
user=root
password=MySQL
package com.RainbowSea.bank.utils;


import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ResourceBundle;

public class DBUtil {

    // resourceBundle 只能讀取到 properties 尾碼的文件,註意不要加文件尾碼名
    private static ResourceBundle resourceBundle = ResourceBundle.getBundle("resources/jdbc");
    private static String driver = resourceBundle.getString("driver");
    private static String url = resourceBundle.getString("url");
    private static String user = resourceBundle.getString("user");
    private static String password = resourceBundle.getString("password");


    // DBUtil 類載入註冊驅動
    static {
        try {
            Class.forName(driver);
        } catch (ClassNotFoundException e) {
           e.printStackTrace();
        }

    }


    // 將構造器私有化,不讓創建對象,因為工具類中的方法都是靜態的,不需要創建對象
    // 為了防止創建對象,故將構造方法私有化
    private DBUtil() {

    }

    /**
     * 這裡沒有使用資料庫連接池,直接創建連接對象
     */
    public static Connection getConnection()  {
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(url, user, password);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
        return  connection;
    }


    /**
     * 資源的關閉
     * 最後使用的最先關閉,逐個關閉,防止存在沒有關閉的
     */
    public static void close(Connection connection , PreparedStatement preparedStatement, ResultSet resultSet) {

        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }


        if (preparedStatement!=null) {
            try {
                preparedStatement.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }


        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

對應Account數據表的DAO操作工具類

AccountDao 是負責Account 數據的增上改查

什麼是DAO ?

  • Data Access Object (數據訪問對象)
  • DAO實際上是一種設計模式,屬於 JavaEE的設計模式之一,不是 23種設計模式
  • DAO只負責資料庫表的CRUD ,沒有任何業務邏輯在裡面
  • 沒有任何業務邏輯,只負責表中數據增上改查的對象,有一個特俗的稱謂:DAO對象

為什麼叫做 AccountDao 呢?

  • 這是因為DAO是專門處理t_act 這張表的
  • 如果處理t_act 表的話,可以叫做:UserDao
  • 如果處理t-student表的話,可以叫做 StudentDao

主要定義如下:增刪改查方法()

int insert() ;
int deleteByActno();
int update() ;
Account selectByActno();
List<Account> selectAll();
package com.RainbowSea.bank.mvc;


import com.RainbowSea.bank.utils.DBUtil;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Collection;
import java.util.List;

/**
 * AccountDao 是負責Account 數據的增上改查
 * <p>
 * 1. 什麼是DAO ?
 * Data Access Object (數據訪問對象)
 * 2. DAO實際上是一種設計模式,屬於 JavaEE的設計模式之一,不是 23種設計模式
 * 3.DAO只負責資料庫表的CRUD ,沒有任何業務邏輯在裡面
 * 4.沒有任何業務邏輯,只負責表中數據增上改查的對象,有一個特俗的稱謂:DAO對象
 * 5. 為什麼叫做 AccountDao 呢?
 * 這是因為DAO是專門處理t_act 這張表的
 * 如果處理t_act 表的話,可以叫做:UserDao
 * 如果處理t-student表的話,可以叫做 StudentDao
 * <p>
 * int insert() ;
 * int deleteByActno();
 * int update() ;
 * Account selectByActno();
 * List<Account> selectAll();
 */
public class AccountDao {


    /**
     * 插入數據
     *
     * @param account
     * @return
     */
    public int insert(Account account) {
        Connection connection = DBUtil.getConnection();
        PreparedStatement preparedStatement = null;
        int count = 0;
        try {
            String sql = "insert into t_act(actno,balance) values(?,?)";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, account.getActno());
            preparedStatement.setDouble(2, account.getBalance());
            count = preparedStatement.executeUpdate();


        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }


        return count;

    }


    /**
     * 通過Id刪除數據
     *
     * @param id
     * @return
     */
    public int deleteById(String id) {
        Connection connection = DBUtil.getConnection();
        int count = 0;
        PreparedStatement preparedStatement = null;
        try {
            String sql = "delete from t_act where id = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, id);
            count = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }

        return count;

    }


    /**
     * 更新數據
     *
     * @param account
     * @return
     */
    public int update(Account account) {
        Connection connection = DBUtil.getConnection();
        PreparedStatement preparedStatement = null;
        int count = 0;

        try {
            String sql = "update t_act set balance = ?, actno = ? where id = ?";
            preparedStatement = connection.prepareStatement(sql);

            //註意設置的 set類型要保持一致。
            preparedStatement.setDouble(1, account.getBalance());
            preparedStatement.setString(2, account.getActno());
            preparedStatement.setLong(3, account.getId());

            count = preparedStatement.executeUpdate();
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, preparedStatement, null);
        }

        return count;
    }


    /**
     * 通過 actno 查找賬戶信息
     *
     * @param actno
     * @return
     */
    public Account selectByActno(String actno) {
        Connection connection = DBUtil.getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        Account account = new Account();

        try {
            String sql = "select id,actno,balance from t_act where actno = ?";
            preparedStatement = connection.prepareStatement(sql);

            //註意設置的 set類型要保持一致。
            preparedStatement.setString(1, actno);

           resultSet = preparedStatement.executeQuery();

            if (resultSet.next()) {
                Long id = resultSet.getLong("id");
                Double balance = resultSet.getDouble("balance");
                // 將結果集封裝到java 對象中
                account.setActno(actno);
                account.setId(id);
                account.setBalance(balance);

            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, preparedStatement, resultSet);
        }

        return account;
    }


    /**
     * 查詢所有的賬戶信息
     *
     * @return
     */
    public List<Account> selectAll() {
        Connection connection = DBUtil.getConnection();
        PreparedStatement preparedStatement = null;
        ResultSet resultSet = null;
        List<Account> list = null;

        try {
            String sql = "select id,actno,balance from t_act";
            preparedStatement = connection.prepareStatement(sql);

            resultSet = preparedStatement.executeQuery();

            while (resultSet.next()) {
                String actno = resultSet.getString("actno");
                Long id = resultSet.getLong("id");
                Double balance = resultSet.getDouble("balance");
                // 將結果集封裝到java 對象中
                Account account = new Account(id,actno,balance);

                // 添加到List集合當中
                list.add(account);

            }

        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            DBUtil.close(connection, preparedStatement, resultSet);
        }

        return list;
    }


}

對指定的數據表的數據進行service 業務邏輯處理操作:

service 翻譯為:業務。

  • AccountService 專門處理Account業務的一個類
  • 在該類中應該編寫純業務代碼。(只專註域業務處理,不寫別的,不和其他代碼混合在一塊)
  • 只希望專註業務,能夠將業務完美實現,少量bug.
  • 業務類一般起名:XXXService,XXXBiz...
package com.RainbowSea.bank.mvc;


/**
 * service 翻譯為:業務。
 * AccountService 專門處理Account業務的一個類
 * 在該類中應該編寫純業務代碼。(只專註域業務處理,不寫別的,不和其他代碼混合在一塊)
 * 只希望專註業務,能夠將業務完美實現,少量bug.
 * <p>
 * 業務類一般起名:XXXService,XXXBiz...
 */
public class AccountService {

    // 這裡的方法起名,一定要體現出,你要處理的是什麼業務:
    // 我們要提供一個能夠實現轉賬的業務的方法(一個業務對應一個方法)
    // 比如:UserService StudentService OrderService

    // 處理Account 轉賬業務的增刪改查的Dao
    private AccountDao accountDao = new AccountDao();

    /**
     * 完成轉賬的業務邏輯
     *
     * @param fromActno 轉出賬號
     * @param toActno   轉入賬號
     * @param money     轉賬金額
     */
    public void transfer(String fromActno, String toActno, double money) throws MoneyNotEnoughException, AppException {
        // 查詢餘額是否充足
        Account fromAct = accountDao.selectByActno(fromActno);
        if (fromAct.getBalance() < money) {
            throw new MoneyNotEnoughException("對不起,餘額不足");
        }

        // 程式到這裡說明餘額充足
        Account toAct = accountDao.selectByActno(toActno);

        // 修改金額,先從記憶體上修改,再從硬碟上修改
        fromAct.setBalance(fromAct.getBalance() - money);
        toAct.setBalance(toAct.getBalance() + money);


        // 從硬碟資料庫上修改
        int count = accountDao.update(fromAct);
        count += accountDao.update(toAct);

        if(count != 2) {
            throw new AppException("賬戶轉賬異常,請聯繫管理員");
        }

    }
}

異常處理類:

package com.RainbowSea.bank.mvc;


/**
 * 餘額不足異常
 */
public class AppException extends Exception{

        public AppException() {

        }

        public AppException(String msg) {
            super(msg);
        }

}

package com.RainbowSea.bank.mvc;


/**
 * 餘額不足異常
 */
public class MoneyNotEnoughException extends Exception{
    public MoneyNotEnoughException() {

    }

    public MoneyNotEnoughException(String msg) {
        super(msg);
    }
}

5.2 C (Controller : 控制層)

僅僅負責調度 M業務處理層,V視圖顯示層,而不做其他操作。

package com.RainbowSea.bank.mvc;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.io.IOException;


/**
 * 賬戶小程式
 * AccountServlet 是一個司令官,他負責調度其他組件來完成任務。
 *
 */
@WebServlet("/transfer")
public class AccountServlet extends HttpServlet { // AccountServlet 作為一個 Controller 司令官

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException,
            IOException {

        // 獲取數據
        String fromActno = request.getParameter("fromActno");
        String toActno = request.getParameter("toActno");
        double money = Double.parseDouble(request.getParameter("money"));

        // 調用業務方法處理業務(調度Model處理業務,其中是對應數據表的 CRUD操作)
        AccountService accountService = new AccountService();
        try {
            accountService.transfer(fromActno,toActno,money);
            // 執行到這裡說明,成功了,
            // 展示處理結束(調度 View 做頁面展示)

            response.sendRedirect(request.getContextPath()+"/success.jsp");
        } catch (MoneyNotEnoughException e) {
            // 執行到種類,說明失敗了,(餘額不足
            // 展示處理結束(調度 View 做頁面展示)
            response.sendRedirect(request.getContextPath()+"/error.jsp");

        } catch (AppException e) {
            // 執行到種類,說明失敗了,轉賬異常
            // 展示處理結束(調度 View 做頁面展示)
            response.sendRedirect(request.getContextPath()+"/error.jsp");

        }

        // 頁面的展示 (調度View做頁面展示)


    }
}

5.3 V (View :視圖/展示)

index.jsp 轉賬頁面:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
  <title>銀行賬號轉賬</title>
</head>
<body>
<form action="<%=request.getContextPath()%>/transfer" method="post">
  轉出賬戶: <input type="text" name="fromActno" /> <br>
  轉入賬戶: <input type="text" name="toActno" /> <br>
  轉賬金額: <input type="text" name="money" /><br>
  <input type="submit" value="轉賬" />
</form>
</body>
</html>

success轉賬成功的頁面顯示:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>轉賬成功</title>
</head>
<body>

<h3>轉賬成功</h3>
</body>
</html>

error 轉賬失敗的頁面顯示:


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>轉賬失敗</title>
</head>
<body>
<h3>轉賬失敗</h3>
</body>
</html>

在這裡插入圖片描述

雖然上述:代碼成功實現的了用戶轉賬的操作,但是並沒有進行事務的處理。

如下是運用 TreadLocal 進行事務的處理:

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

-Advertisement-
Play Games
更多相關文章
  • 學過 Java、C# 或者其他托管語言(managed languages)的同學,回過頭來看 C++ 的時候,第一反應就是 C++ 沒有自動垃圾回收器(GC),而不能充分利用的資源被稱為垃圾。 ...
  • Consul 是微服務網路解決方案之一, 用於管理跨網路和多雲環境服務之間的安全網路連接, 提供服務發現, 服務網格, 流量管理和自動更新. 可以單獨部署, 也可以分散式部署. Consul 內建安全通信選項, 使用 Go 語言編寫, 啟動資源消耗小, 腳本化配置, 對容器部署方式更友好 ...
  • AZ-1的第二次博客作業 AZ-1 - 博客園 (cnblogs.com) 前言 題量 題目集4題量較小。 題目集5題量較小。 期中考試題量中等。 難度 題目集4雖然只有一道題,但是題目很長,難度很大,讓人在看到的時就心生畏懼。菜單4在菜單3的基礎上增加了大量的錯誤輸入,大大增加了程式的代碼量,很考 ...
  • 5 註冊-控制層 5.1 創建響應 狀態碼、狀態碼描述信息、數據。這部分功能封裝到一個類中,將這類作為方法返回值,返回給前端瀏覽器。 package com.cy.store.util; import java.io.Serializable; /** * Json格式的數據進行響應 */ publ ...
  • ThreadLocal 的原理講述 + 基於ThreadLocal實現MVC中的M層的事務控制 每博一文案 生活不是努力了就可以變好的,喜歡做的事情也不是輕易就可以做的。以前總聽別人說, 堅持就好了,努力就好了,都會好的,可是真的做起來壓根就不是這樣。這種時候要怎麼辦? 這種時候還能輕易地相信時間嗎 ...
  • Java的產生和發展 產生與發展歷程 1991年,由Sun公司開發Oak,最初為家用消費電子產品進行編程,是Java前身。 1994年,使用Oak語言編寫了Web瀏覽器 1995年,改名為Java,96年發佈JDK1.1 … 1998年,發佈JDK1.2,從語言發展為平臺 … 2004年,發佈JDK ...
  • 列印輸出的Java對象是一知半解的字元串,那麼這個字元串是怎麼來的?代表什麼?我們如何列印出對象中的數據呢? ...
  • set(可變集合)與frozenset(不可變集合)的區別: set無序排序且不重覆,是可變的,有add(),remove()等方法。既然是可變的,所以它不存在哈希值。基本功能包括關係測試和消除重覆元素. 集合對象還支持union(聯合), intersection(交集), difference( ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...