๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ
๐ŸŒฟ Spring

[Spring Boot/RESTful] Validation API์™€ Internationalization

by nitronium102 2022. 2. 18.

Validation API

์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์œ ํšจ์„ฑ ์ฒดํฌ -> @Valid annotation ์‚ฌ์šฉ

1. dependency ์ถ”๊ฐ€

<dependency>
      <groupId>org.hibernate.validator</groupId>
      <artifactId>hibernate-validator</artifactId>
      <version>6.0.7.Final</version>
</dependency>

2. dto์— ์ œ์•ฝ์กฐ๊ฑด ์ถ”๊ฐ€

@Data
@AllArgsConstructor
public class User {
	private Integer id;

	@Size(min=2, message = "Name์€ 2๊ธ€์ž ์ด์ƒ ์ž…๋ ฅํ•ด์ฃผ์„ธ์š”.")
	private String name;
	private String password;
	@Past // ๊ณผ๊ฑฐ ๋‚ ์งœ๋งŒ ๊ฐ€๋Šฅํ•œ ์ œ์•ฝ ์กฐ๊ฑด
	private Date joinDate;
}

3. controller์— ์ถ”๊ฐ€

  • JDK์— ํฌํ•จ๋œ API์™€ hibernate library์— ํฌํ•จ๋œ validation ๊ธฐ๋Šฅ
  • @Valid : ์‚ฌ์šฉ์ž ์ถ”๊ฐ€ํ•  ๋•Œ validation ๊ฒ€์ฆ
  • @RequestBody : ํ˜„์žฌ variable์ด requestBody ํ˜•์‹์œผ๋กœ ๋“ค์–ด์˜ด์„ ์•Œ๋ฆผ
@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @ResponseBody User user){ ... }

4. Exception handler ์ถ”๊ฐ€

handleMethodArgumentNotValid ๋ฉ”์„œ๋“œ ์žฌ์ •์˜
  • ex.getMessage()๊ฐ€ ์ค‘๋ณต๋˜๊ณ  ๋„ˆ๋ฌด ๊ธธ๊ธฐ ๋•Œ๋ฌธ์— "Validation Failed"๋ผ๋Š” ๊ฐ’์œผ๋กœ ๋Œ€์ฒด
  • ex.getBindingResult.toString() : @Size(message="{๋ฉ”์‹œ์ง€}") ๊ฐ’๋„ ํฌํ•จ
@Override // ๋ฉ”์†Œ๋“œ ๊ตฌํ˜„์ด ์ž˜๋ชป๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€
protected ResponseEntity<Object> handleMethodArgumentNotValid
          (MethodArgumentNotValidException ex, // ๋ฐœ์ƒํ•œ exception
          HttpHeaders headers, // request header
          HttpStatus status,
          WebRequest request) { // ์š”์ฒญ request
		ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(),
			"Validation Failed", ex.getBindingResult().toString());
		return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST);
	}

 

๋‹ค๊ตญ์–ด ์ฒ˜๋ฆฌ๋ฅผ ์œ„ํ•œ Internationalization ๊ตฌํ˜„

๋‹ค๊ตญ์–ด ์ฒ˜๋ฆฌ : ํ•˜๋‚˜์˜ ์ถœ๋ ฅ ๊ฐ’์„ ์—ฌ๋Ÿฌ ์–ธ์–ด๋กœ ํ‘œ์‹œํ•ด์ฃผ๋Š” ๊ธฐ๋Šฅ(ํ”„๋กœ์ ํŠธ ์ „๋ฐ˜์ ์œผ๋กœ ์ ์šฉ)

1. yml ํŒŒ์ผ์— ์„ค์ • ์ถ”๊ฐ€

spring.messages.basename={์‚ฌ์šฉํ•  properties ํŒŒ์ผ์˜ ์ด๋ฆ„}

#๋‹ค๊ตญ์–ด ํŒŒ์ผ ์„ค์ •
spring:
  messages:
    basename: messages # ์šฐ๋ฆฌ๊ฐ€ ์‚ฌ์šฉํ•  message ํŒŒ์ผ์˜ ์ด๋ฆ„

2. Resources์— {yml ํŒŒ์ผ์—์„œ ์„ค์ •ํ•œ ์ด๋ฆ„}.properties ์ƒ์„ฑ

