Java(單元測試,反射)

来源:https://www.cnblogs.com/yaomagician/archive/2023/03/13/17212536.html
-Advertisement-
Play Games

單元測試、反射 一、單元測試 1.1 單元測試快速入門 所謂單元測試,就是針對最小的功能單元,編寫測試代碼對其進行正確性測試。 我們想想,咱們之前是怎麼進行測試的呢? 比如說我們寫了一個學生管理系統,有添加學生、修改學生、刪除學生、查詢學生等這些功能。要對這些功能這幾個功能進行測試,我們是在main ...


單元測試、反射

一、單元測試

1.1 單元測試快速入門

所謂單元測試,就是針對最小的功能單元,編寫測試代碼對其進行正確性測試。

我們想想,咱們之前是怎麼進行測試的呢?

比如說我們寫了一個學生管理系統,有添加學生、修改學生、刪除學生、查詢學生等這些功能。要對這些功能這幾個功能進行測試,我們是在main方法中編寫代碼來測試的。

但是在main方法中寫測試代碼有如下的幾個問題,如下圖所示:

 

 

 

為了測試更加方便,有一些第三方的公司或者組織提供了很好用的測試框架,給開發者使用。這裡給同學們介紹一種Junit測試框架。

Junit是第三方公司開源出來的,用於對代碼進行單元測試的工具(IDEA已經集成了junit框架)。相比於在main方法中測試有如下幾個優點。

 

 

 


我們知道單元測試是什麼之後,接下來帶領同學們使用一下。由於Junit是第三方提供的,所以我們需要把jar包導入到我們的項目中,才能使用,具體步驟如下圖所示:

 

 

 

接下來,我們就按照上面的步驟,來使用一下.

先準備一個類,假設寫了一個StringUtil工具類,代碼如下

public class StringUtil{
    public static void printNumber(String name){
        System.out.println("名字長度:"+name.length());
    }
}

 

接下來,寫一個測試類,測試StringUtil工具類中的方法能否正常使用。

public class StringUtilTest{
    @Test
    public void testPrintNumber(){
        StringUtil.printNumber("admin");
        StringUtil.printNumber(null);
    }
}

 

寫完代碼之後,我們會發現測試方法左邊,會有一個綠色的三角形按鈕。點擊這個按鈕,就可以運行測試方法。

 

 

 

1.2 單元測試斷言

接下來,我們學習一個單元測試的斷言機制。所謂斷言:意思是程式員可以預測程式的運行結果,檢查程式的運行結果是否與預期一致。

我們在StringUtil類中新增一個測試方法

 public static int getMaxIndex(String data){
     if(data == null){
         return -1;
     }
     return data.length();
 }

 

接下來,我們在StringUtilTest類中寫一個測試方法

public class StringUtilTest{
    @Test
    public void testGetMaxIndex(){
       int index1 = StringUtil.getMaxIndex(null);
       System.out.println(index1);
        
       int index2 = StringUtil.getMaxIndex("admin");
       System.out.println(index2);
        
        //斷言機制:預測index2的結果
        Assert.assertEquals("方法內部有Bug",4,index2);
    }
}

 

運行測試方法,結果如下圖所示,表示我們預期值與實際值不一致

 

 

 

1.3 Junit框架的常用註解

同學們,剛纔我們以及學習了@Test註解,可以用來標記一個方法為測試方法,測試才能啟動執行。

除了@Test註解,還有一些其他的註解,我們要知道其他註解標記的方法什麼時候執行,以及其他註解在什麼場景下可以使用。

 

 

 

接下來,我們演示一下其他註解的使用。我們在StringUtilTest測試類中,再新增幾個測試方法。代碼如下

public class StringUtilTest{
    @Before
    public void test1(){
        System.out.println("--> test1 Before 執行了");
    }
    @BeforeClass
    public static void test11(){
        System.out.println("--> test11 BeforeClass 執行了");
    }
    @After
    public void test2(){
        System.out.println("--> test2 After 執行了");
    }
    @AfterClass
    public static void test22(){
        System.out.println("--> test22 AfterCalss 執行了");
    }
}

 

