Angular ว่าด้วยเรื่อง Build

 bb

Working Software คือ เป้าหมาย

สำหรับการพัฒนา Software มันจะมีขั้นตอนในการแปลง source code และ resources ต่างๆให้ออกมาเป็น “ของ” ที่พร้อมที่จะ deploy เป็นระบบที่ทำงานได้จริง (Working Software) เราเรียกกระบวนการนี้ว่า การ “build” ซึ่งไอ้การ build แต่ละครั้งเราก็มีเหตุผลที่ต่างกันไปเช่น เพื่อทดสอบระหว่างการพัฒนา เพื่อให้ QA ทดสอบ UAT หรือ Go live ใช้งานจริงๆ

สำหรับ Angular เรานิยมใช้ Angular CLI เพื่อช่วยทั้งสร้างโปรเจค สร้าง source code และแน่นอนรวมทั้ง build ของด้วย เราจะไปดูว่ามันจะช่วยเรา build ได้แบบไหน ยังไงบ้าง 🙂

แล้ว Angular CLI มี build แบบไหนบ้าง ?

ปกติเราจะ build ตาม environment ต่างๆกันไปตามที่ออกแบบ เช่นอาจจะแบ่งเป็น alpha, beta, prod แต่ถ้าจะให้แยกตามลักษณะ output ที่ออกมาจะแยกออกเป็น 2 แบบคือแบบ dev กับ prod การทดลองนี้จะลอง ng new ngdemo โง่ๆขึ้นมาตัวนึง แล้วมาลอง build ดูกันว่าจะได้ผลกันยังไง

Build สำหรับการพัฒนาระบบ

ng buld —dev

Screen Shot 2560-06-19 at 11.29.53 PM

Screen Shot 2560-06-19 at 11.32.53 PM

เวลาเรา build ด้วย option นี้ เราจะได้ประโยชน์คือเราจะได้ source mapping มาด้วย (สังเกตุขนาดไฟล์ vendor.bundle.js ที่ได้มาหลัก MB เลย) ดังนั้นเวลาเราพัฒนาแล้วเกิดเจอ error อะไรมันก็ยังกลับจุดทีมีปัญหาได้ว่ามาจากตรงไหนไฟล์ไหนนั้นเอง

Build สำหรับใช้งานจริง

ng build —prod

Screen Shot 2560-06-19 at 11.34.59 PM

Screen Shot 2560-06-19 at 11.35.26 PM

สิ่งแรกที่อยากให้สังเกตคือจะเห็นว่าขนาดไฟล์ลดขนาดไปพอควร โดยเฉพาะ vendor.xxx.bundle.js ลดลงจากหลัก MB ไปหลัก 3xx kB เพราะการ build ด้วย option นี้จะตัดสวนของ source mapping ออกไปนั้นเอง

อย่างที่สองที่อยากชวนดูคือ ชื่อไฟล์ มันจะมีตัวอักษรแปลกๆแปะมาระหว่างชื่อไฟล์ ตัวอักษรแปลกๆพวกนี้คือ hashing ที่ได้จากไฟล์นั้นๆ ถ้าไม่มีการแก้ไขในไฟล์ hash ที่ได้ก็จะได้เลขเดิมเสมอ ซึ่งมันจะช่วยในเรื่อง browser caching นั้นเอง

ต่อมาที่น่าสนใจคือ styles.bundle.js ถูก extract ออกมากลายมาเป็น styles.xxx.bundle.css แทน ก็เพื่อใช้แสดงผลตามปกติของ css ที่มันควรจะเป็น

นอกจากนี้เวลา build แบบ prod นี้ยังมีเรื่องการ Ahead-of-Time Compilation อีก ดังนั้นเวลาเราต้องการ build ของสำหรับใช้งานจริงควรจะใช้ option นี้

ตารางเปรียบเทียบ –dev กับ –prod

Flag --dev --prod
--aot false true
--environment dev prod
--output-hashing media all
--sourcemaps true false
--extract-css false true

สรุป

ก็น่าจะเห็นภาพมาขึ้นสำหรับเรื่องการ build โปรเจคทั้ง 2 แบบด้วย ng build ของ Angular CLI เหมือนเดิมครับ ถ้าใครมีเทคนิคแจ่มๆเอามาแบ่งกันได้นะครับ สวัสดีครับ (-/\-)

