Spring、SpringMVC、SpringData + JPA 整合詳解

来源:http://www.cnblogs.com/crawl/archive/2017/11/01/7759874.html
-Advertisement-
Play Games

對 Spring,SpringMVC,SpringData 和 JPA 進行了詳細的整合說明,並實現了一個常見的分頁操作。 ...


 原創播客,如需轉載請註明出處。原文地址:http://www.cnblogs.com/crawl/p/7759874.html 

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

筆記中提供了大量的代碼示例,需要說明的是,大部分代碼示例都是本人所敲代碼併進行測試,不足之處,請大家指正~

本博客中所有言論僅代表博主本人觀點,若有疑惑或者需要本系列分享中的資料工具,敬請聯繫 [email protected]

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

前言:之前詳細講解過了 JPA 和 SpringData,包括 Spring 和 SpringMVC 也進行了詳細的講述。很早就想來一個整合了,因為事情比較多,所以就一直拖著。

那麼現在就來說說 Spring + SpringMVC + SpringData + JPA(下文中簡寫為 SSSP) 的整合,SSSP 的整合之後再來寫一個  CRUD 的小案例,LZ 不打算把增刪改查都來一遍了,只介紹一個查詢所有員工信息,然後分頁顯示即可。大家可以對比在 JavaWeb 的過程中寫的分頁查詢,看一看是否簡單的許多。下麵進行詳細的介紹~

一、加入 Spring

1. 首先當然要新建一個動態的 WEB 的工程了,取名 sssp

2. 加入 Spring 的 jar 包,觀察這些 jar 包,大家可以發現其中既包含了 Spring 的 jar 包,也包含了 SpringMVC 的 jar 包

3. web.xml 中配置啟動 Spring IOC 的 ContextLoaderListener

1 <!-- 配置啟動 Spring IOC 的 Listener -->
2     <context-param>
3         <param-name>contextConfigLocation</param-name>
4         <param-value>classpath:applicationContext.xml</param-value>
5     </context-param>
6 
7     <listener>
8         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
9     </listener>

其中 LZ 配置的 Spring 的配置文件在 classpath 下,取名為 applicationContext.xml 

4. 這一步當然就是在類路徑下創建 Spring 的配置文件:applicationContext.xml 了,在這裡先創建好,稍後進行配置。

二、加入 SpringMVC

1. 首先呢肯定要想到的是先導入 jar 包,這裡在加入 Spring 的時候已經導入,前面也已經做了說明。

2. web.xml 中配置 SpringMVC 的 DispatcherServlet

 1 <!-- 配置 SpringMVC 的 DispatcherServlet -->
 2     <!-- 使用預設的 SpringMVC 的配置文件,為 [servlet-name]-servlet.xml 放到 WEB-INF 目錄下 -->
 3     <servlet>
 4         <servlet-name>springDispatcherServlet</servlet-name>
 5         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
 6         <load-on-startup>1</load-on-startup>
 7     </servlet>
 8 
 9     <servlet-mapping>
10         <servlet-name>springDispatcherServlet</servlet-name>
11         <url-pattern>/</url-pattern>
12     </servlet-mapping>

在這裡呢 LZ 刪除了一部分配置,我們使用預設的 SpringMVC 的配置文件,這個預設的 SpringMVC 的配置文件的名字為 :springDispatcherServlet-servlet.xml ,需要註意的是,若使用預設的配置文件,文件的位置需要在 WEB-INF 目錄下

3. 在 WEB-INF 目錄下新建 SpringMVC 的配置文件: springDispatcherServlet-servlet.xml (註意:LZ 的 Eclipse 中是安裝了 Spring 插件的,實質上 LZ 使用 Spring 的插件創建了 SpringMVC 的配置文件,只是文件名不同而已)

4. 然後我們對 SpringMVC 的配置文件 springDispatcherServlet-servlet.xml 進行配置

1)加入命名空間,因為我們在新建配置文件的時候沒有加入命名空間,所以先加入 context 和 mvc 的命名空間。那麼如何加入呢,當我們打開 SpringMVC 的配置文件後,大家可以看到文件的左下角有一些選項卡(如下麵圖片所示),大家點擊第二個選項 Namespaces,