執行上面的測試類,結果如下圖所示,觀察執行結果特點如下

1.@BeforeClass標記的方法,執行在所有方法之前
2.@AfterCalss標記的方法,執行在所有方法之後
3.@Before標記的方法,執行在每一個@Test方法之前
4.@After標記的方法,執行在每一個@Test方法之後

 

 

 

我們現在已經知道每一個註解的作用了,那他們有什麼用呢?應用場景在哪裡?

我們來看一個例子,假設我想在每個測試方法中使用Socket對象,並且用完之後,需要把Socket關閉。代碼就可以按照下麵的結構來設計

public class StringUtilTest{
    private static Socket socket;
    @Before
    public void test1(){
        System.out.println("--> test1 Before 執行了");
    }
    @BeforeClass
    public static void test11(){
        System.out.println("--> test11 BeforeClass 執行了");
        //初始化Socket對象
        socket = new Socket();
    }
    @After
    public void test2(){
        System.out.println("--> test2 After 執行了");
    }
    @AfterCalss
    public static void test22(){
        System.out.println("--> test22 AfterCalss 執行了");
         //關閉Socket
        socket.close();
    }
}

 

 

二、反射

 

什麼是反射。其實API文檔中對反射有詳細的說明,我們去瞭解一下。在java.lang.reflect包中對反射的解釋如下圖所示

 

 

 

翻譯成人話就是:反射技術,指的是載入類的位元組碼到記憶體,並以編程的方法解刨出類中的各個成分(成員變數、方法、構造器等)。

反射有啥用呢?其實反射是用來寫框架用的,但是現階段同學們對框架還沒有太多感覺。為了方便理解,我給同學們看一個我們見過的例子:平時我們用IDEA開發程式時,用對象調用方法,IDEA會有代碼提示,idea會將這個對象能調用的方法都給你列舉出來,供你選擇,如果下圖所示

 

 

 

問題是IDEA怎麼知道這個對象有這些方法可以調用呢? 原因是對象能調用的方法全都來自於類,IDEA通過反射技術就可以獲取到類中有哪些方法,並且把方法的名稱以提示框的形式顯示出來,所以你能看到這些提示了。

 

為反射獲取的是類的信息,那麼反射的第一步首先獲取到類才行。由於Java的設計原則是萬物皆對象,獲取到的類其實也是以對象的形式體現的,叫位元組碼對象,用Class類來表示。獲取到位元組碼對象之後,再通過位元組碼對象就可以獲取到類的組成成分了,這些組成成分其實也是對象,其中每一個成員變數用Field類的對象來表示每一個成員方法用Method類的對象來表示每一個構造器用Constructor類的對象來表示

如下圖所示:

 

 

 

1.1 獲取類的位元組碼

反射的第一步:是將位元組碼載入到記憶體,我們需要獲取到的位元組碼對象。

 

 

 

 

比如有一個Student類,獲取Student類的位元組碼代碼有三種寫法。不管用哪一種方式,獲取到的位元組碼對象其實是同一個。

public class Test01_Class {
​
    public static void main(String[] args) throws ClassNotFoundException {
        /*
          位元組碼文件對象獲取三種方式
         */
        //1:根據類名.class
        Class c1 = Student.class;
        System.out.println(c1);
        System.out.println(c1.getName());// 獲取全類名  包名+類名
        System.out.println(c1.getSimpleName());// 獲取簡單類名
//2:根據類的全路徑 (包名+類名)獲取
        Class c2 = Class.forName("com.itheima.d2_reflect.Student");
        // c1 c2 是不是一個對象? 類只載入一次!!
        System.out.println(c1==c2);
​
        //3:得到對象之後,通過對象的方法獲取 運行時類
        Student stu = new Student();
        Class c3= stu.getClass();
        System.out.println(c1==c3);
    }
}
​

 

 

1.2 獲取類的構造器

同學們,上一節我們已經可以獲取到類的位元組碼對象了。接下來,我們學習一下通過位元組碼對象獲取構造器,並使用構造器創建對象。

獲取構造器,需要用到Class類提供的幾個方法,如下圖所示:

 

 

 

想要快速記住這個方法的區別,給同學們說一下這些方法的命名規律,按照規律來記就很方便了。

