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 和子樹不同

2019年9月14日 星期六

Excel VBA 五 String、日期、Function、Sub

※String

Dim str As String
str = "abcdefg"
Cells(1, "A").Value = Now
Cells(1, "B").Value = Left(str, 4) 'abcd
Cells(2, "B").Value = Right(str, 4) 'defg
Cells(3, "B").Value = Mid(str, 4, 2) 'de
Cells(4, "B").Value = Len(str) '7
Cells(5, "B").Value = InStr(str, "cd") '3

※VBA 的 index 是從 1 開始的



※日期

Dim d1 As Date
Dim d2 As Date

d1 = DateValue("Jan 21, 1999")
Cells(1, "A").Value = d1 '1999/1/21
Cells(2, "A").Value = Year(d1) '1999
Cells(3, "A").Value = Month(d1) '1
Cells(4, "A").Value = Day(d1) '21

d2 = TimeValue("17:25:37")  '等同 TimeValue("5:25:37 pm")
Cells(5, "A").Value = Hour(d2) '17
Cells(6, "A").Value = Minute(d2) '25
Cells(7, "A").Value = Second(d2) '37


.增加
Dim d As Date
d = DateValue("Jan 21, 1999")
d = DateAdd("m", -1, d)
MsgBox (d)

※第一個參數如下:
yyyy - 年
q - 季度
m - 月
y - 当年的第几天
d - 日
w - 当周的第几天
ww - 周
h - 小时
n - 分钟
s - 秒


 ※Function 和 Sub

Sub hello() '我是註解
  'MsgBox 3 * fun1()
  'MsgBox fun2(3, 2)
  'Call s1
  's1
  Call s2(3, 2)
  s2 3, 2
End Sub

Function fun1() As Integer
  fun1 = 2
End Function

Function fun2(a As Integer, b As Integer) As Integer
  fun2 = a * b
End Function

Sub s1()
  MsgBox fun2(3, 2)
End Sub

Sub s2(a As Integer, b As Integer)
  MsgBox fun2(a, b)
End Sub

※Function 有沒有回傳值都可以,Sub 不能有回傳值

※呼叫時,Sub 可用 Call,如果不想用 Call,後面一定不能有圓括號

2019年9月13日 星期五

telegram BotAPI

安裝好 telegram 後,開啟 https://core.telegram.org/bots 文檔

開啟你的 telegram,然後點紅框的連結,即可加入 BotFather
指令查詢:輸入 /start 或 /help 會出現可以打得指令
/newbot 新增一個 bot

出現 Alright, a new bot. How are we going to call it? Please choose a name for your bot. 後
為你的 bot 取一個名字

取好後,會出現
Good. Now let's choose a username for your bot. It must end in `bot`. Like this, for example: TetrisBot or tetris_bot.

再取一個使用者名稱,一定要 bot 結尾
這個地方我試了好幾個名稱都不行

不行的訊息:
Sorry, this username is already taken. Please try something different.

成功後,會出現 Done! Congratulations on your new bot. You will find it at 開頭的
同時 telegram 也會增加一個 bot
Use this token to access the HTTP API 是取得的 token




可以使用 /token 和 /revoke 重新產生 token 和註消 token

如果按了清螢幕,所以看不到 token 了,還可以用 /mybots
然後點擊你取的 username,再點擊 API Token 即可

開啟群組:

/setjoingroups
@你的 username
然後開啟或關閉
這個功能能讓你的 bot 加入其他的群組
然後在 xxxbot 隨便打幾個字,然後新建群組後,將 xxxbot 加進去就可以對這個群發送訊息了




https://api.telegram.org/bot{你的 token}/getUpdates 可以取得你向你的 bot 發訊息的 json 內容
其中 id 表示此群的 id,如果有加入群組,每個群組的 id 會不一樣

加入群組:
創一個群組後,將機器人加入,並發訊息,然後在上面的網址 getUpdates 裡會有 id


使用 java 11 發送訊息:

