2022年3月31日 星期四

React打包排除

當React資料夾, 放在SpringBoot專案下面的時候

他在run Maven install的時候

整包會被複製到Target中

這樣整個操作過程會相當緩慢

如果要避免這個複製的動作可以在pom檔中build加入以下






<resources>

<resource>

<directory>src/main/resources</directory>

<excludes>

<exclude>react/**</exclude>

</excludes>

</resource>

</resources>

2022年3月24日 星期四

table 去邊框 + 組合

 這次的需求是寄出信件,

但是信件內容是html組成如下







一開始覺得麻煩, 乾脆都弄表格的

因為不知道去邊框怎麼弄成這種格式

後來有想法

只要都只留下橫線的部分,  另外把外框去掉, 就可以形成外面的部分

另外, 中間就再弄個3X3 table出來就好了

去外框可以用 frame=void

都使用橫線可以用 rules=rows

<html> 
<head> <title> TABLE 範例程式 </title> </head>
<body> 
<table BORDER="5"WIDTH="680" frame=void rules=rows> 
<tr></tr> 
<tr><td COLSPAN="8" align="center">雲端腎臟病照顧平台訊息通知[庫存量]</tr> 
<tr><td COLSPAN="6">訊息來源<td COLSPAN="4">[台北透析診所]雲端腎臟病照顧平台</tr> <tr> <td COLSPAN="8">
<p>訊息內容</p>
 <table border=4 align=center width=80% cellspacing=5 cellpadding=6 rules=none frame=void> 
<tr> <td>商品代號</td> <td>品項名稱</td> <td>目前庫存量</td> </tr> 
<tr><td>12345678</td><td>安全穿刺針17G</td><td>10</td></tr> 
</table> 
<p>本信件為系統自動寄出,請勿直接回覆</p> 
</td></tr> 
<tr></tr> 
</table> 
</body> 
</html>

結果








參考
https://www.twblogs.net/a/5b7f41f82b717767c6aea0a3
https://blog.csdn.net/tobebetterprogrammer/article/details/52527441
https://www.w3schools.com/html/html_tables.asp
http://mirlab.org/jang/books/html/table.asp?title=3-2%20%AA%ED%AE%E6%20(Tables)
https://www.itread01.com/content/1549340291.html

2022年3月10日 星期四

timestamp 查詢某月份資料

這裡timestamp和timestamp with time zone都可以處理

Select * From patient_examine_order where to_char(sampling_date, 'YYYYMM') like '202102%'

可以使用to_char再搭配like組字做使用

超難的阿~~

https://www.postgresql.org/docs/9.6/functions-formatting.html

2022年3月9日 星期三

想把興趣當工作? 何不反過來看

https://www.gvm.com.tw/article/73791

整篇圍繞著興趣不能當工作, 及為何興趣不能當工作在走

凸顯各種, 不能....因為....

這種思維是不會使一個人進步的


何不反過來看

為何不能把工作當興趣?

工作真的不能當興趣嗎?

本文開始

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

職涯發展中, 總是有時候在高峰, 有時候在低谷, 沒有人是永遠在顛峰

好像有種循環, 

不知道從什麼時候開始,

我好像在期待下班, 在期待下一次發薪水, 期待下一個月, 我存款裡的數字增加不少,

期待早上看著自己帳戶的股票成長, 而對於工作, 進修, 什麼的, 一點興趣也沒有?

像這樣的想法我相信一般工作者或多或少都有過這樣的心情,

有的人找方法轉念, 上些心靈成長的課, 有的人藉由假日的休閒, 轉換工作狀態,

和朋友一起去吃吃喝喝, 唱唱歌, 舒緩一下壓力,

也有的人參加讀書會, 獲得一些正面力量, 再回來面對工作

不禁讓人思考

我現在的工作, 真的是我的興趣嗎?

或是, 為何我感興趣的事變成工作, 我就對它厭煩?


的確, 是有可能工作久了, 我逐漸對我的工作開始厭煩

但是原因真的是因為"工作"嗎?

如果仔細去探究其根源, 其實真正令你厭煩的, 另有其他東西


比如, 公司內部走一個高壓, 需要高效的產出, 

使得你不得不占用下班的休息時間去完成公司所安排的任務, 

在付出與薪水極度不平衡之下, 你厭惡這份工作

更準確地說, 

你厭惡的並不是工作, 

而是公司習慣榨乾你最後一分力氣的文化

你下意識地將工作和累進行了連結, 

而實際上, 或許有另外一份工作不用你"這麼累"

只是這公司對你的安排, 使你"這麼累"


又比如, 上司對你極其嚴厲, 你常常被上司定, 

同事對你的評價也差, 覺得你就是個毫無用處的大叔, 

看你的眼神中充滿著不屑, 

在公司裡充滿著挫折, 

沒成就感, 

公司外,

又缺乏自信, 交不到女朋友, 

因此, 你就認為, 這份工作你沒興趣, 

因為這工作令你感到自己

是一個魯蛇, 

但是, 真的是工作造成你這麼負面的嗎? 

是這工作害你交不到女朋友嗎? 

是這工作讓你人生失敗嗎? 

不, 更有可能是性格上, 

漫不經心, 常常丟三落四, 被上司盯上, 

另外一面, 人際關係也差, 

不懂得和同事怎麼相處, 

只知道抱怨主管,

抱怨工作, 

然後就被同事白眼了, 列為黑名單

這是工作的問題嗎? 

是不是只有"你"才發生問題?

然而你為了讓自己好過點, 

於是就說"這工作真是令我厭煩", 

然後對工作一點興趣也沒有, 

下班只想要各種放鬆跟休息, 

但是真正的問題是工作嗎?

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

這裡, 我不想要給什麼喝起來好喝, 一點用處都沒有的雞湯

好讓你感覺很好, 然後接受現狀, 就這樣下去


我們不如反過來想

是我決定"工作"成為厭煩的事

是我決定"把興趣"當成藉口

是我決定當遇到所有挫折的時候都用這句"工作不能當興趣"做擋箭牌

我就是這些事情的主宰

我需要對這些事情付完全的責任

因為"這是我的人生", 即使我因他人或其他事影響

"所有做決定的都是我"

上面這句話, 你覺得論述如何?

如果你覺得並沒有說錯

那我可以大膽的說


我可以"把工作當興趣"

我可以"把提早做完工作當成就"

我可以"把bug數減少當作遊戲分數"

我可以"改善自己的人際關係"

我可以"使上司對我改觀"

如果我的一切事情, 都是我可以決定的,

那我也可以決定要這樣做, 要這樣想


其實, 事實就是這樣

我們在想很多藉口的時候, 只是我們想逃避那要付出的成本

但是當我們去做的時候, 就發現事情沒我們想得那麼難

我得承認的確有些事情很難, 但是我認為當我們"只有想想", 很容易就把事情想難了

也不得不說

其實有些事情, 會需要去學點方法, 

和前輩請教, 會降低許多難度

但是這些都不及

"你真的想去這麼做"


如果你真的想把工作當興趣, 

你基本上就會思考, 怎麼去克服其中的難點,

很多的難點, 還是在自身身上, 

是溝通需要改善, 是想法要再開拓點, 是面對事情態度

當我想著, 我提早做完, 把事情做好, 對我來說是無比喜悅

當我有時間整理好運用的技術, 我從一個個項目有新的學習

就好像遊戲中蒐集武器入庫一樣愉悅

當我從工作中, 發現那些優秀的code, 優秀的人經營的github

我感到世界是如此廣闊, 帶著感謝運用著他人已經為我寫好的範例

誠心的感謝google帶來的便利

在下班的時候, 因今天的進度而感到充實, 因今天的見聞而覺得自己有所成長

而去鍛鍊身體, 使工作能更專注, 而去學習說有趣的話使同事感覺舒壓

我可以做的事情, 就遠遠比我消極的領薪水來的多


更何況.....薪水不少........未來還會更多的時候........

然後自己又會投資把錢翻倍的時候.........

是不用想著有錢之後我要做什麼什麼什麼, 那只會令自己期待著下班, 領下個月薪水

還不如這樣想

為何不能把工作當興趣?

工作真的不能當興趣嗎?


參考閱讀: 

被討厭的勇氣

參考課程: 

超越魅力 第二階段 負責任模式

超越魅力 第三階段 團隊貢獻度







2022多益線上家教 版本202203

地點線上 Teams

教學課程 多益, 生活會話, 外商面試


*具有多年讀書會經驗

*聽力滿分

*懂得如何從低分群準備到高分群

*多次考試經驗, 並從準備考試中建構會話基礎


主教多益聽力部分,以及準備方法

每周上課1小時,會出一天份量的回家作業

藉由每周進度,幫助久未接觸英文的工作人

找回英文的熟悉度,並累積英文基礎能力

養成良好的學習模式


主要分為四階段

1階段: 發音矯正, 句型累積, 單字記憶

2階段: 簡易生活會話應用

3階段: 多變情境應用

4階段: 英文面試情境準備


目前進度: 多益第二大題

目前人數:8

程度: 多益 500-700


地點:Teams 線上

時間:周日 晚上8:20 - 10:00

收費:300(失業者 or 為人父母者 收費100)

收費方式:轉帳

聯絡方式 : 站內私訊,或是line: iw5420 

教材:由老師提供,也可自行購買課本

資料表存JSON格式文字

把JSON存進資料庫的欄位, 要做以下的設置



@Entity(name = "patient_xxx")
@TypeDef(name = "json", typeClass = JsonType.class)
public class PatientXXX {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    // 傳送Json內容
    @Type(type = "json")
    @Column(name = "content", columnDefinition = "json")
    private String content;
...
}

另外, 接值進來的時候, 要用ObjectMapper轉成字串




    @PostMapping("/lab/PutStatus")
	 public JwtResponseResult putStatus(@RequestBody PutStatusRequestVo putStatusRequestVo) {
    	
    	try {
    		ObjectMapper mapper = new ObjectMapper();
       	  String jsonString = mapper.writeValueAsString(putStatusRequestVo);
       
        	labService.updatePatientExamineOrder(putStatusRequestVo.getExamList());
        	labService.recordCallApiLog(
        		putStatusRequestVo.getLab_id(), 
        		jsonString, 
        		PatientExamineLogEnum.Receive.getCode(),
        		"OK");
        
		} catch (Exception ex) {
			ex.printStackTrace();
			return new JwtResponseResult("fail", messageHelper, "common.error", ex.getMessage());
		}
		return new JwtResponseResult("ok", null);
	 }

***如果直接VO.toString()的話, 是沒辦法列印成做成JSON結構的

Java String 轉 localdatetime yyyyMMddHHmmss 格式


import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
public class LocalDateTimeTest {
	
	@Test
	void test() {
		String datetimestr ="20210212111022";
		DateTimeFormatter formatter= DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
		LocalDateTime datetime = LocalDateTime.parse(datetimestr, formatter);
		System.out.println(datetime);
		
		DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
		String datetime2 = datetime.format(formatter2);
		System.out.println(datetime2);
	}

}

2022年3月6日 星期日

使用RestTemplate請求Token

參考了幾篇文章, 直接拿來用, 然後就.....掛掉

真是不靠譜, 還是自己寫一篇好

根據下列這篇

https://www.baeldung.com/spring-resttemplate-post-json

基本上傳過去的內容是可以用Json物件

不過~他其實也可以傳自定義物件

所以我們就拿自定義物件來做示範


這是要傳過去的物件


public class JwtUserExternal {
	
	private String account;
	private String pwd;
	...
}

在開始的地方先注入


	@Autowired
	RestTemplate restTemplate;

要在Config也加入Bean就是, 不然會報java.lang.IllegalStateException: Failed to load ApplicationContext錯誤


	@Bean
	public RestTemplate getRestTemplate() {
		return new RestTemplate();
	}

因為URI是從資料庫取出來, 我們化名為Target

然後從Target對象中取出帳號密碼, 生出JwtUserExternal物件

然後就~call sendRequestForToken function, 把Url和物件傳過去, 取得Token


	public String getToken(String LabId) {
		Target target = targetRepo.findById(Id);
		if (target == null) {
			throw new ICUmodelJwtException(HttpStatus.NOT_FOUND, "patientExamin not found");
		}
		JwtUserExternal jwtUser = new JwtUserExternal(target.getTokenId(), target.getTokenPassword());
		String token = sendRequestForToken(patientExamine.getTokenUrl(), jwtUser);
		return token;
	}

打對方API細節

這裡先生出HttpHeader, 再用它和傳送物件生出HttpEntity為request

然後使用restTemplate.postForObject(url, request, String.class)

將回傳值用使用ObjectMapper轉成JsonNode

目前回傳格式是這樣

{
    "CODE""OK",
    "TOKEN""eyJhbGciOxxxxxxxxx"
}

因此就root.path("TOKEN").asText()就能拿出Token


	public String sendRequestForToken(String url, JwtUserExternal requestObject) {
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			HttpEntity<jwtuserexternal> request = new HttpEntity<jwtuserexternal>(requestObject, headers);
			String personResultAsJsonStr = restTemplate.postForObject(url, request, String.class);
			ObjectMapper objectMapper = new ObjectMapper();
			JsonNode root = objectMapper.readTree(personResultAsJsonStr);
			return root.path("TOKEN").asText();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}
	

完整的類別如下



@Service
public class JwtLogin {

	@Autowired
	RestTemplate restTemplate;

	@Autowired
	TargetRepo targetRepo;

	private String targetId;

	public String getToken() {
		String token = getToken(this.getLabId());
		return token;
	}

	public String getToken(String id) {
		Target target = targetRepo.findByTargetId(id);
		if (target == null) {
			throw new ICUmodelJwtException(HttpStatus.NOT_FOUND, "target not found");
		}
		JwtUserExternal jwtUser = new JwtUserExternal(target.getTokenId(), target.getTokenPassword());
		String token = sendRequestForToken(target.getTokenUrl(), jwtUser);
		return token;
	}

	public String sendRequestForToken(String url, JwtUserExternal requestObject) {
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			HttpEntity<JwtUserExternal> request = new HttpEntity<JwtUserExternal>(requestObject, headers);
			String personResultAsJsonStr = restTemplate.postForObject(url, request, String.class);
			ObjectMapper objectMapper = new ObjectMapper();
			JsonNode root = objectMapper.readTree(personResultAsJsonStr);
			return root.path("TOKEN").asText();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public String getTargetId() {
		return targetId;
	}

	public void setTargetId(String targetId) {
		this.targetId = targetId;
	}

}

重構以上程式碼

差異部分,直接傳Json物件過去

重構的點是因為, 有可能來源來自於不同Table

我們對前面邏輯, 開放新增方法, 可以自行新增將JwtUserExternal set進來

也就是如果他從其他來源來, 可以新增一個類似setTargetId, 只要將JwtUserExternal設到成員變數就可

對後面邏輯封閉, 傳參JwtUserExternal類讓他可以打API, 來取回Token

新增方法上符合開閉原則

JwtUserExternal類別


public class JwtUserExternal {
	
	private String account;
	private String pwd;
	private String url;
	...
		
}

主程式


@Service
public class JwtLogin {

	@Autowired
	RestTemplate restTemplate;

	@Autowired
	PatientExamineRepo patientExamineRepo;

	private JwtUserExternal jwtUserExternal;
	

	public String getToken() {
		String token = sendRequestForToken(this.getJwtUserExternal());
		return token;
	}
	
	public void setTargetId(String targetId) {
		Target target = targetRepo.findByTargetId(targetId);
		if (target == null) {
			throw new ICUmodelJwtException(HttpStatus.NOT_FOUND, "target not found");
		}
		this.setJwtUserExternal(new JwtUserExternal(
						target.getTokenId(),
						target.getTokenPassword(),
						target.getTokenUrl())
				);
	}

	public String sendRequestForToken(JwtUserExternal jwtUser) {
		try {
			HttpHeaders headers = new HttpHeaders();
			headers.setContentType(MediaType.APPLICATION_JSON);
			JSONObject requestObject = new JSONObject();
			requestObject.put("account", jwtUser.getAccount());
			requestObject.put("pwd", jwtUser.getPwd());
			HttpEntity<String> request = new HttpEntity<String> (requestObject.toString(), headers);
			String personResultAsJsonStr = restTemplate.postForObject(jwtUser.getUrl(), request, String.class);
			ObjectMapper objectMapper = new ObjectMapper();
			JsonNode root = objectMapper.readTree(personResultAsJsonStr);
			return root.path("TOKEN").asText();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	public JwtUserExternal getJwtUserExternal() {
		return jwtUserExternal;
	}

	public void setJwtUserExternal(JwtUserExternal jwtUserExternal) {
		this.jwtUserExternal = jwtUserExternal;
	}	

}

2022年3月4日 星期五

spring boot 後端 i18n

Spring boot 其實有自動配置好

因此只需要注入MessageSource就可以使用了



而~i18n檔案的目錄

可以從application.properties檔案中做控制

例如:

spring.messages.basename=static/i18n/report

這個是從resource下面開始的路徑








後面~我們檔案名稱就為report

多國檔就會為report_xxx


@Autowired
    private MessageSource messageSource;
    
    @Test 
    void test() {
    	String s1 = messageSource.getMessage(
            "demo.message", 
            null, 
            Locale.ENGLISH);
    	System.out.println(s1);

       	String s2 = messageSource.getMessage(
                "demo.message", 
                null, 
                Locale.TAIWAN);
        System.out.println(s2);
  
    }

在多國文字檔案的部分如下










run的結果如下





另外~我們可以發現, 他原生的用法, 參數多又麻煩
所以, 我另外寫了一個helper把它簡化
只要一開始設定完語言, 使用的時候就只要getMessage一個參數就搞定
寫好的內容如下, 裡面還有一個邏輯是圖片的邏輯
比方說中文版, 我們就原圖, 英文版我們使用英文版的圖, 圖檔名結尾為_en
這樣, 方便我們getImage取得相對應的路徑
程式碼如下




@Service
public class ReportHelper {
	
	   @Autowired
	   private MessageSource messageSource;
	   
	   private Locale locale;
	   
	   public String getMessage(String name) {   	
	    	return messageSource.getMessage(name, null, locale);
	    }

		public Locale getLocale() {
			return locale;
		}

		public void setLocale(Locale locale) {
			this.locale = locale;
		}   
		
		public String getImagePath(String path) {
			String suffix="";
			if(locale.equals(Locale.TAIWAN)) {
	        	suffix="";
	        } else {
	        	suffix="_en";
	        }
			return path + suffix;
		}

}

使用如下


    @Autowired 
    private ReportHelper reportMessage;
    
    @Test
    void utilTest() {
    	reportMessage.setLocale(Locale.TAIWAN);
    	String s2 = reportMessage.getMessage("demo.message");
    	System.out.println(s2);
    }

最後~如果有超過一種以上的多國檔要注入只要在application.properties檔案用逗號隔開就好

ex


# i18n
spring.messages.basename=static/i18n/report, static/i18n/message

安裝nvm, node

為何要安裝呢? 
因為現在專案開始有使用到React, 
有React包 但是他的相依套件, 
並不會上到gitlab 所以, 在打包之前要先載入相關套件, 
build完 再run maven install產生jar檔 
那要使用 
npm i 
npm build 
可以先下載nvm再用其下載node 
https://github.com/coreybutler/nvm-windows

步驟如下








然後~在3做完後~是有一個小坑, 就是
windows他預設安裝路徑是在user下面
是很有可能被擋到的(以至於nvm install版號, 沒反應)










這個時候就換個資料夾來安裝就好
我是直接放D巢







安裝完之後~
在command打一下 nvm version
出現以下就OK






然後~可以上到node官網看一下版號16.14.0 












然後在回到command下 nvm install 16.14.0
他就會開始安裝node 16.14.0 版本

安裝完之後要輸入nvm use 版本號
這時~第二個小坑來了, 這裡他可能會出現亂碼
你就要採取以下作為解決





或是用系統管理員身分啟動command會進到一樣的路徑
然後 輸入 nvm use 版號
這樣就能run了
然後~當拉下新專案時
進入到reat資料夾
在command 輸入 
npm i
完後輸入
npm build
就可以進行後面spring boot 專案打包


[leetcode] [KMP] KMP

ABCDABD... ABCDABF... 簡單的說, 傳統解兩字串匹配部分 可能會來個雙迴圈, 哀個比對, 當不匹配的時候, 會將下方列再後移1位 然後不匹配再後移 然而 如果像上放已經有4個屬於匹配的字串, 她就應該直接往後移四位來匹配, 而不是只移動1位 隱藏的思維是, 當...