get:獲取
Declared: 有這個單詞表示可以獲取任意一個,沒有這個單詞表示只能獲取一個public修飾的
Constructor: 構造方法的意思
尾碼s: 表示可以獲取多個,沒有尾碼s只能獲取一個

話不多少,上代碼。假設現在有一個Cat類,裡面有幾個構造方法,代碼如下

public class Cat{
    private String name;
    private int age;
    
    public Cat(){
        
    }
    
    private Cat(String name, int age){
        
    }
}

 

    1. 接下來,我們寫一個測試方法,來測試獲取類中所有的構造器

       

  @Test
    public void testGetConstructors(){
        // 反射第一步 獲取位元組碼對象
        Class c= Cat.class;
​
        // 獲取 所有的 public 修飾的 構造器
//        Constructor[] constructors = c.getConstructors();
//        System.out.println(constructors.length);
//        for (Constructor constructor : constructors) {
//            System.out.println("構造器全稱:"+constructor);
//            System.out.println("構造器名稱:"+constructor.getName());//獲取構造器的名字
//            System.out.println("參數個數:"+constructor.getParameterCount());
//        }
        // 獲取 所有存在的 構造器 (無所謂修飾符)
        Constructor[] constructors = c.getDeclaredConstructors();
        System.out.println("總共:"+constructors.length+"個構造器");
        for (Constructor constructor : constructors) {
            System.out.println("構造器全稱:"+constructor);
            System.out.println("構造器名稱:"+constructor.getName());//獲取構造器的名字
            System.out.println("參數個數:"+constructor.getParameterCount());
            System.out.println("==============================");
        }
​
    }

 

運行測試方法列印結果如下

 

 

 

    1. 剛纔演示的是獲取Cat類中所有的構造器,接下來,我們演示單個構造器試一試

//獲取指定的構造器
    @Test
    public void testContructor() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        // 獲取構造器(方法 )  是不需要指定名字的 因為構造方法名字是類名!!!
//第一步 獲取 位元組碼對象
        Class c = Cat.class;
        //獲取 無參這個構造器  public
        Constructor constructor1 = c.getConstructor();
        //列印構造器 相關信息
        System.out.println("構造器全稱:"+constructor1);
        System.out.println("構造器名稱:"+constructor1.getName());//獲取構造器的名字
        System.out.println("參數個數:"+constructor1.getParameterCount());
​
        Cat cat1 = (Cat)constructor1.newInstance();
        System.out.println("查看對象:"+cat1);
        System.out.println("==============================");
        // String類型?String.class
//獲取兩個參數的構造器   忽略修飾符
        Constructor constructor2 = c.getDeclaredConstructor(String.class, int.class);
        //() 參數的順序和類型來匹配指定的構造器
        System.out.println("構造器全稱:"+constructor2);
        System.out.println("構造器名稱:"+constructor2.getName());//獲取構造器的名字
        System.out.println("參數個數:"+constructor2.getParameterCount());
        //針對私有的成員 需要繞過許可權訪問
       constructor2.setAccessible(true);
       Cat cat2 =(Cat)constructor2.newInstance("小花",3);//參數 倆 第一個參數String,第二個是int
        System.out.println(cat2);
    }

 

列印結果如下

 

 

 

 

1.3 反射獲取構造器的作用

同學們,剛纔上一節我們已經獲取到了Cat類中的構造器。獲取到構造器後,有什麼作用呢?

其實構造器的作用:初始化對象並返回

這裡我們需要用到如下的兩個方法,註意:這兩個方法時屬於Constructor的,需要用Constructor對象來調用。

 

 

 

如下圖所示,constructor1和constructor2分別表示Cat類中的兩個構造器。現在我要把這兩個構造器執行起來

 

 

 

由於構造器是private修飾的,先需要調用setAccessible(true) 表示禁止檢查訪問控制,然後再調用newInstance(實參列表) 就可以執行構造器,完成對象的初始化了。

代碼如下:為了看到構造器真的執行, 故意在兩個構造器中分別加了兩個列印語句

 

 

 

代碼的執行結果如下圖所示:

 

 

 

 