๋‹ค๊ตญ์–ด ๋ฒ„์ „์œผ๋กœ ์—ฌ๋Ÿฌ ๊ฐœ ์ƒ์„ฑ

// message_properties
# properties : ์ž๋ฐ”์˜ ๋ฆฌ์†Œ์Šค ๋ฒˆ๋“ค
# ํŠน์ • key๊ฐ’๊ณผ value๋ฅผ ์ €์žฅํ•ด ๋†“๊ณ  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์šฉ๋„๋กœ ์‚ฌ์šฉ๋จ
greeting.message=์•ˆ๋…•ํ•˜์„ธ์š”
// messages_fr.properties
greeting.message=Bonjour

3. @SpringBootApplication์— localeResolver ์ƒ์„ฑ

@SpringBootApplication์— @Bean์„ ๋“ฑ๋กํ•˜๊ฒŒ ๋˜๋ฉด Spring Boot๊ฐ€ ์ดˆ๊ธฐํ™”๋  ๋•Œ, ํ•ด๋‹น ์ •๋ณด์— ํ•ด๋‹น๋˜๋Š” ๊ฐ’์ด ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€์„œ ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

@Bean
// @SpringBootApplication์— @Bean์„ ๋“ฑ๋กํ•˜๊ฒŒ ๋˜๋ฉด Spring Boot๊ฐ€ ์ดˆ๊ธฐํ™”๋  ๋–„,
// ํ•ด๋‹น ์ •๋ณด์— ํ•ด๋‹น๋˜๋Š” ๊ฐ’์ด ๋ฉ”๋ชจ๋ฆฌ์— ์˜ฌ๋ผ๊ฐ€์„œ ๋‹ค๋ฅธ ํด๋ž˜์Šค๊ฐ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.
public LocaleResolver localeResolver() {		
	SessionLocaleResolver localeResolver = new SessionLocaleResolver();
	localeResolver.setDefaultLocale(Locale.KOREA); // default : ํ•œ๊ตญ์–ด ์ฒ˜๋ฆฌ
	return localeResolver;
}

4. Controller์— ๋ฉ”์‹œ์ง€ ์ฃผ์ž…

  • Header๋กœ language ๊ฐ’์„ ๋ฐ›์•„์„œ ํ•ด๋‹น ์–ธ์–ด์— ๋งž๋Š” ๋ฉ”์„ธ์ง€๋ฅผ ์ถœ๋ ฅ
  • @Autowired : spring framework์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” bean ์ค‘ ๊ฐ™์€ ํƒ€์ž…์„ ๊ฐ€์ง„ bean์„ ์ž๋™์œผ๋กœ ์ฃผ์ž…(annotation์„ ์ด์šฉํ•œ ์˜์กด์„ฑ ์ฃผ์ž…)
  • "Accept-Language" ๊ฐ’์ด ์„ค์ •๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ์ž๋™์œผ๋กœ default๊ฐ’์ธ ํ•œ๊ตญ์–ด๋กœ ์„ค์ •(๊ธฐ๋ณธ locale ๊ฐ’)
  • "Accept-Language" ๊ฐ€ ์„ค์ •๋˜์–ด ์žˆ์œผ๋ฉด locale์— ํ•ด๋‹น ๊ฐ’์„ ์ €์žฅ
@Autowired
private MessageSource messageSource;

@GetMapping(path="/hello-world-internationalized")
	public String helloWorldInternationalized(
		@RequestHeader(name="Accept-Language", required = false) Locale locale) {
		// ์ฒซ๋ฒˆ์งธ ์ธ์ž: ์„ค์ • ํŒŒ์ผ์—์„œ์˜ key ๊ฐ’
		// ๋‘๋ฒˆ์งธ ์ธ์ž: ๋งŒ์•ฝ parameter๋ฅผ ๊ฐ€์ง„ ๊ฐ€๋ณ€๋ณ€์ˆ˜๋ผ๋ฉด parameter ์ง€์ •
		// ์„ธ๋ฒˆ์งธ ์ธ์ž: RequestHeader๋ฅผ ํ†ตํ•ด ์ „๋‹ฌ๋ฐ›์€ locale
		return messageSource.getMessage("greeting.message", null, locale);
	}

๋Œ“๊ธ€