主頁 > 後端開發 > Spring Cloud開發實踐(六): 基于Consul和Spring Cloud 2021.0的演示專案

Spring Cloud開發實踐(六): 基于Consul和Spring Cloud 2021.0的演示專案

2023-05-18 09:33:45 後端開發

目錄

  • Spring Cloud開發實踐(一): 簡介和根模塊
  • Spring Cloud開發實踐(二): Eureka服務和介面定義
  • Spring Cloud開發實踐(三): 介面實作和下游呼叫
  • Spring Cloud開發實踐(四): Docker部署
  • Spring Cloud開發實踐(五): Consul - 服務注冊的另一個選擇
  • Spring Cloud開發實踐(六): 基于Consul和Spring Cloud 2021.0的演示專案

Consul 服務

啟動Consul服務, 在Win10下可以執行以下命令, 或者存成bat檔案運行, 保持視窗打開

consul agent -dev -client=0.0.0.0 -data-dir .\ -advertise 127.0.0.1 -ui -config-dir .\

瀏覽器訪問 http://127.0.0.1:8500 , 用于觀察后面注冊的Node和Health情況

Spring Cloud 專案

這個演示專案使用的 Spring Boot 和 Spring Cloud 都不是最新版本, 因為最新版本最低要求 JDK17. 這里選擇的是對應 JDK11 可用的最高版本, 各組件版本明細為

  • Consul 1.15
  • JDK 11
  • Spring Boot 2.7.11
  • Spring Cloud 2021.0.6

整體結構

這個用于演示的專案名稱為 Dummy, 包含3個子模塊, 分別是 dummy-common-api, dummy-common-impl 和 dummy-admin, 其中

  • dummy-common-api 和 dummy-common-impl 邏輯上屬于同一個模塊 dummy-common. api 是對外輸出的介面, impl是對應的實作
  • dummy-admin 依賴 dummy-common-api , 使用其提供的介面

打包后, 需要部署的是兩個jar: dummy-common.jar 和 dummy-admin.jar, 前者提供服務介面, 后者消費前者提供的介面, 并對外(例如前端, 小程式, APP)提供介面

專案的整體結構如下

│   pom.xml
├───dummy-admin
│   │   pom.xml
│   ├───src
│   │   ├───main
│   │   │   ├───java
│   │   │   └───resources
│   │   │           application.yml
│   │   └───test
│   └───target
├───dummy-common-api
│   │   pom.xml
│   ├───src
│   │   ├───main
│   │   │   ├───java
│   │   │   └───resources
│   │   └───test
│   └───target
└───dummy-common-impl
    │   pom.xml
    ├───src
    │   ├───main
    │   │   ├───java
    │   │   └───resources
    │   │           application.yml
    │   └───test
    └───target

根模塊 Dummy

根模塊的 pom.xml 中,

  • 定義了子模塊, module標簽中的內容, 要和子模塊目錄名一致.
  • 設定JDK版本 11
  • 引入全域 Spring Boot Dependencies, 版本 2.7.11
  • 引入全域 Spring Cloud Dependencies, 版本 2021.0.6
  • 還有一些是Plugin相關的版本, 略
<?xml version="1.0" encoding="UTF-8"?>
    ...
    <name>Dummy: Root</name>
    <modules>
        <module>dummy-common-api</module>
        <module>dummy-common-impl</module>
        <module>dummy-admin</module>
    </modules>

    <properties>
        <!-- Global encoding -->
        <project.jdk.version>11</project.jdk.version>
        <project.source.encoding>UTF-8</project.source.encoding>

        <!-- Global dependency versions -->
        <spring-boot.version>2.7.11</spring-boot.version>
        <spring-cloud.version>2021.0.6</spring-cloud.version>
    </properties>

    <dependencyManagement>
        <dependencies>
            <!-- Spring Boot Dependencies -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <!-- Spring Cloud Dependencies -->
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

        </dependencies>
    </dependencyManagement>

    <build>
        ...
    </build>