1.4 反射獲取成員變數&使用

同學們,上一節我們已經學習了獲取類的構造方法並使用。接下來,我們再學習獲取類的成員變數,並使用。

其實套路是一樣的,在Class類中提供了獲取成員變數的方法,如下圖所示。

 

 

 

這些方法的記憶規則,如下

get:獲取
Declared: 有這個單詞表示可以獲取任意一個,沒有這個單詞表示只能獲取一個public修飾的
Field: 成員變數的意思
尾碼s: 表示可以獲取多個,沒有尾碼s只能獲取一個
  • 假設有一個Cat類它有若幹個成員變數,用Class類提供 的方法將成員變數的對象獲取出來。

 

 

 

執行完上面的代碼之後,我們可以看到控制臺上列印輸出了,每一個成員變數的名稱和它的類型。

 

 

 

 
public class Test03_Field {
​
    @Test
    public void getFields() throws NoSuchFieldException, IllegalAccessException {
       //獲取所有的屬性
       // 1:獲取位元組碼對象
       Class c = Cat.class;
       //2:獲取所有的成員屬性
        Field[] fields = c.getDeclaredFields();
        //3:遍歷得到每個成員屬性的 對象形式
        for (Field field : fields) {
            System.out.println("全稱:"+field+" 查小名:"+field.getName()+" 屬性的類型:"+field.getType());
        }
        System.out.println("=========================");
        // 需求 對某個對象的某個屬性完成 賦值  取值
        Cat cat = new Cat();
        //   給cat對象的 name 屬性 賦值  "加菲貓"
        //   給cat對象的 age 屬性 賦值  3
        //  通過反射方式 找到指定的屬性對象
        Field fName = c.getDeclaredField("name");
        Field fAge= c.getDeclaredField("age");
​
        // 只要是在反射形式調用 可以繞過許可權檢查
        fName.setAccessible(true);
        fAge.setAccessible(true);
        // 完成 賦值
//        fName  fAge  屬性的對象形式
         fName.set(cat,"加菲貓");
         fAge.set(cat,3);
​
        System.out.println(cat);
        // 獲取到 指定對象的指定屬性的值?  cat.getName() cat.name
        //屬性對象反向調用
        String name = (String) fName.get(cat);//cat.name
        System.out.println(name);
    }
}
​

 

 

 

  • 獲取到成員變數的對象之後該如何使用呢?

在Filed類中提供給給成員變數賦值和獲取值的方法,如下圖所示。

 

 

 

再次強調一下設置值、獲取值的方法時Filed類的需要用Filed類的對象來調用,而且不管是設置值、還是獲取值,都需要依賴於該變數所屬的對象。代碼如下

 

 

 

執行代碼,控制台會有如下的列印

 

 

 

 

1.5 反射獲取成員方法

各位同學,上面幾節我們已經學習了反射獲取構造方法、反射獲取成員變數,還剩下最後一個就是反射獲取成員方法並使用了。

在Java中反射包中,每一個成員方法用Method對象來表示,通過Class類提供的方法可以獲取類中的成員方法對象。如下下圖所示

 

 

 

接下來我們還是用代碼演示一下:假設有一個Cat類,在Cat類中紅有若幹個成員方法

public class Cat{
    private String name;
    private int age;
    
    public Cat(){
        System.out.println("空參數構造方法執行了");
    }
    
    private Cat(String name, int age){
        System.out.println("有參數構造方法執行了");
        this.name=name;
        this.age=age;
    }
    
    private void run(){
        System.out.println("(>^ω^<)喵跑得賊快~~");
    }
    
    public void eat(){
        System.out.println("(>^ω^<)喵愛吃貓糧~");
    }
    
    private String eat(String name){
        return "(>^ω^<)喵愛吃:"+name;
    }
    
    public void setName(String name){
        this.name=name;
    }
    public String getName(){
        return name;
    }
    public void setAge(int age){
        this.age=age;
    }
     public int getAge(){
        return age;
    }
}

 

接下來,通過反射獲取Cat類中所有的成員方法,每一個成員方法都是一個Method對象