อ้างอิง : https://github.com/angular/angular-cli/wiki/build

Advertisements

เพิ่มความสนุกในการเขียน Angular ด้วย HMR (Hot Module Replacement)

299673_10151471144320809_1119982299_n

ปัญหาในการพัฒนา Angular

ผมเคยฟัง คุณจั๊ว ในหัวข้อ Hyper Productivity ด้วยสมองผมที่มีรอยหยักจำกัดเลยจำอะไรไม่ค่อยได้มากนัก แต่สิ่งที่จำได้ลางๆ คือ

การทำงานมันจะอยู่ในสภาวะไหลลื่น(Flow) นั้นการตอบสนอง(Feedback loop) ต้องสั้นทันใจ

การพัฒนาระบบก็เหมือนกันถ้าเรารู้ว่าสิ่งที่เราแก้ไขไปมันถูกต้องได้ไวขึ้นมันก็น่าจะทำให้ Productivity ดีขึ้นด้วย กลับมาที่ Angular ปัญหาอย่างนึงที่พบเวลาพัฒนาคือเวลาเราแก้ไขอะไรแม้จะเล็กน้อยมันจะต้อง reload ทั้งหน้า ซึ่งปัญหานี้แหละครับที่เราจะเอาเจ้า HMR มาช่วย

เริ่มที่ CLI

ในบทความนี้จะเป็นการใช้ HMR ร่วมกับเครื่องมือยอดนิยมของ Angular นั้นก็คือ Angular CLI นั้นเอง ดังนั้นเริ่มเลยครับ

ng new hmr-demo

hmr-demo-02

หลังจากนั้นก็แวะไปดื่มกาแฟ เข้าห้องน้ำ ดูหน้ากากนักร้องย้อนหลังไปซักแป๊บ ก็จะได้โปรเจค hmr-demo ที่พร้อมว่าแล้วก็ลอง run ซักดอกนึงก่อนครับว่ามันโอเคไหมด้วย

ng serve

hmr-demo-01
โอเคดูเรียบร้อยดีต่อมาเราจะมาเริ่ม configuration กัน

Environment สำหรับ HMR

ปกติเวลาเราพัฒนาระบบเราก็จะมีการแยก environment เป็นไปตามเงื่อนไขต่างๆกันเเช่นเป็น dev, uat หรือ prod ตัว HMR เราก็จะแยก environment ออกมาเหมือนกัน เพราะถ้าเราไป Hot Module replace กับที่ prod ก็อาจจะไม่เหมาะเท่าไหร่ โอเคเรามาเริ่มกัน เริ่มจากสร้างไฟล์ environment.hmr.ts แล้วเพิ่มส่วนของ hmr ลงไปเป็น true อย่างงี้

hmr-demo-03

ส่วน environment อื่นๆที่ไม่ใช่ hmr เราก็จะ set เป็น false ให้หมดแบบนี้เป็นต้น

hmr-demo-04

ต่อมาส่วนที่เราจะไป set เพิ่มเวลาเราเพิ่ม environment ขึ้นมาก็คือ .angular-cli.json ก็ตามนี้เลย

hmr-demo-05

Install ตัว HMR

ต่อมาก่อนที่เราจะใช้ HMR ได้เราก็ต้อง Install มันก่อนก็จาก

npm install --save-dev @angularclass/hmr

จากนั้นเราก็ไปสร้างไฟล์ที่ hmr.ts เพื่อ configuration ตัว HMR กันก็ตามนี้เลย

// src/hmr.ts
import { NgModuleRef, ApplicationRef } from '@angular/core';
import { createNewHosts } from '@angularclass/hmr';

export const hmrBootstrap = (module: any, bootstrap: () => Promise<NgModuleRef<any>>) => {
  let ngModule: NgModuleRef<any>;
  module.hot.accept();
  bootstrap().then(mod => ngModule = mod);
  module.hot.dispose(() => {
    let appRef: ApplicationRef = ngModule.injector.get(ApplicationRef);
    let elements = appRef.components.map(c => c.location.nativeElement);
    let makeVisible = createNewHosts(elements);
    ngModule.destroy();
    makeVisible();
  });
};

hmr-demo-06