點開後大家吧 context 和 mvc 選項挑上對勾即可。

2)配置自動掃描的包

1 <!-- 配置自動掃描的包:只掃描有 @Controller 和 @ControllerAdvice 註解的包 -->
2     <context:component-scan base-package="com.software.sssp" use-default-filters="false">
3         <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
4         <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice" />
5     </context:component-scan>

在配置自動掃描的包時,LZ 使用了 context:include-filter 子標簽,目的就是讓 SpringMVC 只掃描帶有 @Controller 和 @ControllerAdvice 註解的包中的類,為什麼要這樣做呢?因為我們加入 Spring 的時候只創建了 Spring 的配置文件,還沒有進行配置,一會我們配置的時候,也會先配置 Spring 的 IOC 掃描的包,這樣就有可能出現某些包 Spring 的容器掃描了一遍,SpringMVC 又掃描了一遍,這樣就會造成有些對象會創建多次,造成資源的浪費,配置 context:include-filter 標簽就是為瞭解決這個問題,讓 Spring 和 SpringMVC 只掃描各自關註的包即可。

3)配置視圖解析器:

1 <!-- 配置視圖解析器 -->
2     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
3         <property name="prefix" value="/WEB-INF/views/"></property>
4         <property name="suffix" value=".jsp"></property>
5     </bean>

這裡我們使用的是預設的 InternalResourceViewResolver 視圖解析器,然後配置了一個首碼,一個尾碼。這裡 InternalResourceViewResolver 視圖解析器是如何解析工作的,我們配置的 prefix 和 suffix 有什麼用,在 LZ 的 深入淺出 SpringMVC - 1 中已經詳細介紹,大家可以自行查看。

4)既然在配置視圖解析器的時候我們配置了 prefix 和 suffix ,那麼就需要我們在 WEB-INF 目錄下新建一個 views 文件夾,用來存放我們需要的 jsp 頁面

 5)然後我們把 SpringMVC 的兩個標配配置上:處理靜態請求資源的 <mvc:default-servlet-handler/> 以及 <mvc:annotation-driven></mvc:annotation-driven>

1 <mvc:default-servlet-handler/>
2 <mvc:annotation-driven></mvc:annotation-driven>

三、加入 JPA

1)使用 JPA 需要導入 HIbernate 和 JPA 的 jar 包

Hibernate 的 jar 包:

JPA 的 jar 包:

2)加入 c3p0 和 MySQL 的驅動

c3p0:

MySQL 驅動:

3)其實在這個小案例中 LZ 還是用了 JPA 的二級緩存,所以還加入了二級緩存相關的 jar 包,和配置文件,這裡就不詳細說明瞭。

關於 JPA 的知識呢,LZ 也寫了幾篇播客,大家可以參考:

JPA + SpringData 操作資料庫原來可以這麼簡單 ---- 深入瞭解 JPA - 1

JPA + SpringData 操作資料庫原來可以這麼簡單 ---- 深入瞭解 JPA - 2

JPA + SpringData 操作資料庫原來可以這麼簡單 ---- 深入瞭解 JPA - 3

手把手教你解決無法創建 JPA 工程的問題

 四、配置 Spring 的配置文件

1.加入 context 和 tx 的命名空間,關於如何加入命名空間,上文中進行了詳細的說明,此處不再贅述。

2.配置自動掃描的包

<!-- 配置自動掃描的包 -->
    <context:component-scan base-package="com.software.sssp">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
         <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/>
    </context:component-scan>

註意,此處我們使用 context:exclude-filter 來設置不進行掃描的包,原因在上文中也已經詳細說明。

3.配置數據源

1)在類路徑下新建一個 db.properties 文件,設置連接資料庫的基本信息,在這 LZ 只設置必須的屬性

1 jdbc.user=root
2 jdbc.password=qiqingqing
3 jdbc.driverClass=com.mysql.jdbc.Driver
4 jdbc.jdbcUrl=jdbc:mysql://localhost:3306/sssp