package com.itheima.d2_reflect;
​
import org.junit.Test;
​
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
​
public class Test04_Method {
​
    @Test
    public void testGetMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1:獲取位元組碼對象
        Class c = Cat.class;
       //2:獲取所有的方法
        Method[] methods = c.getDeclaredMethods();
        //3:遍歷
        for (Method method : methods) {
            System.out.println("全稱:"+method+" 簡稱:"+method.getName()+" 返回值類型:"+method.getReturnType()
                    +" 參數個數:"+method.getParameterCount());
        }
        System.out.println("==============");
       //獲取指定的方法
        // run
        Method run = c.getDeclaredMethod("run");//  因為類中 是這麼區分方法的 方法名和參數列表
        System.out.println(" 簡稱:"+run.getName()+" 返回值類型:"+run.getReturnType()
                +" 參數個數:"+run.getParameterCount());
​
​
        Method eat = c.getDeclaredMethod("eat",String.class);//  因為類中 是這麼區分方法的 方法名和參數列表
        System.out.println(" 簡稱:"+eat.getName()+" 返回值類型:"+eat.getReturnType()
                +" 參數個數:"+eat.getParameterCount());
    }
}

 


執行上面的代碼,運行結果如下圖所示:列印輸出每一個成員方法的名稱、參數格式、返回值類型

 

 

 

也能獲取單個指定的成員方法,如下圖所示

 

 

 


獲取到成員方法之後,有什麼作用呢?

在Method類中提供了方法,可以將方法自己執行起來。

 

 

 

下麵我們演示一下,把run()方法和eat(String name)方法執行起來。看分割線之下的代碼

package com.itheima.d2_reflect;
​
import org.junit.Test;
​
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
​

public class Test04_Method {
​
    @Test
    public void testGetMethod() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        //1:獲取位元組碼對象
        Class c = Cat.class;
       //2:獲取所有的方法
        Method[] methods = c.getDeclaredMethods();
        //3:遍歷
        for (Method method : methods) {
            System.out.println("全稱:"+method+" 簡稱:"+method.getName()+" 返回值類型:"+method.getReturnType()
                    +" 參數個數:"+method.getParameterCount());
        }
        System.out.println("==============");
       //獲取指定的方法
        // run
        Method run = c.getDeclaredMethod("run");//  因為類中 是這麼區分方法的 方法名和參數列表
        System.out.println(" 簡稱:"+run.getName()+" 返回值類型:"+run.getReturnType()
                +" 參數個數:"+run.getParameterCount());
​
​
        Method eat = c.getDeclaredMethod("eat",String.class);//  因為類中 是這麼區分方法的 方法名和參數列表
        System.out.println(" 簡稱:"+eat.getName()+" 返回值類型:"+eat.getReturnType()
                +" 參數個數:"+eat.getParameterCount());
​
        Cat cat = new Cat();
        // 方法對象是主體  由方法對象完成調用
//        run.invoke(cat,實際參數);
        run.setAccessible(true); //繞過許可權檢查
        Object returnValue1 = run.invoke(cat);//run方法執行
                              // run方法被 cat 對象調用執行
        System.out.println("run方法調用之後的返回值:"+returnValue1);
        eat.setAccessible(true);
        Object returnValue2 = eat.invoke(cat,"魚兒");//eat方法執行
        System.out.println("eat方法調用之後的返回值:"+returnValue2);
    }
}
​

 

列印結果如下圖所示:run()方法執行後列印貓跑得賊快~~,返回null; eat()方法執行完,直接返回貓最愛吃:魚兒

 

 

 

 

1.6 反射的應用

各位小伙伴,按照前面我們學習反射的套路,我們已經充分認識了什麼是反射,以及反射的核心作用是用來獲取類的各個組成部分並執行他們。但是由於同學們的經驗有限,對於反射的具體應用場景還是很難感受到的(這個目前沒有太好的辦法,只能慢慢積累,等經驗積累到一定程度,就會豁然開朗了)。

我們一直說反射使用來寫框架的,接下來,我們就寫一個簡易的框架,簡單窺探一下反射的應用。反射其實是非常強大的,這個案例也僅僅值小試牛刀。

 

 