เสร็จแล้วก็ไป set ใน main.ts อีกนิดเพื่อให้ตัว HMR ขึ้นมาทำงานในกรณีที่เรา run ด้วย hmr environment

// src/main.ts
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
import { hmrBootstrap } from './hmr';

if (environment.production) {
  enableProdMode();
}

const bootstrap = () => {
  return platformBrowserDynamic().bootstrapModule(AppModule);
};

if (environment.hmr) {
  if (module['hot']) {
    hmrBootstrap(module, bootstrap);
  } else {
    console.error('HMR is not enabled for webpack-dev-server!');
    console.log('Are you using the --hmr flag for ng serve?');
  }
} else {
  bootstrap();
}

hmr-demo-07
เมื่อเรียบร้อยดีแล้วก็ลองเลยครับ

ng serve --environment=hmr --hmr

ซึ่งถ้าตัว HMR มันทำงานก็จะขึ้นมาบอกประมาณนี้ Hot Module Replacement (HMR) is enabled for the dev server.
hmr-demo-08

พอเราแก้ไข code เช่นแก้ title เป็น Angular Developers Thailand ก็จะเปลี่ยนโดยไม่ต้อง reload ใหม่ทั้งหมด
hmr-demo-09

สรุป

ต้องออกตัวว่ายังไม่เคยลองใช้ในโปรเจคตัวเอง(แต่จะเอาไปลองเดี๋ยวนี้แหละ) แต่มีโปรเจคข้างๆของ คุณเน็ต กูโค้ดใช้อยู่ (ซึ่งก็เป็นคนเอาตัว HMR มาขายผม) แต่ดูแล้วตัว HMR จะทำให้การพัฒนาระบบด้วย Angular รวดเร็วและสนุกขึ้น ถ้าใครลองใช้กันแล้วชอบหรือติดอะไรยังมาแชร์กันได้นะครับ (-/\-)

จบปิ๊ง

เนื้อหาต้นฉบับ: Tutorial: Enable HMR in angular-cli apps

Maven ตอน profile

marvel
ยัง ยัง ยังเล่นอยู่อีก

รอบที่แล้วได้คายเรื่อง resources ไป เรื่องต่อมาที่เกี่ยวเนื่องกันก็คือเรื่อง profiles 

ยกตัวอย่างง่ายๆเช่นตอนเราทำ Web app ขึ้นมา..

  • ตอนเรา dev เราต่อ DB เครื่องเราเอง
  • ทำเสร็จก็ต้องเอาไปลงเครื่อง Test server ให้ Tester ทดสอบซึ่งก็ต้องต่อ DB สำหรับเทส
  • ตอนส่งลูกค้าต่อ DB เครื่อง UAT หรือ Production

ไอ้ครั้นจะค่อยมาแก้ก่อน package มันก็มีโอกาสผิดพลาดได้ง่ายมาก โชคดีที่ Maven มี <profiles> ไว้สำหรับเรื่องนี้ โดยเราสามารถใส่ได้ดังนี้

2016-02-05 14_07_51-Java - struts2demo_pom.xml - Eclipse Platform
profile id=tumit ลงไปเปลี่ยน username/password เป็น tumit/789456

ตัวอย่างนี้เราเพิ่ม profile ที่ id=tumit ลงไป จากนั้นก็ mvn clean package กันเลย แต่…

2016-02-05 14_12_39-MINGW32__D_github_struts2demo
อ้าว! ทำไมยังเป็น admin/123456 ล่ะ?

ที่มันยังไม่เป็น tumit/789456 เพราะเรายังไม่ได้ระบุให้ Maven รู้ว่าเราใช้ profile tumit ในการ package ตัว Maven เลยไปเอาค่า default ใน properties มาใช้เหมือนเดิม

ดังนั้นเอาใหม่ใส่ mvn clean package -P tumit  เพื่อเป็นการบอกให้ Maven รู้ว่าเราจะใช้ profile อะไร

2016-02-05 14_17_00-MINGW32__D_github_struts2demo.png
เย้! เป็นแล้วๆ

ส่วนตัวใน properties ที่เป็นค่า default มักกำหนดไว้เป็นสำหรับเครื่องทดสอบ แล้วแยก profile ตอน dev เป็นชื่อตัวเอง, uat และ production ตอนจบมันก็เลยเป็นประมาณนี้2016-02-05 14_45_32-Java - struts2demo_pom.xml - Eclipse Platform.pngจบปิ๊ง สวัสดีcode:

    git clone git@github.com:tumit/struts2demo.gitgit pull origin mastergit checkout 6a1c629