2)在 Spring 的配置文件中導入 db.properties 文件,進行數據源的配置

 1 <!-- 配置數據源 -->
 2     <!-- 導入資源配置文件 -->
 3     <context:property-placeholder location="classpath:db.properties"/>
 4     
 5     <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
 6         <property name="user" value="${jdbc.user}"></property>
 7         <property name="password" value="${jdbc.password}"></property>
 8         <property name="driverClass" value="${jdbc.driverClass}"></property>
 9         <property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
10     </bean>

至此數據源的配置已經結束,在 LZ 的博客中,LZ 不只強調了一次進行分步測試或單元測試的重要性,可以為我們避免不必要的麻煩,接下來就看看我們的數據源是否配置成功。LZ 新建一個測試類 SSSPTest,先來測試一下數據源:

 1 public class SSSPTest {
 2     
 3     private ApplicationContext ctx = null;
 4     
 5     {
 6         ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
 7     }
 8     
 9     @Test
10     public void testDataSource() throws SQLException {
11         DataSource dataSource = ctx.getBean(DataSource.class);
12         System.out.println(dataSource.getConnection());
13     }
14 
15 }

執行 testDataSource 方法,結果為:

這就證明我們的數據源獲取成功!

4. 配置 JPA 的 EntityManagerFactory 

 1 <!-- 配置 JPA 的 EntityManagerFactory -->
 2     <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
 3         <property name="dataSource" ref="dataSource"></property>
 4         <property name="packagesToScan" value="com.software.sssp"></property>
 5         <property name="jpaVendorAdapter">
 6             <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"></bean>
 7         </property>
 8         <property name="jpaProperties">
 9             <props>
10                 <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
11                 <prop key="hibernate.hbm2ddl.auto">update</prop>
12                 <prop key="hibernate.show_sql">true</prop>
13                 <prop key="hibernate.format_sql">true</prop>
14                 <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
15                 
16                 <prop key="hibernate.cache.use_second_level_cache">true</prop>
17                 <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
18                 <prop key="hibernate.cache.use_query_cache">true</prop>
19             </props>
20         </property>
21         <!-- 配置使用二級緩存的模式:只允許帶有 @Cacheable 的類使用二級緩存 -->
22         <property name="sharedCacheMode" value="ENABLE_SELECTIVE"></property>
23     </bean>

解釋一下,第 3 行配置數據源,4 行配置掃描的包,5 行配置 JPA 提供商的適配器,8 行配置 JPA 實現產品即 Hibernate 的基本屬性,22 行配置二級緩存相關。

5. 配置 JPA 的註解和基於註解的事務操作

1 <!-- 配置 JPA 的註解 -->
2     <bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
3         <property name="entityManagerFactory" ref="entityManagerFactory"></property>
4     </bean>
5     
6     <!-- 配置基於註解的事務 -->
7     <tx:annotation-driven transaction-manager="transactionManager"/>

到這裡 JPA 的配置已經完成了,我們再來測試一下 JPA 是否配置成功

我們新建我們需要的兩個實體類,Employee 和 Department,為它們添加基本的 JPA 註解

 1 package com.software.sssp.entity;
 2 
 3 import java.util.Date;
 4 
 5 import javax.persistence.Entity;
 6 import javax.persistence.FetchType;
 7 import javax.persistence.GeneratedValue;
 8 import javax.persistence.Id;
 9 import javax.persistence.JoinColumn;
