[Spring] Validation API and LocaleResolver ๐Ÿงฑ

15525 ๋‹จ์–ด Springrestful apiSpring

Validation API(์œ ํšจ์„ฑ ์ฒดํฌ) ๐Ÿ‘‰ ์‚ฌ์šฉ์ž๊ฐ€ ์ž…๋ ฅํ•œ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์œ ํšจ์„ฑ ์ฒดํฌ

@Valid




// User Class

import lombok.AllArgsConstructor; 
import lombok.Data; 
import javax.validation.constraints.Past; 
import javax.validation.constraints.Size; 
import java.util.Date; 

@Data 
@AllArgsConstructor 
public class User { 

private Integer id; 

@Size(min=2)  // ์ตœ์†Œ ๊ธธ์ด 2๊ฐœ ์ด์ƒ
private String name;  

@Past // ๋ฏธ๋ž˜ ๋ฐ์ดํ„ฐ๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค๋Š” ์ œ์•ฝ ์กฐ๊ฑด
private Date joinDate; 
}



 // UserController Class
 
 @PostMapping("/users")
 public ResponseEntity<User> createUser(@Valid @RequestBody User user){
        User savedUser = service.save(user);

        URI location = ServletUriComponentsBuilder.fromCurrentRequest()
                .path("/{id}") //๋ฐ˜ํ™˜ ๊ฐ’์€ ๊ฐ€๋ณ€ ๋ณ€์ˆ˜ id
                .buildAndExpand(savedUser.getId()) //์ €์žฅ๋œ user ๊ฐ’์˜ id ๊ฐ’์„ ์ง€์ •
                .toUri(); //URI๋กœ ๋ฐ˜ํ™˜

        return ResponseEntity.created(location).build();
        //์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ์ ์ ˆํ•œ ์ƒํƒœ ์ฝ”๋“œ๋ฅผ ๋ณด๋‚ด์ฃผ๋Š” ๊ฒƒ์ด ์ข‹์€ api์ž„
    }



๐Ÿ‘‰ ์ƒํƒœ ์ฝ”๋“œ๋Š” 400 Bad Request ๋‹ค๋งŒ, body์— ์˜ˆ์™ธ ๋‚ด์šฉ ์ „๋‹ฌ์€ X




์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ๋ฉ”์‹œ์ง€๋ฅผ ์ถœ๋ ฅํ•˜๊ธฐ ์œ„ํ•ด ExceptionResponse์— ์˜ˆ์™ธ๋ฅผ ์ž‘์„ฑํ•œ๋‹ค.

๋‹ค์Œ๊ณผ ๊ฐ™์ด handleMethodArgumentNotValid ๋ฉ”์„œ๋“œ๋ฅผ ์žฌ์ •์˜ ํ•œ๋‹ค.


// CustomizedResponseEntityExceptionHandler Class

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(
					
                    MethodArgumentNotValidException ex,
                    HttpHeaders headers,
                    HttpStatus status,
                    WebRequest request) {
                           
	 ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), 
		ex.getMessage(), ex.getBindingResult().toString());

     return new ResponseEntity(exceptionResponse, HttpStatus.BAD_REQUEST);
    }



๐Ÿ‘‰ ์ƒํƒœ ์ฝ”๋“œ๋Š” 400 Bad Request ๋™์ผ, body์— ์˜ˆ์™ธ ๋‚ด์šฉ ์ „๋‹ฌ O




Refactoring ๐Ÿ‘‰


// CustomizedResponseEntityExceptionHandler Class ๐Ÿ‘‰ ์ˆ˜์ •

ExceptionResponse exceptionResponse = new ExceptionResponse(new Date(), 
	"Validation Failed", ex.getBindingResult().toString());
// User Class ๐Ÿ‘‰ ์ˆ˜์ •

