How to Run Spring Boot Application in a Docker Container

首先如平時作法、將寫好的專案生成 jar 檔。

  1. Maven – Clean
    http://idea0816.synology.me/wordpress/wp-content/uploads/2022/11/Maven發佈1.jpg

  2. Maven – Package
    http://idea0816.synology.me/wordpress/wp-content/uploads/2022/11/Maven發佈2.jpg

之前的作法都是先在要運行的主機上安裝好 JRE 後、再執行以下的指令

java -jar webapierp-0.1.jar

現在要在 Docker 上直接運行。先新增 Dockerfile 內容如下(20221226更新):

# jdk版本號
FROM adoptopenjdk/openjdk11:latest
# 工作目錄
RUN mkdir /opt/app
# 添加所有檔案到工作目錄中
COPY webapierp-0.1.jar /opt/app
# port
EXPOSE 9090
# 時區1
RUN apt-get update \
    &&  DEBIAN_FRONTEND=noninteractive apt-get install -y tzdata
# 時區2-胡志明    
RUN TZ=Asia/Ho_Chi_Minh \
    && ln -snf /usr/share/zoneinfo/TZ /etc/localtime \
    && echoTZ > /etc/timezone \
    && dpkg-reconfigure -f noninteractive tzdata 
# 安裝Vim
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y vim
# RUN
CMD ["java", "-jar", "/opt/app/webapierp-0.1.jar"]

將 jar 和 Dockerfile 放在同一目錄下(或是直接將這2個檔案直接上傳到 Server 上)、並執行以下指令(先放圖)。

http://idea0816.synology.me/wordpress/wp-content/uploads/2022/11/截圖-2022-11-10-下午1.53.14.jpg

firstjar 可替換成自己要的名字。特別注意此指令後面有一個「 . 」、沒加上會出錯。

docker build -t firstjar . 

「 -d -p 」或「 -dp 」是為了在後台運行新容器。另外在主機創立 9090 到 容器 9090 的端口映射。

docker run -dp 9090:9090 firstjar

20221226更新:
在 Docker 上線發現有時區問題、所以修改了 Dockerfile。
DEBIAN_FRONTEND=noninteractive:在 Linux 中不需使用者交互。
執行了新的 Dockerfile 會有以下的訊息出現、以確定是否已將時區修正完成:

在 Linux 中也可使用以下指令去修正 Locltime:

# 安裝Vim
RUN DEBIAN_FRONTEND=noninteractive apt-get install -y vim

How to Run ReactJs Application in a Docker Container

踩坑了許多、在查閱眾多文件後;以下為目前最終作法(非最佳)、希望之後可以再讓其更好。

  • 在項目的根目錄下新增 Dockerfile 。

http://idea0816.synology.me/wordpress/wp-content/uploads/2022/11/截圖-2022-11-09-下午7.32.20.jpg

  • 原本寫法會使 image 暴增成近 1G 的檔案;經修改為以下的設定後目前僅有 27MB 左右。
# node 版本號(依開發時所使用的環境選擇為 18 、並加上 alpine 為穩定版)
FROM node:18-alpine as builder
# 建立工作目錄(小寫)
WORKDIR /webbyerp
# 添加所有檔案到工作目錄中
ADD . /webbyerp
# RUN npm install && npm run build && npm install -g http-server(用 ci 替代 npm install)
RUN npm ci && npm run build
# PORT(這裡只是給發布的人知道自己原本的 PORT 接口)
EXPOSE 3000
# CMD http-server ./build -p 3000容器啟動後、執行http-server(用 nginx 取代)
FROM nginx:alpine
COPY --from=builder /webbyerp/build /usr/share/nginx/html
  • 建立完成後就來產出 image 檔(先上全圖)。

http://idea0816.synology.me/wordpress/wp-content/uploads/2022/11/截圖-2022-11-09-下午8.03.29.jpg

  • testimage 可替換成自己要的名字。特別注意此指令後面有一個「 . 」、沒加上會出錯。
docker build -t testimage .
  • 「 -d -p 」或「 -dp 」是為了在後台運行新容器。另外在主機創立 3000 到 容器 3000 的端口映射。後來因為修改成使用 nginx 而非 http-server 、所以我直接改為 80:80 ;當然可以也可以 3000:80 避開主機的 port 80 。
docker run -dp 3000:3000 testimage

