2020年11月13日 星期五

Nacos ( SpringCloud 2.x 八)

下載nacos
下解解壓後,bin 下有開啟和關閉nacos的程式,副檔名cmd用在windows;sh用在linux
有兩種模式,cluster 和 standalone,預設使用cluster,如果什麼都不做直接啟動會失敗(需要有conf/cluster.conf),改成 standalone才可以啟動,以 windows當例子,打開start.cmd,如下修改即可:
紅框是nacos的判斷,只有兩種,copy到綠框改一下即可
啟動後,開啟 localhost:8848/nacos,預設的帳號密碼都是 nacos,想改密碼如下操作:

點擊權限控制的用戶列表,然後對使用者按修改可改密碼
綠框是改界面的語言



<modules>
    <module>DiscoveryConsumer</module>
    <module>DiscoveryProvider</module>
</modules>
<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>bruce.home</groupId>
<artifactId>SpringCloudPractice</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>SpringCloudPractice</name>
<description>Demo project for Spring Boot</description>
    
<properties>
    <java.version>11</java.version>
    <spring-cloud.version>Hoxton.SR4</spring-cloud.version>
    <nacos.version>2.2.3.RELEASE</nacos.version>
</properties>
    
<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>${nacos.version}</version>
        </dependency>
    
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>${nacos.version}</version>
        </dependency>
    
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.16</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

主pom下有兩個module
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
</properties>
    
<dependencies>
    <!--<dependency>-->
    <!--    <groupId>com.alibaba.cloud</groupId>-->
    <!--    <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>-->
    <!--</dependency>-->
    
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    
    <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>
</dependencies>

兩個子pom內容一樣


子專按的 spring-boot-start-web 一定要有,否則不會註冊到 nacos,如果註冊成功會在控制台顯示
當然yml也要設定

也可以在nacos控制台看

服務名是 spring.application.name




※改變資料庫

內鍵的資料庫是derby,可以換成 mysql,打開 conf/application.properties,將底下的五行註解打開,帳密資料庫名稱修改一下即可!然後將conf/nacos-mysql.sql 執行到自己的資料庫,結果如下兩張圖,控制台可看到差異




※集群設定
集群至少要三個以上(含)才可以,且一定不能是內鍵資料庫,不然就不能共享了
conf/cluster.conf.example 修改或新增一個檔案成為 cluster.conf,內容如下:

127.0.0.1:9000
127.0.0.1:9001
127.0.0.1:9002

然後將整個 nacos 複製成三份,然後改變 application.properties 的 port 成為以上三個 port
最後用類似 nginx 這種負載均衡的軟體來轉發,nginx.conf 如下,只貼最重要的部分:
http {
        upstream clusterNacos {
server 127.0.0.1:9000;
server 127.0.0.1:9001;
server 127.0.0.1:9002;
}

server {
listen 9003;
server_name localhost;
location / {
proxy_pass http://clusterNacos;
}
}
}

使用 localhost:9003/nacos 就會轉發三台了,「集群管理/節點列表」可看到結果

源碼請看github

Lombok 的 builder 繼承

@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
public class Me extends Father {
    private String color;
}

@Data
@EqualsAndHashCode(callSuper = true)
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
@ToString(callSuper = true)
public class Father extends GrandFather {
    private int id;
}

@Data
@SuperBuilder
@AllArgsConstructor
@NoArgsConstructor
public class GrandFather {
    private int age;
}

// test
Me me = Me.builder()
			.color("red")
			.id(555)
			.age(78)
			.build();
	System.out.println(me);
	System.out.println(me.getColor());
	System.out.println(me.getAge());

※必需使用 @SuperBuilder 註解,父子類都要,使用 1.18.16 版本測試的

2020年10月20日 星期二

快速排序

1.將隨便一個數字設定為 pivot,通常設為第一個

2.左大右小,取最左邊和最右邊的數,左邊 > pivot;右邊 < pivot

先判斷右邊,如果沒有 < pivot,就再往左

再判斷左邊,如果沒有 > pivot,就再往右

都符合條件就左右互換

3.持續做 2 一直到左右的 index 一樣,此時將 pivot 和此值做交換,這時結果為左邊都 < pivot;右邊都 > pivot

4.pivot 的左邊和右邊又有兩個未排序好的(不包括 pivot 這個值),再重覆 1~4


例:

