10 Tips สำหรับผู้เริ่มต้นกับ Spring Boot

Wattanachai Prakobdee
Ascend Developers
Published in
4 min readSep 22, 2017

--

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?

--

--

Software Engineer at LINE Thailand | Learning is a journey, Let's learn together.