結論:
1. 使用 alpine 減少容量。
2. 鎖定 node 版本號:ex: node:18-alpine。
3. npm ci 取代 npm Install 、避免版本問題及提高依賴安裝速度。
4. package.json 單獨添加、充分利用鏡像緩存。
5. 只提取自己撰寫的文作、減小容量。

use Antd for React

選了 Antd 來當做 React 的腳手架、仍在學習熟悉。

安裝:

npm install antd

在官網教學是輸入 npm install antd –save 。後綴的 –save 作用是為了要寫入 package.json 中的 dependencies ;但其實在 npm 5.0 之後就會預設自動加入了、所以我在這裡就去掉不輸入了。

簡易使用:

import { DatePicker } from 'antd';
import 'antd/dist/antd.min.css';

<DatePicker />

在官網教學中、引入樣式是:import ‘antd/dist/antd.css’; 、但這樣會出現如下的錯誤:

經查詢後、需將引入樣式改成 import ‘antd/dist/antd.min.css’; 才不會有錯誤

React App 101

先依這個連結確認在電腦裡已裝好 node & npm 。

打開終端機、輸入:

npx create-react-app myapp

待安裝完成後、打開 Visual Studio Code 並開啟剛建好的資料夾。

public 資料夾中刪除沒用(自認為)的檔案:

src 資料夾中只留 index.js & App.js:

刪除檔案說明:
在 public 資料夾中,create-react-app 生成了一些預設的檔案,像是 logo 圖片和 manifest.json 等,這些檔案通常是用來作為示例或者基本的應用程式設定。對於一個新的應用程式來說,這些檔案可能是不必要的,因此我們可以安全地將它們刪除,以保持專案的簡潔性。

打開 index.html 、將內容精簡如下(自認為):

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta
      name="description"
      content="Web site created using create-react-app"
    />
    <title>React App</title>
  </head>
  <body>
    <noscript>You need to enable JavaScript to run this app.</noscript>
    <div id="root"></div>
  </body>
</html>

index.html 的修改說明:
在 index.html 中,我們對一些標籤和屬性進行了修改和刪除。首先,我們刪除了一些不必要的 meta 標籤和連結,以保持頁面的簡潔性。另外,我們將

放置在頁面的最頂部,這是因為 React 應用程式將會被渲染到這個元素中。而 %PUBLIC_URL%/favicon.ico 是一個指向 favicon 圖標的路徑,這樣瀏覽器就可以正確地載入圖標。

index.js 也精簡如下 :

import React from "react";
import ReactDOM from "react-dom/client";
import App from "./App";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

index.js 的說明:
在 index.js 中,我們引入了 React 和 ReactDOM,這兩個庫是用來建構和渲染 React 應用程式的關鍵庫。我們使用 createRoot 函式將我們的應用程式渲染到了 HTML 文件中的

元素中。值得注意的是,我們使用了 <React.StrictMode>,這是一個用來啟用嚴格模式的元件,可以幫助我們在開發過程中偵測潛在的問題和錯誤。

至於 App.js 我習慣全刪、後續再自己寫碼。

101 大概就這樣囉~

Spring Boot 101 with GitHub

配合 GitHub 創建一個 Spring Boot Project。

  • 先進入到 GitHub 的網頁。點擊 New 按扭去新增一個 Repository。

  • 輸入名稱、並點擊下方按鈕創建。

  • 如果沒有特別去設定 SSH key 的話、就必需得是 https開頭。將此網址複製。

  • 開啟 IntelliJ 、點擊右上角的 Get from VCS 。

  • 貼上剛剛複製的連結並點擊右下角的 Clone 。

  • 先關掉 IntelliJ、進到剛剛 Clone 的資料夾、刪掉 .idea 的隱藏資料夾。

  • 回到 IntelliJ 、選擇 New Project 創建和剛剛相同名稱的 Project 、此時會出現警告視窗、直接 Yes 即可。

  • 在 Dependencies 這裡、依個人所需選擇。(Spring Web, JDBC API, MS SQL Server DRiver)

  • 建立完成後可點擊右下角的 Always Add 、讓 IntelliJ 自動將檔案加到 Git 版本控制下、加好後可看到左邊檔案會變成綠色的狀態。

  • 將以下多餘的檔案刪掉。

  • 設定 pom.xml

<!--SQL2008 https://mvnrepository.com/artifact/com.microsoft.sqlserver/mssql-jdbc -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>mssql-jdbc</artifactId>
            <version>7.2.2.jre11</version>
        </dependency>
<exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
</exclusions>
  • 點選左邊的 Commit 、填入說明、點擊 Commit and Push 進行第一次上傳。

  • 回到 GitHub 上檢查、收工。

jQuery’s GET,POST,PUT and DELETE example

知道很多人不看說明、就想直接 copy 程式碼去測(我說我自己XD);所以先上程式碼、廢話放在後面。

jQuery 版本:jquery-3.6.0.min.js

GET

$.ajax({
    type: "GET",
    contentType: "application/json;charset=utf-8", // 要寫、不然會報 415 Error
    url: "/lbzls/getlbzlsList/" + td[0].innerText,
    dataType: "json",
    success: function (lbzlsList) {
    $.each(lbzlsList, function (key, value) {
        $("#lbzls_getList").append("<tr onMouseOut='this.style.backgroundColor=\"\"' onMouseOver='this.style.backgroundColor=\"#B2C67F\"';>" +
        "<td>" + value.lbdh + "</td>" +
        "<td>" + value.zwsm + "</td>" +
        "<td>" + value.bz + "</td>" +
        "<td>" + value.bz1 + "</td>" +
        "<td class='delCol' style='display: none;'>" +
            "<input class='delColButton' type='button' value='Del' style='font-size: 0.75rem; width: 2rem;' />" +
        "</td>" +
        "</tr>");
        });
    },
    beforeSend: function () {
        $.blockUI();
    },
    complete: function () {
        $.unblockUI();
    },
    error: function () {
        alert("未取得类别明细资料!");
    }
});

POST

// POST-Insert、 创建,会产生新的数据,则用POST
.ajax({
    type: "POST",
    contentType: "application/json;charset=utf-8", // 要寫、不然會報 415 Error
    url: "/lbzls/insertlbzl/",
    data: JSON.stringify({ "oldlbzl": [templbzl], "newlbzl": [lbzl], "newlbzls": lbzlsData }), // 因為jQuery安全性升高、所以要這樣寫
    dataType: "text", // 回傳 String
    success: function (message) {("#content").load("lbzls");
    }
});

PUT

// PUT-Update、更新,并不会产生新的数据,新的数据会覆盖老的数据,用PUT
$.ajax({
    type: "PUT",
    contentType: "application/json;charset=utf-8", // 要寫、不然會報 415 Error
    url: "/lbzls/updatelbzl/",
    data: JSON.stringify({ "oldlbzl": [templbzl], "newlbzl": [lbzl], "newlbzls": lbzlsData }), // JSON傳值
    dataType: "text",
    success: function (message) {
        alertify.success("修改成功!!");
    }
});

DELETE

$.ajax({
    type: "DELETE",
    contentType: "application/json;charset=utf-8", // 要寫、不然會報 415 Error
    url: "/lbzls/deletelbzl/",
    data: $("#textlb").val(),
    dataType: "text",
    success: function (message) {
        alertify.success("删除成功");
    }
});

貼完程式碼,突然也覺得沒什麼好說的;這是 2016 年之後再次把 jQuery 拿出來寫;不為別的、只是因為直至現在 2022 年、一直想學的 React 和 VUE 還是沒學好,所以只好繼續玩最熟的 jQuery 。留下這篇也只是因為發現自己太久沒寫了、很多基本東西(語法、JSON 傳值⋯⋯)都變得很不熟悉。

還是那句話:「不進則退」。

IDEA solved “Wrong tab” Warning Message

其實這個問題的根本就是:在 Java Doc 裡不存在這個標籤、所以只需在設定中新增標籤即可。

注意事項:需在 Default IDE 裡做設定、才不會下一次開新的 Project 時又出現錯誤。

配置路徑如下:
Settings / Preferences -> Editor -> Inspections -> Java -> Javadoc -> Javadoc declaration problems -> Options -> Additional Javadoc tags

IDEA-一劳永逸的解决-Wrong-tag-警告信息

HOW TO RESTORE SQL SERVER ON MAC USING DOCKER

續前篇 HOW TO INSTALL MSSQL SERVER ON MAC USING DOCKER 在安裝完資料庫後;接下來當然就是先還原之前的資料庫、以利後續開發。

sudo docker cp 檔案名 容器名:/var/opt/mssql/backup

在這裡特別強調(因為我犯了這個蠢、還重新安裝了 Container) : 在這裡是輸入本機密碼、不是資料庫的連線密碼