需求是讓我們寫一個框架,能夠將任意一個對象的屬性名和屬性值寫到文件中去。不管這個對象有多少個屬性,也不管這個對象的屬性名是否相同。

分析一下該怎麼做

1.先寫好兩個類,一個Student類和Teacher類
2.寫一個ObjectFrame類代表框本架
在ObjectFrame類中定義一個saveObject(Object obj)方法,用於將任意對象存到文件中去
參數:Object obj: 就表示要存入文件中的對象

3.編寫方法內部的代碼,往文件中存儲對象的屬性名和屬性值
1)參數obj對象中有哪些屬性,屬性名是什麼實現值是什麼,中有對象自己最清楚。
2)接著就通過反射獲取類的成員變數信息了(變數名、變數值)
3)把變數名和變數值寫到文件中去

寫一個ObjectFrame表示自己設計的框架,代碼如下圖所示

 
public class ObjectFrame {
​
    /**
     * 告訴對象  我幫你解剖
     *      屬性 屬性值解析出來 並寫到指定文件中。
     *      1: 根據傳遞的對象 即系 屬性名 和屬性值
     *      2: 通過流的形式把內容寫到文件中
     *   方法三要素:  方法名 參數列表  返回值類型
     */
    public static void saveTxt(Object obj) throws IllegalAccessException, FileNotFoundException {
        //已知條件 obj對象
        PrintStream ps = new PrintStream(	   

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

-Advertisement-
Play Games
更多相關文章
  • 軟體設計開發某種意義上是“取”與“舍”的藝術。 關於性能方面,就像建築設計成抗震9度需要額外的成本一樣,高性能軟體系統也意味著更高的實現成本,有時候與其他質量屬性甚至會衝突,比如安全性、可擴展性、可觀測性等等。 大部分時候我們需要的是:在業務遇到瓶頸之前,利用常見的技術手段將系統優化到預期水平。 ...
  • Spring:現代Java開發的必備框架 Spring是一個輕量級的Java框架,它提供了各種企業級應用程式開發的工具和技術。Spring框架的核心是IoC容器和AOP框架。IoC容器使得Java應用程式的組件化變得更加容易,AOP框架使得Java應用程式的切麵編程變得更加容易。Spring框架還提 ...
  • 1、當使用生成介面 生成全局模型時, 生成的validate文件的namespace錯誤 應為 namespace app\common\validate;實際為 namespace app\api\validate;解決方法:1、找到 application/admin/library/buiap ...
  • 容器功能 1.Spring註入組件的註解 Spring中的傳統註解@Component、@Controller、@Service、@Repository,在SpringBoot中仍然有效。 2.@Configuration @Configuration是 Spring 3.0 添加的一個註解,用來代 ...
  • 我是3y,一年CRUD經驗用十年的markdown程式員👨🏻‍💻常年被譽為職業八股文選手 開源項目消息推送平臺austin倉庫地址: 消息推送平臺🔥推送下發【郵件】【簡訊】【微信服務號】【微信小程式】【企業微信】【釘釘】等消息類型。 https://gitee.com/zhongfuchen ...
  • 搞懂無鎖編程的重要一步是完全理解記憶體順序! 本教程由作者和ChatGPT通力合作完成。 都有哪幾種? c++的記憶體模型共有6種 memory_order_relaxed memory_order_consume memory_order_acquire memory_order_release me ...
  • 首先理解常亮表達式。常量表達式是指值不會改變,並且在編譯過程就能計算得到結果。 const修飾的對象無法修改,constexpr對象在編譯期間就確定且無法修改。 constexpr變數,編譯器在編譯階段驗證變數是否為一個常量表達式。 constexpr側重變數初值編譯階段確定,且無法修改。如果認定變 ...
  • 處理GB/T4754—2017國民經濟行業分類與代碼數據,劃分四級分類存入mysql資料庫【文末獲取下載方式】 第二張圖是之前的格式,今天應一位網友的要求,將其處理為如下第三張圖的格式。更貼近源文檔,方便使用。 如圖所示: 按 門類編碼 門類名稱 大類編碼 大類名稱 中類編碼 中類名稱 小類編碼 小 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...