Maven ตอน resources

marvel.jpg
เดี๋ยวๆ นี้มัน Marvel เฟ้ย!

ต่อจาก Eclipse หัวข้อถัดมาที่อยากจะ #คายของเก่า คือ Maven นี้นี่เอง

Maven คืออะไร

สำหรับคนที่ไม่รู้ว่า Maven คืออะไรหรือสร้างยังไง… ก็ลองไปกูเกิ้ลเอานะ(ฮา) แต่ถ้าจะให้อธิบายคร่าวๆ Maven ก็คือเครื่องมือช่วย build โปรเจคจาก source code + config ต่างๆให้กลายเป็นไฟล์พร้อมเอาไป execute (jar) หรือ deploy (war)ได้นั้นเอง

Maven กับ resources

ส่วนของเก่าที่อยากคายรอบนี้คือ resources (พวกไฟล์นามสกุล properties, xml หรืออื่นๆที่ไม่ใช่ source code) เช่นถ้าเรามี jdbc.properties ไว้เก็บ username / password ไว้สำหรับต่อ database ปกติเราก็จะสร้างไฟล์ properties แล้วก็ใส่ properties ประมาณนี้

2016-02-03 17_31_55-Java - struts2demo_src_main_resources_jdbc.properties - Eclipse

คือถ้ามันมีไฟล์เดียวคงไม่มีปัญหาอะไร สมมุติถ้าเรามีไฟล์ properties หรือ xml ที่ต้องมา config เยอะๆมานั่งไรแก้ทีละไฟล์คงไม่ดีแน่ Maven จะมาช่วยเราตรงนี้ได้ ด้วยการย้ายมากำหนดที่ Maven ที่เดียวเลย แล้วค่อยเอาค่าที่เรากำหนดใน Maven ไปไล่แปะตามไฟล์พวกนี้ให้

โอเคสมมุติว่าเราสร้างโปรเจคจาก maven-archetype-webapp มาแล้ว แล้วเราต้องการย้ายการกำหนดค่า jdbc.username, jdbc.password มาไว้บน Maven ก็ทำง่ายๆประมาณนี้

แก้ jdbc.properties ไฟล์ซะ

2016-02-03 17_50_49-Java - struts2demo_src_main_resources_jdbc.properties - Eclipse.png
เปลี่ยนค่าเป็นตัวแปรซะโดยใช้ ${xxx} เป็นตัวบอก

เพิ่ม <properties> และสร้าง tag ชื่อเดียวกับที่เรากำหนดไว้ในนั้น

2016-02-03 17_53_13-Java - struts2demo_pom.xml - Eclipse.png
ชื่อ tag ใต้ properties tag ต้องชื่อเดียวกับที่ตั้งไว้

เสร็จแล้วก็เปิด cmd โฟลเดอร์ของโปรเจคจัดเลย mvn clean package

2016-02-03 18_00_57-C__WINDOWS_system32_cmd.exe.png

ถ้ามันมัน “BUILD SUCCESS” ก็ถือว่าโอเค ลองไปเช็คดูในโฟลเดอร์ target/classes จะมี jdbc.properties เด่นเป็นสง่าขึ้นมาแต่..

2016-02-03 18_03_55-jdbc.properties - Notepad2
ค่ายังไม่มา -*-

ค่าไม่มาเพราะเรายังไม่ได้บอก Maven ตอน build ว่าให้ไปกำหนดค่าใน resources ไฟล์ทั้งหลายด้วย ดังนั้นเราก็บอกด้วยการใส่ <resources> ใต้ <build> โดยเราต้องกำหนดโฟลเดอร์ที่เก็บ resources และ flag ที่บอกให้ทำการ filter ลงไปแบบนี้

2016-02-03 18_08_24-Java - struts2demo_pom.xml - Eclipse.png
เอาค่าไป set ให้ทีนะ

mvn clean package อีกที ค่าของ jdbc.username / jdbc.password ก็จะถูกแปะเรียบร้อย เย้ สวัสดี