等待一段時間後、將 Docker Container 重新運行(Restart)。再進入 Azure Data Studio 中去連線資料庫。

Selected path 的部份我是用打字的補入後面的 backup 文件夾、這部份應該是因為我之前沒有先建立資料夾就拷貝檔案進去、所以在檔案瀏覽器中是看不到的(待確認)。

The server selected protocol version TLS10 is not accepted

錯誤環境:使用 OpenJDK 11 連線 SQL Server 2008 時,發生了找不到 openjdk 驅動程式無法使用安全通訊端層 (SSL) 加密建立與 SQL Server 的安全連接。錯誤: “The server selected protocol version TLS10 is not accepted by client preferences [TLS13, TLS12]”。 ClientConnectionId:e98d4e86-b063-47d6-8bc7-7e0c482b146d 的結果。

發生原因:眾說紛云。
一、升級至 JAVA11 後、TLSv1 & TLSv1.1 被預設 Disabled。
二、SQL Server 2008 要求加密連線、需更新。

解決方法
在不動到 Server 的情況下,嘗試改寫連線方式及各種無腦測試後、以最簡單的方式解決了。

在 java.security 這個設定檔中,找到 jdk.tls.disabledAlgorithms ,刪掉其中的 TLSv1 、即可連線成功。

TLSv1

  • 在 Google 時發現,很多文章都會寫此檔案放在 %JAVAHOME%\JAVA\jreXXX\lib\security 中、一開始時一直沒找到;後來我反而是在 %JAVAHOME%\jdk-11.0.13.8-hotspot\Conf\Security 中找到的。有可能是因為版本的不同所以導致資料夾不同,有時候多注意一下,以免浪費了不必要的時間。

20230822 Tips:
在 Mac OS 中尋找 Java 安裝位置

/usr/libexec/java_home -v

20240124 Tips:
最近試著升級成 jdk 17 & SpringBoot 3.2.1 時、遇到了以下問題:

“encrypt” 屬性設定為 “true” 且 “trustServerCertificate” 屬性設為 “false”,但驅動程式無法使用安全通訊端層 (SSL) 加密建立 SQL Server 的安全連線: 錯誤: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target。 ClientConnectionId:77468a01-4798-4f83-a45c-b1b4e5833e6b

除了之前把 TLSv1 去除掉之外、需要在 application.properties 中再增加設定:

spring.datasource.driver-class-name=com.microsoft.sqlserver.jdbc.SQLServerDriver
spring.datasource.url=jdbc:sqlserver://127.0.0.1:1433;databaseName=LYS_ERP;encrypt=false

雖然是可以連絡了、但還是會出現以下警告訊息:
TLSv1 was negotiated. Please update server and client to use TLSv1.2 at minimum.

主要問題還是在於 SQL 2008 、就先撐著吧、看何時解決不了不得不升級囉!

How to install MSSQL Server on Mac using Docker

因為開發的原因、所以需要在 Mac 上安裝 SQL Server 。

Docker 官網

下載並安裝 Docker 。

前往 Dockerhub 找到需要的 Image 檔案:

Dockerhub-SQL Server

  • 目前在官網上只看到 2019 & 2017 的版本、所以我選擇了 2017 的版本。

DockerSQLserver

打開終端機(Terminal)、輸入以下指令:

docker pull mcr.microsoft.com/mssql/server:2017-latest

DockerPull

Pull 完後、在剛剛的網頁往下拉一點、會看到執行方法:

Howtouseimage

在終端機在執行以下命令:

docker run -e "ACCEPT_EULA=Y" -e "SA_PASSWORD=yourStrong(!)Password" -p 1433:1433 -d mcr.microsoft.com/mssql/server:2019-latest
  • 要特別注意的是 Copy 下來的命令檔、需先修改密碼(要求強密碼、否則執行會有問題);另外、因為剛 Pull 的是 2017 、所以版本號也必需要改。我在此行命令中另外加上了 –name 讓執行後的名稱變成我想要的。

Setup

以上完成後、開啟 Docker App 、並 Run 剛剛安裝的 Image 就可以啟動了:

RunDocker

取代 SQLServer Mangament 的 Azure Data Studio:

Azure Data Studio

操作介面和 Visual Studio Code 幾乎一模一樣;經測試、雖然連接 SQL 2008 會跳出警告版本不相容,但目前使用起來沒什麼大問題。

AzureDataStudio