</project>

Dummy Common API 模塊

這個模塊用于生成依賴的jar包, 作用非常重要. 以下詳細說明

pom.xml 中除了定義和父模塊的關系, 需要引入 openfeign

<?xml version="1.0" encoding="UTF-8"?>
    ...
    <parent>
        <groupId>com.rockbb.test</groupId>
        <artifactId>dummy</artifactId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../pom.xml</relativePath>
    </parent>

    <artifactId>dummy-common-api</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>

    <name>Dummy: Commons API</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        ...
    </dependencies>

    <build>
        ...
    </build>
</project>

定義一個 UserDTO, 這個是用于傳輸的資料物件

@Data
public class UserDTO implements Serializable {
    private Long id;
    private String name;
}

對應的服務介面. 這里用到了 @FeignClient 注解

  • @FeignClient 是給 dummy-admin 模塊用的
    • name= CommonConstant.SERVICE_NAME 就是 "dummy-common", 因為這個API模塊中所有Service介面都使用同樣的名稱, 這邊做成常量
    • contextId = "userDTOService" 如果不加這個引數, 多個 FeignClient 使用同樣的 name 時, 就會沖突. 這個一般直接定義為這個 service 的bean名稱
    • path = "/userDTOService" 用于指定當前類中所有介面的請求前綴. 在更早的版本中, 可以將 @RequestMapping 和 @FeignClient 聯用, 這個是定義在 @RequestMapping 中的, 后來不允許了, 因為有安全風險.
  • @GetMapping 和 @PostMapping 同時用于 dummy-admin 和 dummy-common
    • 對于 dummy-admin, 這就是 FeignClient 的請求路徑
    • 對于 dummy-common, 這就是 Contoller 方法的服務路徑
    • 需要注意 @GetMapping 請求的介面形式, 必須顯式添加 @RequestParam("id") 這類 GET 模式的引數注解, 否則使用 @GetMapping 的 Feign 請求也會被轉為 POST 而導致請求錯誤.
@FeignClient(name = CommonConstant.SERVICE_NAME, contextId = "userDTOService", path = "/userDTOService")
public interface UserDTOService {

    @GetMapping("/get")
    UserDTO get(@RequestParam("id") long id);

    @PostMapping("/add")
    int add(@RequestBody UserDTO dto);
}

在 dummy-admin 中, 這個介面會被實體化為 feign 代理, 在模塊中可以像普通 service 一樣呼叫, 而在 dummy-common 中, 不引入 feign 依賴, 或者在 @EnableFeignClients 的 basePackages 中避開本包路徑, 就會忽略這個注解, 從而實作模塊間介面的關聯.

與現在很多 Spring Cloud 專案中單獨拆出一個 Service 模塊的做法, 這種實作有很多的優點

  • 開發程序友好. 與單機開發幾乎一樣的代碼量, 唯一區別是要注意 Get 和 Post 對請求引數的格式和個數的約束
  • 易重構易擴展. 可以借助 IDE 的代碼分析能力, 改動自動標紅, 避免人為錯誤和遺漏
  • 性能開銷小, 如果 DTO 直接映射到資料庫欄位, 可以全程使用一個類.

Dummy Common Impl 模塊

模塊的 pom.xml

  • 引入 spring-boot-starter-web, 因為要提供 RestController 的能力
  • 引入 spring-cloud-starter-consul-discovery 或 spring-cloud-starter-consul-all, 因為要接 Consul
  • 引入 dummy-common-api 依賴, 因為 Controller 請求定義在 API 中
  • 打包使用 spring-boot-maven-plugin 的 repackage, 因為要打 fat jar, 在服務器上實作單包部署