10 import javax.persistence.ManyToOne;
11 import javax.persistence.Table;
12 import javax.persistence.Temporal;
13 import javax.persistence.TemporalType;
14 
15 import org.springframework.format.annotation.DateTimeFormat;
16 
17 @Table(name="SSSP_EMPLOYEES")
18 @Entity
19 public class Employee {
20     
21     private Integer id;
22     
23     private String lastName;
24     
25     private String email;
26     
27     @DateTimeFormat(pattern="yyyy-MM-dd")
28     private Date Birth;
29     
30     private Date createTime;
31     
32     private Department department;
33 
34     @GeneratedValue
35     @Id
36     public Integer getId() {
37         return id;
38     }
39 
40     public void setId(Integer id) {
41         this.id = id;
42     }
43 
44     public String getLastName() {
45         return lastName;
46     }
47 
48     public void setLastName(String lastName) {
49         this.lastName = lastName;
50     }
51 
52     public String getEmail() {
53         return email;
54     }
55 
56     public void setEmail(String email) {
57         this.email = email;
58     }
59 
60     @Temporal(TemporalType.DATE)
61     public Date getBirth() {
62         return Birth;
63     }
64 
65     public void setBirth(Date birth) {
66         Birth = birth;
67     }
68 
69     @Temporal(TemporalType.TIMESTAMP)
70     public Date getCreateTime() {
71         return createTime;
72     }
73 
74     public void setCreateTime(Date createTime) {
75         this.createTime = createTime;
76     }
77 
78     @JoinColumn(name="DEPARTMENT_ID")
79     @ManyToOne(fetch=FetchType.LAZY)
80     public Department getDepartment() {
81         return department;
82     }
83 
84     public void setDepartment(Department department) {
85         this.department = department;
86     }
87     
88 }
 1 package com.software.sssp.entity;
 2 
 3 import javax.persistence.Cacheable;
 4 import javax.persistence.Entity;
 5 import javax.persistence.GeneratedValue;
 6 import javax.persistence.Id;
 7 import javax.persistence.Table;
 8 
 9 @Cacheable
10 @Table(name="SSSP_DEPARTMENT")
11 @Entity
12 public class Department {
13     
14     private Integer id;
15     
16     private String departmentName;
17 
18     @GeneratedValue
19     @Id
20     public Integer getId() {
21         return id;
22     }
23 
24     public void setId(Integer id) {
25         this.id = id;
26     }
27 
28     public String getDepartmentName() {
29         return departmentName;
30     }
31 
32     public void setDepartmentName(String departmentName) {
33         this.departmentName = departmentName;
34     }
35     
36 }

然後同樣是在 SSSPTest 中執行測試數據源的那個方法,大家會發現,資料庫中多出了兩張表

這就證明 JPA 配置成功

6. 加入 SpringData

1 <!-- 配置 SpringData -->
2     <jpa:repositories base-package="com.software.sssp" 
3                                 entity-manager-factory-ref="entityManagerFactory"></jpa:repositories>

 五、web.xml 中雜項配置

1. 因為案例中會用到中文,我們配置一個字元編碼的過濾器

 1 <!-- 配置字元編碼過濾器 -->
 2     <!-- 字元編碼過濾器必須配置在所有過濾器的最前面! -->
 3     <filter>
 4         <filter-name>CharacterEncodingFilter</filter-name>
 5         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
 6         <init-param>
 7             <param-name>encoding</param-name>        
 8             <param-value>UTF-8</param-value>
 9         </init-param>
