2021年4月28日 星期三

The server time zone value '¥x¥_¼Ð·Ç®É¶¡' is unrecognized

這是使用Spring boot 建立資料庫連線遇到的問題

解決方法

在後方加入?serverTimezone=UTC

如果要解決中文亂碼問題

也可以加入?useUnicode=true&characterEncoding=UTF-8

合起來可以 ?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC



2021年4月9日 星期五

工程師三年, 年薪百萬-1 緣起

曾經, 我以為這個目標可能還要兩三年

沒想到有公司如此欣賞我

願意給我這樣的價格

雖然, 我達成了目標, 讓我將這段時間的努力, 寫成文章記錄

一個商學院的學生, 轉職成為工程師的故事

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

背景, 我大學念元智國企, 研究所念銘傳財金

其實並沒有說多強悍

只是研究所期間寫點交易&統計程式

多益拿過890金色證照, 業餘圍棋5段, 當過合唱教學, 小提琴家教

也是在有興趣的領域, 認真專注, 也小有收穫

當初出社會跌跌撞撞並沒有銀行收我, 直到一家會計師事務所

我看這地方有點品質, 是做外商的, 想說, 喜歡投資的這部分

有機會進來加強一下公司會計帳務的知識,沒想到~~

會計太弱了, 只好去做薪資組, 當時我一連管了10多家薪資報表

自以為很厲害, 但是看著各家員工的薪資與自己薪資的差距, 我急了

於是我問當初的部門經理:"如果我在這家公司工作8年10年, 有沒有機會領到8-10萬?"

經理斬釘截鐵地說: "絕對沒有可能"

於是我當下就決定要離職

"這個行業沒機會, 但是其他的有"

看著這些外商給的薪資, 我認為自己並沒有比較差,

只是還找不到哪一種類工作能讓我好好發揮

我到底還能做什麼?


2021年4月8日 星期四

[SpringBoot] properties檔案出現亂碼, Unicode的解決方式

我自己遇到問題的情況

是在接手的專案中

多國語言中有message.properties檔案的問題

內容的字發生問題如下

\u4e2d\u6587\u5b57

解決方式如下

必須去idea中的 file>Settings







記得要將Default encoding改為UTF-8
後面的Transparent native-to-ascii conversion也要勾選起來就能解決

另外idea使用上, ctrl + shift + F




2021年3月17日 星期三

[面試考題] 檢查變位字

考題: 給定兩個字串, 寫一個方法判斷一個是否是另一個的變位字


思維:造一個方法

1 先比較其長度是否相等

2 比較兩個值做順序排序, 內容是否會相等

順序排序:

a 產生一個字元char陣列

b使用Arrays.sort

c產生新的字串


public static void main(String[]args){
System.out.println(permutation("see","ese"));
}
static String sort(String s){
char[]content = s.toCharArray();
java.util.Arrays.sort(content);
return new String(content);
}

static boolean permutation(String s, String t){
if(s.length()!=t.length()){
return false;
}
return sort(s).equals(sort(t));
}


[面試考題] 不重複

考題: 實作一個演算法來判斷一個字串中的字元是否不重複. 如果不能使用其他資料結構怎麼辦?


思維:假設字元有128個, 每一個都有特殊的數字, 因此~

1 造一個布林陣列

2 跑迴圈, 當遇到新的字元數字, 布林陣列[數字] 改為true

3 下一次再來, 如果發現其布林陣列[數字]為true , 代表該字元已經出現過了,

然後整個function就要回傳false



public static void main(String[] args) {
System.out.println(isUniqueChars("abbs"));
}

static boolean isUniqueChars(String str) {
if(str.length() > 128) return false;

boolean[]char_set = new boolean[128];

for(int i =0 ; i < str.length() ; i++) {
int val =str.charAt(i);
System.out.println(val);
if(char_set[val]) {
return false;
}
char_set[val]=true;
}
return true;

} 

2021年2月11日 星期四