<?xml version="1.0" encoding="UTF-8"?>
    ...
    <name>Dummy: Common Implementation</name>

    <dependencies>
        <!-- Spring Boot Dependencies -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <!-- Spring Cloud Dependencies  consul-discovery 和 consul-all 二選一 -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-all</artifactId>
        </dependency>
        ...
        <dependency>
            <groupId>com.rockbb.test</groupId>
            <artifactId>dummy-common-api</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>dummy-common</finalName>
        <resources>
            ...
        </resources>
        <plugins>
            ...
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

配置部分 application.yml

  • 定義服務埠 8762
  • 定義 servlet 路徑, 必須定義, 否則不會配置 Controller 請求
  • spring.application.name: dummy-common 定義了本服務的名稱, 這個名稱就是在 FeignClient 中參考的服務名稱, 需要與 FeignClient 中的值一致
  • spring.config.import 如果使用這個設定, 依賴要使用 consul-all, 因為 consul-discovery 中不帶 consul-config. 使用這個設定后, 會自動使用默認的 Consul 地址和埠
  • cloud.consul.host 和 port 如果使用了config.import, 在這里可以修改默認的值, 如果不使用config.import, 則必須配置 host 和 port, 依賴可以換成 consul-discovery
  • cloud.consul.discovery.health-check-path 用于更改默認的 health 檢查請求路徑, 默認的是 /actuator/health, 這里改為 /health
  • cloud.consul.discovery.instance-id 用于定義當前實體在 Consul 里的實體ID. 默認使用 application.name-port, 如果正好這個服務在兩個服務器上分別跑了一個實體, 且實體埠一樣, 就會產生沖突, 可以改為 application.name-[隨機串] 的形式避免沖突
server:
  port: 8762
  tomcat:
    uri-encoding: UTF-8
  servlet:
    context-path: /

spring:
  application:
    name: dummy-common

  config:
    import: 'optional:consul:' #This will connect to the Consul Agent at the default location of "http://localhost:8500"

#  cloud:
#    consul:
#      host: 127.0.0.1
#      port: 8500
#      discovery:
#        health-check-path: /health # replace the default /actuator/health
#        instance-id: ${spring.application.name}:${random.value}

代碼部分, 首先是實作 health 檢查的處理方法, 這部分是普通的 RestController 方法. 回傳字串可以任意指定, 只要回傳的 code 是 200 就可以

@RestController
public class HealthCheckServiceImpl {

    @GetMapping("/health")
    public String get() {
        return "SUCCESS";
    }
}

服務介面的實作類, 這里實作了兩個介面方法 get 和 add

  • 使用 @RestController 注解, 與 API Service 中方法上的 @GetMapping 和 @PostMapping 配合, 將 Service 方法映射為 Controller 方法
  • 在類上的 @RequestMapping("userDTOService") 方法是必須的, 因為在 API Service 中與 @FeignClient 沖突無法定義, 只能在這里定義
  • 方法和引數上除了 @Override 不需要任何注解, 因為都在 API Service 上定義過了. 這里加上注解也沒問題, 但是要手工保持一致.
@RestController
@RequestMapping("userDTOService")
public class UserDTOServiceImpl implements UserDTOService {

    @Autowired
    private UserRepo userRepo;

    @Override
    public UserDTO get(long id) {
        log.debug("Get user: {}", id);
        UserDTO user = new UserDTO();
        user.setId(id);
        user.setName("dummy");
        return user;
    }

    @Override
    public int add(UserDTO dto) {
        log.debug("Add user: {}", dto.getName());
        return 0;
    }
}

dummy-common 模塊運行后會將介面注冊到 Consul, 啟動后注意觀察兩部分:

  1. Consul 的日志輸出和控制面板顯示, 在-dev模式下, 節點注冊后 Consul 日志會顯示模塊的名稱和心跳檢測記錄, 面板上會顯示新的 Node
  2. Consul 控制面板中顯示的 Health Checks 是否正常, 如果不正常, 需要檢查 /health 路徑為什么訪問失敗

Dummy Admin 模塊

dummy-admin 是呼叫介面, 并對外提供服務的模塊