右:23 比 35 小
左:42 比 35 大
交換



右:18 比 35 小
左:79 比 35 大
交換


右:12 比 35 小
左:往右時和右指針 index 一樣
pivot 和 index 的值交換
此時會分成綠色和藍色兩邊,這兩邊再重覆去做即可





public static void main(String[] args) {

    int[] arr = new int[]{5, 4, 8, 6, 3, 9, 0, 1, 7, 2};

    quickSort(arr, 0, arr.length - 1); // 減1是因為 index 從 0 開始

    Arrays.stream(arr).forEach(System.out::print);

}


public static void quickSort(int[] arr, int leftIndex, int rightIndex) {

if (arr == null || arr.length <= 1) return; // 無法再排序

if (leftIndex >= rightIndex) return;


int pivot = arr[leftIndex];

int left = leftIndex;

int right = rightIndex;


while (left != right) { // index 一樣就離開

while (arr[right] >= pivot && left < right) right--; // 右邊要找 < pivot,< 的相反就是 >=

while (arr[left] <= pivot && left < right) left++; // 左邊要找 > pivot,> 的相反就是 <=


if (left < right) { // 左右交換

arr[left] = arr[left] ^ arr[right];

arr[right] = arr[left] ^ arr[right];

arr[left] = arr[left] ^ arr[right];

}

}

        // pivot 和 index 的值交換

arr[leftIndex] = arr[left];

arr[left] = pivot;


quickSort(arr, leftIndex, left - 1); // 綠色

quickSort(arr, left + 1, rightIndex); // 藍色

2020年2月20日 星期四

IntelliJ IDEA 創建 Servlet 並整合 Thymeleaf


1.File -> New -> Project

下面的 web.xml 看要不要產生,後面也還可以改
如果要 thymeleaf,就可以勾 thymeleaf,子選項都不用勾


2.產生後,加入 servlet 的 jar 檔

路徑選 tomcat 路徑下的 bin,抓 servlet-api 或整個資料夾都選


3.File -> Project Structure

如果一開始沒有選 web.xml,可在這裡加入


4.新增 Servlet

舊版的 IntelliJ 不一定會取 Create New Servlet,可能是 New Servlet 而已
如果是用 @WebServlet,要注意預設屬性是 name,但大部分是用 urlPatterns


5.Run -> Edit Configurations

Server 活頁標籤 Application server 要選中 tomcat 的路徑
下面還有 After launch,表示啟動後用什麼瀏覽器打開
Http port 寫你想要的 port

Deployment 的紅框部份的 context 是瀏覽器上要用到的路徑,假設寫 /test,那瀏覽器就要打
http://localhost:8080/test/index.html
又如果是寫 /,那就打
http://localhost:8080/index.html

※如果是 社區版,可以在 File >> Settings >> Plugins,搜尋 smart tomcat 來安裝
Deployment Directory 寫 jsp 的資料夾路徑,一定要有路徑,否則啟動不起來,亂指定沒關係,只差在顯示不了 jsp 的畫面而已
.配合 maven 或 gradle 就可啟動伺服器了,但 gradle 加入 servlet 時,用 providedCompile 時,必需再增加 id 'war',如下:
plugins {
    id 'java'
    id 'war'
}

.社區版也沒有用滑鼠點一點就有 Servlet 可用,只能自己寫了,要對 servlet 熟一點而已


※Thymeleaf


※如果一開始有勾 thymeleaf,且有寫代碼,那啟動伺服器時會報找不到 thymeleaf 的錯,要照這張圖的設定就可以了


※MyServlet.java

@WebServlet("*.do")
public class MyServlet extends HttpServlet {
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html;charset=UTF-8");
        //request.getRequestDispatcher("/WEB-INF/templates/welcome.html").forward(request, response);
    
        WebContext ctx = new WebContext(request, response, request.getServletContext(),
                request.getLocale());
        ctx.setVariable("now", LocalDateTime.now().toString());
    
        var templateResolver = new ServletContextTemplateResolver(request.getServletContext());
        templateResolver.setPrefix("/WEB-INF/templates/");
        templateResolver.setSuffix(".html");
    
        TemplateEngine templateEngine = new TemplateEngine();
        templateEngine.setTemplateResolver(templateResolver);
        templateEngine.process("hi", ctx, response.getWriter()); // 找 /WEB-INF/templates/hi.html
    }
}