[SpringBoot 1.5] 引入靜態頁面相關問題及使用fragment

引入靜態頁面的時候

我們原本可能會使用

<link rel="stylesheet" href="../../static/css/me.css">

這個語法在模板templates(有引入thymeleaf)下, 並不能讀取到









因此~需要改為

<link rel="stylesheet" href="../../static/css/me.css" th:href="@{/css/me.css}">

用th:href="@{}"來引入資源

然後重新build再刷新頁面就沒問題了






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

使用fragment

1 首先產生一個html檔案命名為_fragments

2 然後我們將大部分頁面上會重複的程式碼複製到這頁面

ex

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>博客詳情</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<link rel="stylesheet" href="../static/css/typo.css">
<link rel="stylesheet" href="../static/css/animate.css">
<link rel="stylesheet" href="../static/lib/prism/prism.css">
<link rel="stylesheet" href="../static/lib/tocbot/tocbot.css">
<link rel="stylesheet" href="../static/css/me.css">
</head>


3 將引入方式修改為th:href="@{}"

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<link rel="stylesheet" href="../static/css/typo.css" th:href="@{css/typo.css}">
<link rel="stylesheet" href="../static/css/animate.css" th:href="@{css/animate.css}">
<link rel="stylesheet" href="../static/lib/prism/prism.css" th:href="@{/lib/prism/prism.css}">
<link rel="stylesheet" href="../static/lib/tocbot/tocbot.css" th:href="@{/lib/tocbot/tocbot.css}">
<link rel="stylesheet" href="../static/css/me.css" th:href="@{/css/me.css}">


4 將重複的片段掛上fragment

<head th:fragment="head(title)">


5 如果遇到每個頁面有共通元素, 但是內容不一樣,

例如 <title>博客詳情</title>

這時候我們就要使用傳參數的方式(注意取參數要用$)

<head th:fragment="head(title)">
<title th:replace="${title}">博客詳情</title>
</head>

這樣來做搭配


6 而在要引入的頁面(比方說index.html)

我們可以這樣做, 這樣就是將title裡面的參數傳遞過去

<head th:replace="_fragments :: head(~{::title})">


完整的程式碼:

_fragments.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml">
<head th:fragment="head(title)">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title th:replace="${title}">博客詳情</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<link rel="stylesheet" href="../static/css/typo.css" th:href="@{css/typo.css}">
<link rel="stylesheet" href="../static/css/animate.css" th:href="@{css/animate.css}">
<link rel="stylesheet" href="../static/lib/prism/prism.css" th:href="@{/lib/prism/prism.css}">
<link rel="stylesheet" href="../static/lib/tocbot/tocbot.css" th:href="@{/lib/tocbot/tocbot.css}">
<link rel="stylesheet" href="../static/css/me.css" th:href="@{/css/me.css}">
</head>
<body>

</body>
</html>


index.html 的header

<head th:replace="_fragments :: head(~{::title})">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>博客</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/semantic-ui@2.4.2/dist/semantic.min.css">
<link rel="stylesheet" href="../static/css/me.css" >
</head>


2021年2月2日 星期二

[SpringBoot 1.5] AOP概念及日誌範例

關於橫切面AOP的思維

個人的領會是, 在程式進行的流程為一個直向的流層, 但是, 如果要在其中幾個物件被使用的時候,都插入一段程式碼, 這種的思想就是橫切面設計, 

具體的範例, 是一種鑲嵌, 縫合程式碼的思維, 比方說在每一次從某些controller的時候都警示該功能已經被呼叫, 就是都額外run一段程式碼, 如果說要在每個controller上面加上這段, 就是一個麻煩的事, 如果我們在後面才設計出要被加入的這段程式碼, 那還不如能用縫合的, 將其呼叫的時機設定好, 然後不用每個controller都重新鑲入該程式碼, 那這下面會有些關鍵字的思維可以釐清


1 切面Aspect

切面是一個模塊關注點的模塊化, 他由切入點PointCut和通知Advice組成

