10 Tips สำหรับผู้เริ่มต้นกับ Spring Boot
Spring Boot เป็น Core technology ที่ได้รับความนิยมในการสร้าง microservice หรือสร้าง RESTful Web services และ Sprint Boot ยังง่ายมากๆในการ mapping HTTP เช่น GET, PUT, POST, และ DELETE กับ URLs พร้อมทำ serialization JSON protocol กับ Java objects สำหรับบทความนี้ เป็นบทความเสนอ Tips เล็กๆน้อยๆสำหรับผู้ที่พึ่งเริ่มต้นกับ Spring Boot ครับ
1.ใช้ SPRING INITIALIZR ในการสร้าง Spring Boot project
ใช้ SPRING INITIALIZR ในการสร้าง Spring Boot project ของเราแบบง่ายๆ
2. The project structure
Spring Boot ไม่มี standard หรือข้อกำหนดของ project structure แบบตายตัว แต่ยังไงก็ยังมี best practices ที่เขาใช้กันเยอะ
Java Source code packages และ classes อยู่ภายใต้ src/main/java
com
+- example
+- myproject
+- Application.java
|
+- controller
| +- ProductController.java
|
+- entity
| +- Product.java
|
+- repository
| +- ProductRepository.java
|
+- service
| +- ProductService.java
ส่วนของ Test ก็จะล้อเลียน structure ข้างบน แต่จะอยู่ภายใต้ src/test/java แทน
3. ระบุ Dependency Versions ให้ชัดเจน
ทำการกำหนด version numbers ของ dependency ที่ properties และกำหนด version ของ dependency ให้ชัดเจน จะช่วยให้ง่ายในการ upgrade และ test versions ใหม่ๆของ dependencies
Gradle
ext {
lombokVersion = '1.16.18'
jodaTimeVersion = '2.9.9'
}
...
dependencies {
compile 'joda-time:joda-time:' + jodaTimeVersion
compileOnly 'org.projectlombok:lombok:' + lombokVersion
...
}
Maven
<properties>
<lombok.version>1.16.18</lombok.version>
<jodaTime.version>2.9.9</jodaTime.version>
</properties>
...<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>${jodaTime.version}</version>
</dependency>
...
</dependencies>
4. ใช้ @RESTController แทน @Controller
สำหรับการทำงานกับ JSON ควรใช้ @RESTController แทน @Controller เพื่อทำให้แน่ใจว่า เราจะ return Java Object หรือว่า JSON ไม่ใช่ HTML template
โดยปกติแล้วถ้าเราใช้ @Controller ที่ controller จะทำการไป map และ return HTML template ใน src/main/resources folder และถ้าเราจะให้ return เป็น Java Object หรือว่า JSON ต้องทำการใช้ @Controller ร่วมกับ @ResponseBody เพื่อบอกให้ controller ทำการ return เป็น JSON
ฉะนั้น เราใช้ @RESTController แทน @Controller ในการทำงานร่วมกับ JSON
@Controller
class Greeting {
@GetMapping("/greeting")
@ResponseBody
public String hello() {
return "Hello";
}
}
เราสามารถใช้ @RESTController แทนได้ ดังนี้
@RestController
class Greeting {
@GetMapping("/greeting")
public String hello() {
return "Hello";
}
}
5. ใช้ @GetMapping, @PostMapping etc
ก่อนหน้านี้ ใน Spring/Spring Boot เวลาเราทำการ map GET, POST, DELETE หรือ HTTP method อื่นๆ กับ request handler เราจะเขียนโดยการใช้ @RequestMapping
@RequestMapping(method = RequestMethod.GET, value="/{product_id}")
public ResponseEntity<?> getProduct(@PathVariable("product_id") String productId){
...
}
แต่หลังจาก Spring 4.3 และ Spring Boot 1.4 (ข้างใน Spring Boot 1.4 ใช้ Spring 4.3) เราสามารถใช้ annotations ใหม่ในการ map HTTP methods กับ request handlers ดังนี้
- GET ใช้ @ GetMapping
- POST ใช้ @PostMapping
- PUT ใช้ @PutMapping
- PATCH ใช้ @PatchMapping
- DELETE ใช้ @DeleteMapping
จากตัวอย่างข้างบน เราสามารถใช้ @GetMapping แทน แบบนี้
@GetMapping("/{product_id}")
public ResponseEntity<?> getProduct(@PathVariable("product_id") String productId){
...
}
6. ใช้ constructor injection แทน field injection เมื่อทำ Dependency Injection ด้วย Autowired
สำหรับการทำ Spring Dependency Injection ด้วยการใช้ field injection (Setter Injection) และ constructor injection ผลลัพธ์ได้เหมือนกัน แต่วิธีที่ Spring engineers แนะนำให้ใช้คือ constructor injection เนื่องด้วยมีข้อได้เปรียบในหลายๆด้าน เช่น ง่ายในการ test มากกว่า field injection ข้อมูลเพิ่มเติมดูได้จาก Why field injection is evil
@Service
class Foo {
private Bar bar;
@Autowired
public Foo(Bar bar) {
this.bar = bar;
}
...
}
@Service
class Bar {
...
}
7. ใช้ @ControllerAdvice ในการทำ Global exception handling
โดยปกติแล้ว เวลาเราทำ error handling จะใช้ @ExceptionHandler ในการดัก Exception ใน Controller level และจะ active เฉพาะภายใน Controller นั้นๆ เราสามารถใช้ @ControllerAdvice ในการทำ Global exception handling แทนได้
8. Custom Error page
สำหรับผู้ที่ต้องการ Custom error page ใน spring Boot สามารถเพิ่ม static HTML file ใน /src/main/resources/static/error folder
src/
+- main/
+- java/
| + <source code>
+- resources/
+- public/
+- error/
| +- 404.html
| +- 40x.html
| +- 500.html
| +- 50x.html
จากตัวอย่างด้านล่าง ผมทำการเพิ่ม custom error page ในชื่อ 404.html ใน /src/main/resources/static/error
จากนั้นทำการเรียก endpoint ที่ไม่มีอยู่จริง ก็จะแสดง custom error page ดังรูปด้านล่าง
9. ใช้ Profiles ในการจำแนก environment
ใช้ Profiles ในการจำแนก environment ที่แตกต่างกัน ในการทำงานจริงๆ เราต้องมีการจำแนก environment ของการทำงาน เช่น development, testing, staging และ production เนื่องจากแต่ละ environment อาจจะมีการ configuration ที่ไม่เหมือนกัน เช่น database URL
ในการใช้ profile สามามารถใช้ property file .properties/.yml หรือใช้ command line ก็ได้ ในการทำ profile specific properties สามารถใช้โดยการตั้งชื่อ file เป็น application-{profile}.properties เช่น application-development.properties หรือถ้าใช้ application.yml เราสามารถจำแนก profiles ได้ใน file เดียว เช่น
---
spring:
profiles: development
server:
address: 127.0.0.1
---
spring:
profiles: production
server:
address: 192.168.1.120
เพื่อที่จะ active profile เราต้อง configure กำหนด spring.profiles.active property
ใช้ application.properties
spring.profiles.active=development
ใช้ application.yml
spring:
profiles:
active: development
หรือใช้วิธี pass argument
java -jar -Dspring.profiles.active=development spring-boot-demo.jar
10. Make JAR, not WAR
Spring Boot, Spring Cloud นินจา Josh Long ได้กล่าวไว้
Make JAR, not WAR — Josh Long
Spring Boot สามารถ package Jar พร้อม embedded container เช่น tomcat embedded ที่สามารถใช้ java -jar command ในการ run application แต่ถ้าเราใช้ War เราต้องทำการ deploy War ใน application server เช่น Tomcat หรือ WebSphere และใน Spring Boot เอง เราต้องทำการแก้ Code บางส่วนของ Application.java เพื่อให้ทำงานกับ application server ได้ เช่น
@Configuration
public class WebInitializerConfiguration extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(SpringBootDemoApplication.class);
}}
ดังนั้น สำหรับ Spring boot แล้วต้อง Make JAR, not WAR สำหรับบทความความเกี่ยวกับ archive format สามารถอ่านต่อได้ที่ WAR or JAR?