import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class TestTelegram {
    private final String TELEGRAM_TOKEN = "你的 token";
    private final String CHAT_ID = "你的群組 id 或機器人 id";
    private final String TEXT = "要發送的訊息";

    public static void main(String[] args) throws Exception {
        TestTelegram telegram = new TestTelegram();
        HttpClient client = HttpClient.newBuilder().build();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(
                        "https://api.telegram.org/bot" + telegram.TELEGRAM_TOKEN +
                                "/sendMessage")
                )
                .header("Content-Type", "application/x-www-form-urlencoded")
                .POST(HttpRequest.BodyPublishers.ofString("chat_id=" + telegram.CHAT_ID + "&text=" + telegram.TEXT))
                .build();

        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        System.out.println(response.statusCode());
    }
}




使用 apache 發送訊息:
CloseableHttpClient httpClient = HttpClients.createDefault();
HttpPost httpPost = new HttpPost("https://api.telegram.org/bot" + 得到的 token +
"/sendMessage");

httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
List<NameValuePair> urlParameters = new ArrayList<>();
urlParameters.add(new BasicNameValuePair("chat_id", CHAT_ID));
urlParameters.add(new BasicNameValuePair("text", TEXT));
httpPost.setEntity(new UrlEncodedFormEntity(urlParameters));

CloseableHttpResponse execute = httpClient.execute(httpPost);
execute.close();

2019年9月11日 星期三

Excel VBA 四 宣告變數、陣列、If、迴圈、Select Case

※宣告變數

Dim x As Integer
'x = "d"
x = 1 + 2
MsgBox (7 + x)
MsgBox ("x=" & x)

※雖然不用宣告也可以執行,但如果不宣告,註解那行是可以執行的

※類型
Byte (1):無符號,0-255
Integer (2)
Long (4)
Double (8)
Boolean (2)
Decimal (14)
String

Date (8)
Currency (8)
Single (4)
Object (4)
Variant (根据分配确定)

數字預設是 Integer



※陣列

Dim a(6 To 10) As String
a(6) = "a"
a(8) = "b"
a(10) = "c"
MsgBox a(6) 'a
MsgBox a(7) '

※如果不在範圍內 (6-10),如 a(5) 會報 Subscript out of range

.二維陣列

Dim b(1 To 3, 2 To 4) As String
b(1, 2) = "kkk"
MsgBox b(1, 2) 'kkk


※If

Dim i As Byte
i = 7
If i = 1 Then
  MsgBox (1)
ElseIf i = 2 Then
  MsgBox (2)
ElseIf i = 7 Then
  MsgBox (7)
Else
  MsgBox ("hahaha")
End If

※不等於用 <>


Dim i As Byte
i = 7
If i = 0 Then
  MsgBox (0)
ElseIf i >= 1 & i <= 10 Or i = 100 Then
  MsgBox ("1~10 or 100")
Else
  MsgBox ("hahaha")
End If

※& 和 Or 可以更進一步的判斷


※迴圈

※Do ~ Loop

Dim i As Integer
'i = 10
Do While i < 10
  i = i + 1
Loop
MsgBox (i)

※至少會跑一次


※For ~ Next

Dim i As Integer
Dim sum As Long

For i = 1 To 10 'Step 1
  sum = sum + i
Next i
MsgBox (sum)

※Step 預設就是 1 了


For i = 1 To 9
  For j = 1 To 9
    Cells(i, j).Value = i & "x" & j & "=" & i * j
  Next j
Next i

※可以嵌套


※For Each ~ Next

For i = 1 To 5 Step 1
    Cells(i, "a").Value = i * 9
Next i

For Each j In Range("A1: A5")
  If j = 36 Then
    GoTo xx
    'Exit For
  End If
  MsgBox (j)
  xx:
Next j

※Exit For 就是 break

※GoTo 到一個標籤,模擬 continue



※Select Case

n = -9
Dim str As String

Select Case n
  Case 1
    n = "a"
  Case 2, 3
    n = "b"
  Case 4 To 6
    n = "c"
  Case Is > 6
    n = "d"
  Case Else
    n = "other"
  End Select
MsgBox (n)

2019年9月10日 星期二

Excel VBA 三 選取、複製、清除內容、總數、常用方法