@Aspect
@Component
public class LogAspect {
}


2 目標Target

將要被縫合的類別, 比方說, 我們就設計了一個controller, 等下測試縫合程式碼的執行順序

@Controller
public class IndexController {

@GetMapping("/{id}/{name}")
public String index(@PathVariable Integer id, @PathVariable String name){
System.out.println("~~~~~~~~~~~~index~~~~~~~~~~");
return "index";
}
}


3 連接點JoinPoint

被視為切入連接點, 是下列範例中的log()方法


@Before("log()")
public void doBefore(JoinPoint joinPoint){
 logger.info("~~~~~~~Before~~~~~~~");
}


4 切入點PointCut

而切入點則是下面括號中指定execution中的東西,* 是指說返回任何東西

 com.lrm.web.*.*(..)是AOP要切入的對象, web後面*表示任何類,第二個*表示任何方法

而(..)表示任何參數, 當然也可以使用web.IndexController 這樣就只有這個Controller會被

橫切插入程式

@Pointcut("execution(* com.lrm.web.*.*(..))")
public void log(){
}


5 通知Advice

有不同被通知的種類, 比方說Before, After, 

@Before("log()")
public void doBefore(JoinPoint joinPoint){
 logger.info("~~~~~~~Before~~~~~~~");
}

@After("log()")
public void doAfter(){
logger.info("~~~~~~~After~~~~~~~");

}


6 織入Weaving

將切面Aspect與對象Target連接起來, 織入可以在類別加載的的時候完成, 也可以在編譯, 或是運行的時候完成...如果是編譯時完成就是靜態代理, 如果在運行時完成就是動態代理

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

以下是一個完整的程式碼

會設計一個內部類別, 然後將其Url, ip, 目標的物件名稱及參數都印出來

package com.lrm.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;

@Aspect
@Component
public class LogAspect {

private final Logger logger= LoggerFactory.getLogger(this.getClass());
@Pointcut("execution(* com.lrm.web.*.*(..))")
public void log(){

}

@Before("log()")
public void doBefore(JoinPoint joinPoint){
logger.info("~~~~~~~before~~~~~~~");
ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request=attributes.getRequest();
String url =request.getRequestURL().toString();
String ip=request.getRemoteAddr();
String classMethod=joinPoint.getSignature().getDeclaringTypeName() + "." +joinPoint.getSignature().getName();
Object[] args= joinPoint.getArgs();
RequestLog requestLog= new RequestLog(url,ip,classMethod,args);
logger.info("Request : {}",requestLog);
}

@After("log()")
public void doAfter(){
logger.info("~~~~~~~After~~~~~~~");

}

@AfterReturning(returning = "result" , pointcut = "log()")
public void doAfterReturn(Object result){
logger.info("Result: {}",result);
}

private class RequestLog{
private String url;
private String ip;
private String classMethod;
private Object[] args;

public RequestLog(String url, String ip, String classMethod, Object[] args) {
this.url = url;
this.ip = ip;
this.classMethod = classMethod;
this.args = args;
}

@Override
public String toString() {
return "RequestLog{" +
"url='" + url + '\'' +
", ip='" + ip + '\'' +
", classMethod='" + classMethod + '\'' +
", args=" + Arrays.toString(args) +
'}';
}
}
}

再搭配上前面的IndexController, 開啟然後輸入 http://localhost:8081/1/hat

後面兩個參數是先隨意給的, 以下是結果的截圖




參考網址:

https://zhuanlan.zhihu.com/p/60842627

https://matthung0807.blogspot.com/2018/02/spring-aop.html

AI 時代的軟體工程

  AI 時代的軟體工程:從「代碼寫手」到「系統指揮官」的轉型之路 2026 年,軟體工程正經歷自編譯器發明以來最大的範式轉移。AI 不再只是 IDE 側邊欄的輔助工具,而是進化為具備自主性的 Agent(代理人) ,這場變革正重新定義「工程師」的核心價值。 一、 現狀:AI 普...