10     </filter>
11     
12     <filter-mapping>
13         <filter-name>CharacterEncodingFilter</filter-name>
14         <url-pattern>/*</url-pattern>
15     </filter-mapping>

需要註意的是,這個字元編碼過濾器需要配置在所有過濾器的最前面。

2.因為我們的案例中使用 ResultFul 風格的 URL ,所以在配置一個將 POST 請求轉換為 PUT DELETE 請求的 Filter

 1 <!-- 配置將 POST 請求轉換為 PUT DELETE 請求的 Filter -->
 2     <filter>
 3         <filter-name>HiddenHttpMethodFilter</filter-name>
 4         <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>
 5     </filter>
 6     
 7     <filter-mapping>
 8         <filter-name>HiddenHttpMethodFilter</filter-name>
 9         <url-pattern>/*</url-pattern>
10     </filter-mapping>

至此呢,我們的 SSSP 整合所有的配置和測試就完成了!

六、實現分頁操作

SSSP 整合完成後呢,資料庫中也生成了對應的數據表,LZ 向資料庫中寫入了十幾條測試數據。然後我們實現分頁查詢顯示的效果。

思路分析:

1.DAO 層:直接調用 PagingAndSortingRepository findAll(Pageable pageable) 方法,返回 Page 對象即可(註:關於 PagingAndSortingRepository  的使用 LZ 在介紹 SpringData 的博客已經詳細講解過了)。

2.Service 層:把 Controller 傳入的 pageNo 和 pageSize 封裝成為 Pageable 對象,然後調用 DAO 層的方法即可。

3.Controller 層:獲取 pageNo 並對 pageNo 進行校驗,然後調用 Service  層的方法返回 Page 對象,將 Page 對象放入到 Request 域中進行頁面轉發。

4.JSP 頁面:數據的顯示

思路分析完成之後進行編碼實現。

EmployeeRepository:只定義一個繼承 JpaRepository 的介面即可。

1 public interface EmployeeRepository extends JpaRepository<Employee, Integer> {
2     
3 
4 }

EmployeeService:

 1 @Service
 2 public class EmployeeService {
 3 
 4     @Autowired
 5     private EmployeeRepository employeeRepository;
 6     
 7     @Transactional(readOnly=true)
 8     public Page<Employee> getPage(int pageNo, int pageSize) {
 9         PageRequest pageable = new PageRequest(pageNo - 1, pageSize);
10         return employeeRepository.findAll(pageable);
11     }
12     
13 }

定義了一個 getPage 方法,為該方法添加只讀的事務操作註解,然後調用 DAO 的 findAll() 方法即可,註意 pageNo 是從 0 開始的,所以要對傳入的 pageNo 進行 - 1 的處理。

EmployeeHandler:

 1 @Controller
 2 public class EmployeeHandler {
 3     
 4     @Autowired
 5     private EmployeeService employeeService;
 6     
 7     @RequestMapping("/emps")
 8     public String list(@RequestParam(value="pageNo", required=false, defaultValue="1") String pageNoStr,
 9             Map<String, Object> map) {
10         
11         int pageNo = 1;
12         
13         try {
14             //對 pageNo 的校驗
15             pageNo = Integer.parseInt(pageNoStr);
16             if(pageNo < 0) {
17                 pageNo = 1;
18             }
19         } catch (Exception e) {}
20         
21         Page<Employee> page = employeeService.getPage(pageNo, 5);
22         map.put("page", page);
23         
24         return "emp/list";
25     }
26 
27 }

創建了一個 list 方法,傳入的 pageNoStr 被定義成了 String 類型的,11 行定義了一個 int 型的 pageNo,將 pageNoStr 強轉為 int 型,若傳入的是一個非數值型的字元串,則會出異常,出了異常不必理會,pageNo 還是一開始定義的那個 pageNo,為 1。然後調用 Service 層的方法,定義 pageSize 為 5,得到 Page 對象,放入到 request  域中。

list.jsp 進行數據的顯示即可:

 1 <c:if test="${page == null || page.numberOfElements == 0 }">
 2         <h3>沒有員工記錄!</h3>
 3     </c:if>
 4     
 5     <c:if test="${page != null && page.numberOfElements > 0 }">
 6     
 7         <table border="1" cellspacing="0" cellpadding="10">
 8         
 9             <tr>
10                 <th>Id</th>
11                 <th>LastName</th>
12                 
13                 <th>Email</th>
14                 <th>Birth</th>
15                 
16                 <th>CreateTime</th>
17                 <th>DepartmentName</th>
18                 
19                 <th>Edit</th>
20                 <th>Delete</th>
21             </tr>
22             
23             <c:forEach items="${page.content }" var="emp">
24                 
25                 <tr>
26                     <td>${emp.id }</td>
27                     <td>${emp.lastName }</td>
28                     
29                     <td>${emp.email }</td>
30                     <td>${emp.birth }</td>
31                     
32                     <td>${emp.createTime }</td>
33                     <td>${emp.department.departmentName }</td>
34                     
35                     <td>
36                         <a href="${pageContext.request.contextPath }/emp/${emp.id}">Edit</a>
37                     </td>
38                     <td>
39                         <a href="${pageContext.request.contextPath }/emp/${emp.id}" class="delete">Delete</a>
40                         <input type="hidden" value="${emp.lastName }">
41                     </td>
42                 </tr>
43                 
44             </c:forEach>
45             
46             <tr>
47                 <td colspan="8">
48                     共 ${page.totalElements} 條記錄  &nbsp;&nbsp;&nbsp;
49                     共 ${page.totalPages} 頁  &nbsp;&nbsp;&nbsp;
50                     當前為 ${page.number + 1 } 頁  &nbsp;&nbsp;&nbsp;
51                     
52                     <c:if test="${page.number + 1 > 1 }">
53                         <a href="?pageNo=${page.number + 1 - 1 }">上一頁</a>  &nbsp;&nbsp;&nbsp;
54                     </c:if>
55                     
56                     <c:if test="${page.number + 1 < page.totalPages}">
57                         <a href="?pageNo=${page.number + 1 + 1 }">下一頁</a>  &nbsp;&nbsp;&nbsp;
58                     </c:if>
59                 </td>
60             </tr>
61                         
62         </table>
63         
64     </c:if>

我們註意第 33 行,在顯示 DepartmentName

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

-Advertisement-
Play Games
更多相關文章
  • .net core已經發佈了2.0版本,相對於1.0的有了很大的完善,最近準備在項目中嘗試使用asp.net core,所以就進行了一些簡單的研究。 初識asp.net core分為以下幾個部分: 1、.net core SDK以及vs2017下載安裝 2、創建asp.net core項目 3、初識 ...
  • 1:做過圖像顯示的都知道,我們的圖片大部分都是壓縮過的,大部分為JPEG PNG BMP其中BMP格式是點陣形式,當圖片翻譯到記憶體之後無論壓沒壓縮過都會變成BMP格式放進記憶體,在這個過程中,圖片數據會幾倍的增大,就比如JPEG,一張1M大小的JPEG格式的圖片,翻譯到記憶體可能就會變成7倍左右,也就是 ...
  • C# 語言是在2000發佈的,至今已正式發佈了7個版本,每個版本都包含了許多令人興奮的新特性和功能更新。同時,C# 每個版本的發佈都與同時期的 Visual Studio 以及 .NET 運行時版本高度耦合,這也有助於開發者更好的學習掌握 C#,並將其與 Visual Studio 以及 .NET ... ...
  • 原文:https://www.stevejgordon.co.uk/asp-net-core-anatomy-part-3-addmvc 發佈於:2017年4月環境:ASP.NET Core 1.1 本系列前面兩篇文章介紹了ASP.NET Core中IServiceCollection兩個主要擴展方 ...
  • 1 環境搭建 1.1 Python安裝 1.2 MySQL環境搭建 1.3安裝MySQLdb 2 具體實現 2.1 登陸界面 2.2 註冊界面 2.3 具體實現部分代碼 1 環境搭建 1.1 Python安裝 本文具體實現部分Python環境:Python2.7.14,64位版本 具體安裝步驟見:P ...
  • 要求: 程式流程圖: 程式Readme: MiniFTP主要是由三部分組成:伺服器端、客戶端、管理端。本文主要就是介紹以上三部分內容。 系統初始配置 管理員賬號 用戶名:admin 密碼:password 用戶賬號: 用戶名:zhangsan 密碼:123 伺服器地址: IP:127.0.0.1 P ...
  • RabbitMQ依賴erlang,所以先安裝erlang,然後再安裝RabbitMQ; erlang,下載地址:http://www.erlang.org/download 先安裝erlang,雙擊erlang的安裝文件即可,然後配置環境變數: ERLANG_HOME=D:\Program File ...
  • 線程如何創建 創建線程有三種方式:繼承Thread類;無返回值的Runnable;有返回值的Callable 示例如下 執行結果 線程相關的基礎方法 wait:獲取鎖對象monitor的線程執行wait方法,將會釋放對monitor的控制權,其他線程可以獲取到鎖對象的monitor,執行notify ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...