STACKJAVA

Code ví dụ Spring Boot đọc file properties, @ConfigurationProperties, @PropertySource

Code ví dụ Spring Boot đọc file properties, @ConfigurationProperties, @PropertySource.

Ở phần này mình sẽ làm ví dụ về các cách đọc thông tin từ file config .properties với Spring Boot.

1. Với các file .properties đơn giản

1.1. Sử dụng annotation @Value

Cách đơn giản nhất là sử dụng annotation @Value để inject giá trị trong file application.properites vào thuộc tính của các Spring Bean.

Ví dụ:

message=Default message from application.properties
package stackjava.com.springboothello.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import stackjava.com.springboothello.bean.GlobalConfig;

@Controller
public class BaseController {
  
  @Value("${message}")
  private String message;

}

1.2. Sử dụng annotation @PropertySource để đọc những file .properites tùy chọn.

Ví dụ:

website=stackjava.com
facebook=facebook.com/stackjava
name=kai
package stackjava.com.springboothello.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@PropertySource("classpath:global.properties")
public class GlobalConfig {

  @Value("${name}")
  private String name;

  @Value("${website}")
  private String website;

  @Value("${facebook}")
  private String facebook;

        // getter / setter

}

1.3. Sử dụng annotation @EnableAutoConfiguration

Annotation @EnableAutoConfiguration sẽ tự động mapping thuộc tính của bean với các giá trị trong file .properties

Ví dụ:

package stackjava.com.springboothello.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties
@PropertySource("classpath:global.properties")
public class GlobalConfig {

  private String name;

  private String website;

  private String facebook;
  
  // getter / setter
  
}

2. Đọc các file properties phức tạp

Ví dụ:

#App
app.menus[0].title=Home
app.menus[0].name=Home
app.menus[0].path=/home
app.menus[1].title=Login
app.menus[1].name=Login
app.menus[1].path=/login

Hoặc với file yaml

app:
  menus:
  - title: Home
    name: Home
    path: /
  - title: Login
    name: Login
    path: /login
*Lưu ý: annotation @ConfigurationProperties hỗ trợ cả file.properties và file.yml.
package stackjava.com.springboothello.bean;

import java.util.ArrayList;
import java.util.List;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component
@ConfigurationProperties("app") // prefix app, find app.* values
@PropertySource("classpath:menu.properties")
public class MenuConfig {

  private List<Menu> menus = new ArrayList<>();

  public List<Menu> getMenus() {
    return menus;
  }

  public void setMenus(List<Menu> menus) {
    this.menus = menus;
  }

  public static class Menu {
    private String name;
    private String path;
    private String title;
              // getter - setter
    @Override
    public String toString() {
      return "Menu{" + "name='" + name + '\'' + ", path='" + path + '\'' + ", title='" + title + '\'' + '}';
    }
}

3. Sử dụng Environment

Bạn chỉ cần inject Environment vào các component là có thể lấy các message trong file .properties.
Mặc định Environment lấy message từ trong file application.properties, nếu bạn muốn nó đọc từ cả các file khác thì dùng kèm với  @PropertySource

Ví dụ:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Service;

@Service
public class HelloService {

  @Autowired
  Environment env;
  
  public void hello() {
    System.out.println(env.getProperty("message"));
  }
}

4. Validate dữ liệu từ file properties

@ConfigurationProperties Hỗ trợ validate dữ liệu với javax.validation

Để validate dữ liệu ta sử dụng annotation @Validated ở đầu class và các annotation validate ở mỗi field ví dụ:

package stackjava.com.springboothello.bean;

import javax.validation.constraints.NotEmpty;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

@Component
@ConfigurationProperties
@PropertySource("classpath:global.properties")
@Validated
public class GlobalConfig {

  @NotEmpty
  private String name;

  private String website;

  private String facebook;

  // getter - setter

}

Nếu dữ liệu không hợp lệ thì ứng dụng sẽ start failed và thông báo lỗi:

***************************
APPLICATION FAILED TO START
***************************

Description:

Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under '' to stackjava.com.springboothello.bean.GlobalConfig failed:

    Property: .name
    Value: 
    Origin: "name" from property source "class path resource [global.properties]"
    Reason: must not be empty


Action:

Update your application's configuration

5. Demo.

File Properties:

message=Default message from application.properties
#App
app.menus[0].title=Home
app.menus[0].name=Home
app.menus[0].path=/home
app.menus[1].title=Login
app.menus[1].name=Login
app.menus[1].path=/login
website=stackjava.com
facebook=facebook.com/stackjava
name=kai

File Controller:

package stackjava.com.springboothello.controller;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import stackjava.com.springboothello.bean.GlobalConfig;
import stackjava.com.springboothello.bean.MenuConfig;

@Controller
public class BaseController {
  
  @Autowired
  private GlobalConfig globalConfig;
  
  @Autowired
  private MenuConfig menuConfig;
  
  @Value("${message}")
  private String message;
  
  @RequestMapping("/")
  public String index(Model model) {
    model.addAttribute("name", globalConfig.getName());
    model.addAttribute("website", globalConfig.getWebsite());
    model.addAttribute("facebook", globalConfig.getFacebook());
    model.addAttribute("message", message);
    model.addAttribute("menus", menuConfig.getMenus());
    return "index";
  }
}

File view:

<html xmlns:th="http://www.thymeleaf.org">
<head>
<title>Spring Boot</title>
</head>
<body>
  <h1>Spring Boot Properites file</h1>

  <table>
    <tr>
      <td>Name:</td>
      <td><p th:text="${name}">Default Name</p></td>
    </tr>
    <tr>
      <td>Website:</td>
      <td><p th:text="${website}">Default Website</p></td>
    </tr>
    <tr>
      <td>Facebook:</td>
      <td><p th:text="${facebook}">Default Facebook</p></td>
    </tr>
    <tr>
      <td>Message:</td>
      <td><p th:text="${message}">Default Message</p></td>
    </tr>
    Menu:
    <ul th:if="${menus != null && !menus.empty}">
      <li th:each="menu: ${menus}" th:text="${menu}"></li>
    </ul>

  </table>
</body>
</html>

Kết quả:

Okay, Done!

Download code ví dụ trên tại đây.

 

Code ví dụ Spring Boot đọc file properties, @ConfigurationProperties, @PropertySource, Environment stackjava.com

References:

https://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/htmlsingle/#boot-features-external-config-application-property-files