@Size(min=2, message = "Name์€ 2๊ธ€์ž ์ด์ƒ ์ž…๋ ฅํ•ด ์ฃผ์„ธ์š”.") // ์ตœ์†Œ ๊ธธ์ด 2๊ฐœ ์ด์ƒ
private String name;

๐Ÿ‘‰ Body์˜ ์˜ˆ์™ธ message, details ๋‚ด์šฉ์ด ์ˆ˜์ •ํ•œ ๋Œ€๋กœ ์ „๋‹ฌ๋œ๋‹ค.





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


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


  • (์ œ๊ณตํ•˜๊ณ ์ž ํ•˜๋Š” ์–ธ์–ด๋ณ„๋กœ ์ง€์—ญ ์ฝ”๋“œ, ์–ธ์–ด ์„ค์ •์— ๋”ฐ๋ผ ์ ์ ˆํ•˜๊ฒŒ ํ‘œ์‹œ)

  • ํŠน์ • Controller์— ํ•œํ•ด์„œ๊ฐ€ ์•„๋‹ˆ๋ผ Project ์ „๋ฐ˜์ ์œผ๋กœ ์ ์šฉ



  • ๋‹ค๊ตญ์–ด ์ฒ˜๋ฆฌ์— ํ•„์š”ํ•œ bean์„ Spring Boot Application์— ๋“ฑ๋ก
@SpringBootApplication
public class RestfulWebServiceApplication {

	public static void main(String[] args) {
		SpringApplication.run(RestfulWebServiceApplication.class, args);
	}

	@Bean
	public LocaleResolver localeResolver() { // ์›น ์š”์ฒญ๊ณผ ๊ด€๋ จํ•ด์„œ Locale์„ ์ถ”์ถœํ•˜๊ณ  ์ด Locale ๊ฐ์ฒด๋ฅผ ์ด์šฉํ•ด์„œ ์•Œ๋งž์€ ์–ธ์–ด์˜ ๋ฉ”์‹œ์ง€๋ฅผ ์„ ํƒ
		SessionLocaleResolver localeResolver = new SessionLocaleResolver(); // Session์— Locale ์ •๋ณด๋ฅผ ๋„ฃ๊ณ  ์ด๋ฅผ ํ†ตํ•ด ๋‹ค๊ตญ์–ด๋ฅผ ์ฒ˜๋ฆฌํ•ด ์ฃผ๋Š” ์—ญํ• 
		localeResolver.setDefaultLocale(Locale.KOREA);
		return localeResolver;
	}

}



  • @bean์„ ๋“ฑ๋กํ•˜๊ฒŒ ๋˜๋ฉด SpringBoot๊ฐ€ ์ดˆ๊ธฐํ™”๋  ๋•Œ, ํ•ด๋‹น ๋นˆ์— ํ•ด๋‹นํ•˜๋Š” ์ •๋ณด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ๊ฐ™์ด ๋“ฑ๋ก

  • application.yml์— ์‚ฌ์šฉํ•  ๋‹ค๊ตญ์–ด ํŒŒ์ผ ๋“ฑ๋ก

  • Resource์— ๋‹ค๊ตญ์–ด ํŒŒ์ผ(properties) ์ƒ์„ฑ


// Controller

	@Autowired
    private MessageSource messageSource;

    @GetMapping(path = "/hello-world-internationalized")
    public String helloWorldInternationalized(
            @RequestHeader(name = "Accept-Language", required=false) Locale locale) {
        return messageSource.getMessage("greeting.message", null, locale);
    }



locale ๊ฐ’์„ ์ง€์ •ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ๐Ÿ‘‰ default_locale๊ฐ’์ธ ํ•œ๊ตญ์–ด ๋ฆฌํ„ด

ex) Headers์— KEY(Accept-Language) VALUE(fr) ๐Ÿ‘‰ ํ”„๋ž‘์Šค์–ด ๋ฆฌํ„ด

์ข‹์€ ์›นํŽ˜์ด์ง€ ์ฆ๊ฒจ์ฐพ๊ธฐ