※選取

Set r = Range("C4: E5")
r.Value = 999
r.Select
'r.Rows(1).Select
'r.Columns(1).Select


分別為 Select、Rows(1).Select、Columns(1).Select
R 橫 C 直

※複製

Set r = Range("C4: E5")
r.Value = 888

'方法一
'r.Select
'Selection.Copy

'Range("A7").Select
'ActiveSheet.Paste

'方法二
Range("A7:C8").Value = r.Value

推薦用方法二比較簡潔有力


※清除內容

Range("A7:C8").ClearContents
'Range("A7:C8").Value = ""



※總數

Set r = Range("C4: E5")
r.Value = 888
Cells(1, "A").Value = r.Count '6
Cells(2, "A").Value = r.Rows.Count '2
Cells(3, "A").Value = r.Columns.Count '3


※常用方法

Cells(4, "A").Value = "abc"
Cells(4, "A").Interior.Color = vbYellow '儲存格背景顏色
Cells(4, "A").Font.Color = RGB(100, 200, 255) '字體顏色
Cells(4, "A").Font.Bold = True '粗體
Cells(4, "A").Font.Italic = True '斜體
Cells(4, "A").Font.Underline = True '底線
Cells(4, "A").Font.Size = 20 '字體大小
Cells(4, "A").ColumnWidth = 20 '儲存格寬度
Cells(4, "A").EntireColumn.AutoFit '自動調整適合的儲存格寬度
'Cells(4, "A").ClearContents '清除儲存格內容
'Cells(4, "A").ClearFormats '清除儲存格非內容的狀態 (背景色、字體色、字體大小…等)

Excel VBA 二 插入按鈕、Cell、Range



1.Insert 有很多的圖形可以控制,這裡以左上角的按鈕為例




2.選完第一張圖的按鈕後,在 Excel 工作區隨便畫一個長方形,如此圖的上半部分
滑鼠放開後,就會看到下半部分
然後名稱預設是 CommandButton1,想改名可按上圖的下半部分操作



3.第一和第二張圖都有個 View Code 可到這個畫面來,然後打程式碼
Private Sub CommandButton1_Click()
  Cells(2, "B").Value = "haha"
  MsgBox ("insert" & vbNewLine & "success")
End Sub
打完按三角按鈕即可執行



4.此時按鈕就可以按了,但發現按右鍵沒反應,此時可以發現 Properties 是灰色的
按下橘框的 Design Mode,會發現 Properties 又可以用了且按右鍵也可以了


※Cell、Range

Cells(1, "A").Value = 123  '第二個參數用數字也可以;1就是A,2就是B,依此類推
Cells(2, "B").Value = "haha"

Range("C3").Value = "I'm C3"
Range("C4: E5").Value = "c4-e5"
Range("C4: E5, A7: B13, G1").Value = "yeah"

以上是針對當前工作表,如果想控制其他的工作表可用如下三個方法:

Worksheets("Sheet1").Range("A2").Value = "A7"
Worksheets(1).Range("A3").Value = "A3" 'Worksheets.Count
Sheet1.Range("A4").Value = "A4"


如上圖右邊,Sheet1 和 Sheet2 都是 Excel 幫我們定好的,後面的括號是別名,會對應到上圖左邊下面的名稱
注意 Sheet2 的別名是 Sheet1

第一種是用別名的方式
第二種是以上圖左邊下面去算的,最左邊的 xxx 是1,Sheet1 是 2,但滑鼠按著其中一個去換,是可以換的,這時順序會改變,所以這種方法不推薦
第三種是用 Excel 幫我們定好的名稱
使用 Worksheets.Count 可以知道有幾張工作表

※Range 的另外一種用法

Range("xxx"),裡面的 xxx 可以自己定義,方法如下:


1.這次使用的不是 Developer 了,是 Formulas



2.Scope 是工作表的別名,橘框按了以後視窗會變小,這時在 Excel 拉需要的範圍即可,如果要多個範圍,就按 Ctrl



3.在左上角打上自己取得名稱,就會反白範圍



4.這個畫面可以編輯和刪除,但 Scope 不能改