pom.xml 和 dummy-common 基本一樣, 因為都要連接 Consul, 都要提供 Controller 方法

<?xml version="1.0" encoding="UTF-8"?>
    ...
    <name>Dummy: Admin API</name>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-consul-discovery</artifactId>
        </dependency>

        <dependency>
            <groupId>com.rockbb.test</groupId>
            <artifactId>dummy-common-api</artifactId>
            <version>${project.version}</version>
        </dependency>
    </dependencies>

    <build>
        <finalName>dummy-admin</finalName>
        <resources>
           ...
        </resources>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
            ...
        </plugins>
    </build>
</project>

在主應用入口, 除了 @SpringBootApplication 以外, 還需要增加兩個注解

  • @EnableDiscoveryClient(autoRegister=false) 連接到 Consul 并使用服務發現, 默認會將當前節點也注冊到 Consul 作為服務. 對于純消費節點, 不對其它節點提供介面的, 使用 autoRegister=false 可以避免將自己注冊到 Consul
  • @EnableFeignClients(basePackages = {"com.rockbb.test.dummy.common.api"}) 掃描對應的包, 對 @FeignClient 注解實體化介面代理
/* Attach to discovery service without registering itself */
@EnableDiscoveryClient(autoRegister=false)
@EnableFeignClients(basePackages = {"com.rockbb.test.dummy.common.api"})
@SpringBootApplication
public class AdminApp {
    public static void main(String[] args) {
        SpringApplication.run(AdminApp.class, args);
    }
}

在呼叫方法的地方, 按普通 Service 注入和呼叫

@Slf4j
@RestController
public class IndexController {

    @Autowired
    private UserDTOService userDTOService;

    @GetMapping(value = "https://www.cnblogs.com/user_get")
    public String doGetUser() {
        UserDTO user = userDTOService.get(100L);
        return user.getId() + ":" + user.getName();
    }

    @GetMapping(value = "https://www.cnblogs.com/user_add")
    public String doAddUser() {
        UserDTO user = new UserDTO();
        user.setName("foobar");
        int result = userDTOService.add(user);
        return String.valueOf(result);
    }

可以通過注入的 DiscoveryClient 物件, 查看對應服務的服務地址(一般不需要)

@Autowired
private DiscoveryClient discoveryClient;

@GetMapping("/services")
public Optional<URI> serviceURL() {
    return discoveryClient.getInstances(CommonConstant.SERVICE_NAME)
            .stream()
            .map(ServiceInstance::getUri)
            .findFirst();
}

參考

  • Consul和Spring Boot非常詳細的配置教程 https://medium.com/javarevisited/hands-on-consul-with-spring-boot-1ebf2918165c

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/552769.html

標籤:Java

上一篇:Spring回圈依賴那些事兒(含Spring詳細流程圖)

下一篇:返回列表

標籤雲
其他(159252) Python(38148) JavaScript(25433) Java(18058) C(15228) 區塊鏈(8267) C#(7972) AI(7469) 爪哇(7425) MySQL(7197) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5871) 数组(5741) R(5409) Linux(5340) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4573) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2433) ASP.NET(2403) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1975) 功能(1967) Web開發(1951) HtmlCss(1938) python-3.x(1918) C++(1917) 弹簧靴(1913) xml(1889) PostgreSQL(1878) .NETCore(1861) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Spring Cloud開發實踐(六): 基于Consul和Spring Cloud 2021.0的

    2018年寫的Spring Cloud介紹, 距今已經過去五年, 一些組件和版本已經發生變化. 這篇文章在上一篇介紹 Consul 的基礎上, 介紹基于 Consul 的 Spring Cloud 演示專案 ......

    uj5u.com 2023-05-18 09:33:45 more
  • Spring回圈依賴那些事兒(含Spring詳細流程圖)

    本篇不僅僅是介紹Spring回圈依賴的原理,而且給出Spring不能支持的回圈依賴場景與案例,對其進行詳細決議,同時給出解決建議與方案,以后出現此問題可以少走彎路。 ......