Eclipse พระจันทร์ที่บังแสงแห่งดวงอาทิตย์

จริงๆจาวามันใช้อะไรช่วยโค้ดได้ทั้งนั้น ~ โปรแกรมเมพท่านนึงกล่าว

จำได้ว่าสมัยทำโปรเจคจบ พระจอมฯปราจีน นั่งเสิร์ซนั่งเลือกอยู่ว่าเราจะใช้อะไรไหนช่วยโค้ด สุดท้ายก็เลือก Eclipse ไม่แน่ว่าเพราะอะไร อาจจะเป็นเพราะหน้าตามันถูกจริตมากกว่า Netbeans (ไม่เกี่ยวกับฟีเจอร์หรืออะไรเลยซักนิด #ฮา)

จบมาทำงานที่แรกเขาก็ใช้ Eclipse ไปกี่ที่ก็ Eclipse สรุปเลยไม่ได้มีโอกาสใช้เจ้าอื่นเลย ..แต่ที่น่าสนใจก็คือ ด้วยความที่ว่า Eclipse มันแสนกลมาก สร้างโปรเจคได้ คอมไพล์ให้ เช็ค syntax ได้ตอนจบยัง export เป็น war ไว้ไปวางบน Tomcat อีกต่างหาก สรุปคือทำให้ทุกอย่าง.. ทุกอย่างจนไม่รู้ด้วยซ้ำว่า file/folder structure จริงๆที่อยู่ใน war ไฟล์มันเป็นยังไง เหลือเชื่อจริงๆว่าทำงานเป็นปีๆได้ไงไม่รู้ กากแท้ข้าพเจ้า ==’

web-demo.jpg
เอ.. แล้วโฟลเดอร์ WebContent มันอยู่ตรงไหนของ war ฟ่ะ ==?

 

มาตอนหลังนี้ดีขึ้นหน่อย ได้มารู้จัก Maven ทำให้ตอนนี้บทบาทของ Eclipse ใช้แค่ import โปรเจคเข้า แก้โค้ด และก็ config ไว้ให้ run Maven เท่านั้นเอง

ข้อดีของการ run Maven บน console ของ Eclipse ก็คือ เวลาจาวามันพ่น exception แบบเวิ้นเว้อ ถ้า run บนจอดำท่อนบนๆมันจะหายไปเลย ถ้า run ใน console ของ Eclipse เรายัง scroll หรือกด Link ไปหาจุดตายได้

eclipse-console.png
run มันตรงนี้แหละ

ส่วนเวอร์ชั่นของ Eclipse แต่ก่อนใช้ JEE developr แต่ตอนหลังใช้แค่ Java ธรรมดาเพราะเชื่อว่ามันจะเบากว่า JEE (น่าจะจริงมั้ง) ส่วน plugin จะมี

  • Eclipse Web Developer Tools – ไว้แก้ HTML JavaScript CSS
  • Maven – อันนี้ติดมากับ Eclipse อยู่แล้ว เอาไว้ช่วย import โปรเจคเข้ามาใน Eclipse และก็ run บน eclipse ได้
  • Properties Editor – ไว้แก้ Message resource
  • Lombok – ใช้ @Getter @Setter (ใช้บ่อยมากกับ Struts2)

ส่วน shortkey ที่ใช้บ่อยก็มี

  • Alt+Shift+O – ให้มัน auto ลบ import ที่ไม่ได้ใช้
  • Alt+Shift+R (ที่ชื่อตัวแปร) – ใช้แก้ชื่อตัวแปรที่อยู่ในคลาสให้เปลี่ยนทั้งคลาส
  • Ctrl+Shift+F -จัด format ของ code
  • F11 – ไว้ run maven แบบ debug ใช้ร่วมกับ dcevm จะได้ไม่ต้อง restart บ่อยๆ
  • Contrl+H -> File Search – ไว้หา ข้อความ ในไฟล์
  • Control+Alt+H – หาว่า method นี้ใครเรียกมันบ้าง

เท่าที่นึกออกมีประมาณนี้ ถ้าคิดเพิ่มได้จะมาเติมทีหลังแล้วกันเนาะ สวัสดี

ปล. อ้อตอนนี้ใช้ an Ergonomic Eclipse Theme for Windows 10 ด้วยแต๊ดแต๋สุดๆ 55

คายของเก่า

เริ่มด้วยความรู้สึกที่ว่าช่วงนี้ชีวิตมันชักจะเฉื่อยๆ รู้สึกตัวเองไม่กระตือรือล้นเท่าที่ควรทั้งที่โลกของโปรแกรมเมอร์วิ่งไวขึ้นเรื่อยๆ ตอนเลยอยากจะเริ่มเรียนรู้อะไรใหม่ๆ แต่ก่อนที่จะไปต่อก็อยากจะ #คายของเก่า ออกมาก่อนเพื่อจะได้เคลียร์หัวให้มันโล่งๆและทบทวนตัวเองไปในตัว

จากที่ทำงานมาหลายปี ที่พอทำได้จำได้ก็ประมาณนี้

  • Eclipse
  • Maven
  • Struts2
  • Jquery Validation
  • Spring
  • Hibernate

หลักๆประมาณนี้ เดี๋ยวจะกลับมาขยี้ที่ละหัวข้อ สวัสดี

Jasypt: มาเข้ารหัส property value ใน properties file กัน

ปกติแล้วเวลาทำ app ขึ้นมาเราก็ต้องมีการเก็บข้อมูลจำพวก username, password ไว้ในไฟล์ properties ประมาณนี้

jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:tcp://localhost/~/appdb
jdbc.username=admin
jdbc.password=password

ซึ่งมันดูโหดมากเพราะเรากำลังเอา password ไปโชว์หร่าบน text ไฟล์กันโต้งๆ ดังนั้นถ้าข้อมูลประเภทที่ควรเป็นความลับก็ควรจะเข้ารหัสซักนิดเพื่อความปลอดภัยในชีวิตและทรัพย์สิน

สมมุติโจทย์

สมมุติโจทย์ให้ app เรา(ของเดิมนั้นแหละ) ต้องอ่านข้อมูล JDBC จาก [root]/cfg/jdbc.properties โดยให้ข้อมูลมี่เป็น password ต้องเข้ารหัสให้ไม่สามารถรู้ได้ว่า password คืออะไร

Code เดิมๆ

ถ้าเป็นแบบเดิมๆเราก็จะมี jdbc.properties เหมือนด้านบนและก็เขียน JdbcProperties ขึ้นมาเพื่ออ่าน properties ขึ้นมาประมาณนี้

package ninja.tumit.launch4jdemo.properties;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class JdbcProperties {
 
    final static Logger log = LoggerFactory.getLogger(JdbcProperties.class);
    
    private static final String PROPERTIES_PATH = "../cfg";
    private static String PROPERTIES_FILE = "jdbc.properties";    
    private static JdbcProperties instance = null;
    private Properties prop = null;
    
    private JdbcProperties(){
        
        prop = new Properties();
        try {   
            File executorPath = new File(getExecutorPath());            
            String propertiesPath = executorPath.getParentFile().getAbsolutePath();              
            prop.load(new FileInputStream(propertiesPath+"/"+ PROPERTIES_PATH +"/" + PROPERTIES_FILE));          
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getExecutorPath() {
        return JdbcProperties.class.getProtectionDomain().getCodeSource().getLocation().getPath();
    }      
    
    public static synchronized JdbcProperties getInstance(){
        if (instance == null)
            instance = new JdbcProperties();
        return instance;
    }

    public String getValue(String key){
        return this.prop.getProperty(key);
    }
}

ในส่วนของ app ก็เรียกมาดูว่าอ่าน properties จาก [root]/cfg/jdbc.properties

package ninja.tumit.launch4jdemo;

import java.io.IOException;

import ninja.tumit.launch4jdemo.properties.JdbcProperties;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Hello Launch4j!
 *
 */
public class App 
{
    
    Logger logger = LoggerFactory.getLogger(App.class);

    public void run() {
        try {
            
            String username = JdbcProperties.getInstance().getValue("jdbc.username");
            String password = JdbcProperties.getInstance().getValue("jdbc.password");
            
            logger.info( "JDBC: username={}, password={}",  username, password);
            
            System.in.read();            
        }catch(IOException e) {
            e.printStackTrace();
        }        
    }
        
    public static void main( String[] args ) {
        new App().run();
    }
}
แน่นอนมันควรจะอ่่านได้เรียบร้อยดี

Code แบบเข้ารห้ส

เอาละมาเข้าประเด็นของหัวข้อกัน 😛

ใส่ Jasypt เข้าไปในโปรเจค

แน่นอนอย่างแรกก็ต้องเป็น lib สำหรับช่วยเข้ารหัสก่อนเราใช้ lib ที่ชื่อ Jasypt (อ่านว่าอะไรฟ่ะ) ก่อนอื่ก็เอาเข้าไปใส่ใน pom.xml ก่อน

<dependency>
	<groupId>org.jasypt</groupId>
	<artifactId>jasypt</artifactId>
	<version>1.9.2</version>
</dependency>

เข้ารหัสในไฟล์ properties

ก่อนอื่นเราต้องมีตัวช่วยในการเข้ารหัสเพื่อเอา text ที่เข้ารหัสแล้วไปแปะที่ไฟล์ properties ซึ่งเรา download ได้จากนั้น unzip ซะแล้ว cmd เข้าไปเลย
cmd-jasypt-enc.exe

  • encrypt.bat – executor ตัวช่วย generate password ที่เข้ารหัส
  • input – password เดิมๆที่เราอยากให้เป็นความลับ
  • password – ตัวปั่นให้ password เดิมๆให้อ่านยากๆ
  • —- OUTPUT —-  – นี้แหละ text ที่เราจะเอาไปแปะแทน password เดิม

ว่าแล้วก็เอาไปแปะแทน password เดิมเลย แต่เพิ่ท ENC(xxxx) หน่อยเพื่อเป็นการบอกว่า text ชุดนี้เข้ารหัสนะ

jdbc.driverClassName=org.h2.Driver
jdbc.url=jdbc:h2:tcp://localhost/~/appdb
jdbc.username=admin
jdbc.password=ENC(4pCWOkm2Kwwa1tfM0x9maZMgfMqsdw0v)

เปลี่ยนตัวอ่าน properties

จาก code เดิมเราใช้คลาส Properties ในการโหลดแต่พอเราใช้ Jasypt ก็ต้องใช้ EncryptableProperties + StandardPBEStringEncryptor แทน

package ninja.tumit.launch4jdemo.properties;

import java.io.File;
import java.io.FileInputStream;
import java.util.Properties;

import org.jasypt.encryption.pbe.StandardPBEStringEncryptor;
import org.jasypt.properties.EncryptableProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class JdbcProperties {
 
    final static Logger log = LoggerFactory.getLogger(JdbcProperties.class);
    
    private static final String PROPERTIES_PATH = "../cfg";
    private static String PROPERTIES_FILE = "jdbc.properties";    
    private static JdbcProperties instance = null;
    private Properties prop = null;
    
    private JdbcProperties(){
        
        StandardPBEStringEncryptor encryptor = new StandardPBEStringEncryptor();
        encryptor.setPassword("MAKE_PASS");

        // prop = new Properties();
        prop = new EncryptableProperties(encryptor);        

        try {   
            File executorPath = new File(getExecutorPath());            
            String propertiesPath = executorPath.getParentFile().getAbsolutePath();              
            prop.load(new FileInputStream(propertiesPath+"/"+ PROPERTIES_PATH +"/" + PROPERTIES_FILE));          
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static String getExecutorPath() {
        return JdbcProperties.class.getProtectionDomain().getCodeSource().getLocation().getPath();
    }      
    
    public static synchronized JdbcProperties getInstance(){
        if (instance == null)
            instance = new JdbcProperties();
        return instance;
    }

    public String getValue(String key){
        return this.prop.getProperty(key);
    }
}
  • StandardPBEStringEncryptor – เราจะเอา MAKE_PASS(ตัวช่วยปั่น) ใส่ไปในออปเจคของคลาสนี้
  • EncryptableProperties – เปลี่ยนจาก Properties ธรรมดาเป็นตัวนี้แล้วเอา encryptor หยอดไป

กลับไป run App อีกทีนี้เราก็จะสามารถใช้ properties ที่เข้ารหัสได้เป็นปกติเหมือนไม่เคยเข้ารหัสมาก่อน

buid ซิ buid

อ้าว! ลืมก็อปไฟล์ properties
อ้าว! ลืมก็อปไฟล์ properties
launch4j-enc
ก็อปปี้แล้ว run โอเช