※hi.html

<!doctype html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <title>Thymeleaf Demo</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
</head>
<body>
    <p th:text="#{xxx.ooo}">default text</p>
    <p>Date : <span th:text="${now}">no data</span></p>
</body>
</html>


※hi_en.properties

xxx.ooo=Hello! Thymeleaf!


git 專案

2020年2月14日 星期五

git submodule/subtree

※submodule

一、新增子模組

git submodule status // 只能看有沒有子模組,沒有什麼都不顯示;有就顯示 hash,此 hash 同子模組

git submodule add 路徑
有4個地方會改變
1.整個子模組會成為主模組的一個目錄
2.多了 .gitmodules(隱藏檔),裡面是多個子模組的資訊
3. .git 會增加 modules 資料夾,裡面是各個子模組,再點進去是子模組的 .git 目錄
4. .git/config 檔也會增加資訊,使用 git config --list 會抓此檔的資訊,所以
用這個命令也可以看到

注意事項:
1.主模組和子模組操作是分開的(主模組的命令只對自己有用,子模組也是),但在主模組可看到子模組的狀態,只能看有沒有變動,至於變動什麼要進去子模組操作才知道
  P.S 操作子模組要進去這個子模組裡面,命令都和之前一樣
2.子模組有變動,要做到 commit 這一步,主模組的 add 才有用,add 有用才能對子模組進行版本控制
3.如果只 push 主模組,那別人更新時會有麻煩,所以在 push 時,可用 git push --recurse-submodules=check
如果子模組沒有 push,就會報錯
git push --recurse-submodules=on-demand 會在主模組 push 前將子模組先 push,當然如果有錯就不行


如果有多個子模組都想更新,用上面的方法會進入各個子模組進行操作,比較麻煩,可用如下方式解決
git submodule update --remote 子模組名(如果要更新全部的模組就不需要打子模組名)
這樣所有的子模組就會更新了,但會使子模組分支變成 detached,
解決方法是在子模組新增一個分支,然後在 main 分支 merge 新的分支,最後再刪除新分支

上面的做法太麻煩,以下其中一個指令可以直接做好
git submodule update --remote --merge
git submodule update --remote --rebase


二、clone 有子模組的 git

clone 完,.gitmodules 檔案是 ok 的,但子模組裡是空的
git submodule status 看起來是有的,但實際上是空的

所以要下如下的指令
git submodule init // .git/config 會寫入子模組的資訊,但子模組仍然是空的
git submodule update // 下載子模組的資料
  P.S 以上兩行順序不能換,否則 update 也不報錯,但什麼都沒發生
git submodule update --init // 合併成一行

如果一開始就知道有子模組,可下如下的指令
git clone --recursive 路徑


三、刪除子模組

1.git submodule deinit submodule名(遠端的名字)或者 --all // 將 config 檔案裡的資訊移除,也會將子模組裡的東西清空,在做這步之前 status 必需要是最新的
2.git rm --cached submodule專案名 // 將.gitmodules 檔案裡的子模組資料刪除(--cached 會保留子模組目錄,如不需要就不要加)
  P.S 以上兩步 git submodule status 就看不到了,但其實還沒移乾淨
3.將.git/modules 裡的子模組資料夾刪除(如用指令可下 rm -rf submodule_name)



※subtree

一、新增子樹

git subtree add --prefix=子樹名 --squash 路徑或遠端名 master
--prefix=(有等號) 也可寫成 -P(沒等號), 子樹名會變成目錄名,而路徑的內容會在裡面
--squash 如果不加會所有 log 歷史都有,squash 是壓縮的意思,可想成是精簡版,表示只要最新的 log
master 是遠端分支,意思就是從遠端的 master 分支複製過來
路徑或遠端名:使用 git remote add key 路徑,是個鍵值對,設定完後,這個 key 就等同是遠端名了


二、上傳子樹

git subtree push --prefix=子樹名 路徑或遠端名 master
如果只用 git push 不會上傳子樹






三、下載子樹

git subtree pull --squash --prefix=子樹名 路徑或遠端名 master
注意:如果 add 時有 squash,這裡也要加



※ submodule 和 subtree 比較

submodule 是參照的方式,所以操作時,兩個模組是分開的;commit 和子模組會一樣
subtree 是複製的方式,所以操作時還是用主樹操作即可;commit 和子樹不同