    uj5u.com 2023-05-18 09:28:11 more
  • Java中的字串

    (java中的字串) 一、簡介 Java字串就是Unicode字符序列。Java里沒有內置的字串型別,而是在標準的類別庫中提供了一個預定義類,String。每個用雙引號""括起來的都是String類的一個實體。 字串是日常開發中最常用, Java字串的一個重要特點就是字串不可變 二、字串 ......

    uj5u.com 2023-05-18 09:12:24 more
  • 都說 C++ 沒有 GC,RAII: 那么我算個啥?(贈書福利)

    學過 Java、C# 或者其他托管語言(managed languages)的同學,回過頭來看 C++ 的時候,第一反應就是 C++ 沒有自動垃圾回收器(GC),而不能充分利用的資源被稱為垃圾。 ......

    uj5u.com 2023-05-18 07:44:39 more
  • Spring Cloud開發實踐(五): Consul - 服務注冊的另一個選擇

    Consul 是微服務網路解決方案之一, 用于管理跨網路和多云環境服務之間的安全網路連接, 提供服務發現, 服務網格, 流量管理和自動更新. 可以單獨部署, 也可以分布式部署. Consul 內建安全通信選項, 使用 Go 語言撰寫, 啟動資源消耗小, 腳本化配置, 對容器部署方式更友好 ......

    uj5u.com 2023-05-18 07:44:32 more
  • 解決xorm逆向工程問題

    解決xorm逆向工程問題 問題 xorm : 無法將“xorm”項識別為 cmdlet、函式、腳本檔案或可運行程式的名稱。請檢查名稱的拼寫,如果包括路徑,請確保路徑正確,然后再試一次。 今天在用xorm做逆向工程的時候碰到了一個普遍問題,xorm : 無法將“xorm”項識別為 cmdlet、函式、 ......

    uj5u.com 2023-05-18 07:44:27 more
  • 我的第二次博客作業

    AZ-1的第二次博客作業 AZ-1 - 博客園 (cnblogs.com) 前言 題量 題目集4題量較小。 題目集5題量較小。 期中考試題量中等。 難度 題目集4雖然只有一道題,但是題目很長,難度很大,讓人在看到的時就心生畏懼。選單4在選單3的基礎上增加了大量的錯誤輸入,大大增加了程式的代碼量,很考 ......

    uj5u.com 2023-05-18 07:43:49 more
  • SpringBoot+MyBatis+MySQL電腦商城專案實戰(四)用戶注冊—控制層

    5 注冊-控制層 5.1 創建回應 狀態碼、狀態碼描述資訊、資料。這部分功能封裝到一個類中,將這類作為方法回傳值,回傳給前端瀏覽器。 package com.cy.store.util; import java.io.Serializable; /** * Json格式的資料進行回應 */ publ ......

    uj5u.com 2023-05-18 07:43:19 more
  • ThreadLocal 的原理講述 + 基于ThreadLocal實作MVC中的M層的事務

    ThreadLocal 的原理講述 + 基于ThreadLocal實作MVC中的M層的事務控制 每博一文案 生活不是努力了就可以變好的,喜歡做的事情也不是輕易就可以做的。以前總聽別人說, 堅持就好了,努力就好了,都會好的,可是真的做起來壓根就不是這樣。這種時候要怎么辦? 這種時候還能輕易地相信時間嗎 ......

    uj5u.com 2023-05-18 07:42:13 more
  • 認識Java

    Java的產生和發展 產生與發展歷程 1991年,由Sun公司開發Oak,最初為家用消費電子產品進行編程,是Java前身。 1994年,使用Oak語言撰寫了Web瀏覽器 1995年,改名為Java,96年發布JDK1.1 … 1998年,發布JDK1.2,從語言發展為平臺 … 2004年,發布JDK ......

    uj5u.com 2023-05-18 07:41:35 more