private static final String VIEWS_OWNER_CREATE_OR_UPDATE_FORM = "owners/createOrUpdateOwnerForm";
์ง๊ธ๊น์ง ๋ด๊ฐ ์ฌ์ฉํ๋ ์์กด์ฑ ์ฃผ์ ์ Repository ๊ฐ์ฒด๊ฑด Service ๊ฐ์ฒด๊ฑด ๋ชจ๋ ๋น์ผ๋ก ๋ฑ๋กํ๊ณ @Autowired ์ด๋ ธํ ์ด์ ์ ์ด์ฉํด Controller์์ ์ฃผ์ ๋ฐ๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ค. ๊ทธ๋ฐ๋ฐ Pet Clinic์์๋ ๊ทธ ๋์ ๋ณ์๋ฅผ private final๋ก ์ ์ธํ๊ณ ์์ฑ์์์ ๊ฐ์ฒด๋ฅผ ํ ๋น๋ฐ๋ ๋ฐฉ์์ ์ฌ์ฉํ๋ค.
private final OwnerRepository owners;
public OwnerController(OwnerRepository clinicService) {
this.owners = clinicService;
}
๊ทธ๋ฅ ํ์ ๊ฒ ๊ฐ์ง ์๊ณ ๋ญ๊ฐ ์ด์ ๊ฐ ์์ผ๋ฆฌ๋ผ ์๊ฐํด์ ์ฐพ์๋ดค๋ค. ์์กด์ฑ ์ฃผ์ ๋ฐฉ๋ฒ์๋ ํฌ๊ฒ ์ธ ๊ฐ์ง๊ฐ ์๋ค๊ณ ํ๋ค. ์ฒซ ๋ฒ์งธ๋ก๋ ํ๋ ์ฃผ์ ๋ฐฉ์, ๋ ๋ฒ์งธ๋ก ์์ ์ ์ฃผ์ ๋ฐฉ์, ๋ง์ง๋ง์ผ๋ก ์์ฑ์ ์ฃผ์ ๋ฐฉ์์ด ์๋ค.
์ด ๋ฐฉ์์ ๋ด๊ฐ ์ฃผ๋ก ์ฌ์ฉํ๋ ๋ฐฉ์์ด๋ค. ์์ ์ฝ๋๋ฅผ ํ๋ ์ฃผ์ ๋ฐฉ์์ผ๋ก ๋ฐ๊พธ์๋ฉด
@Autowired
private OwnerRepository owners;
์ด๋ฐ ์ฝ๋๊ฐ ๋ ๊ฒ์ด๋ค. Controller์ ์ฃผ์ ํ ๋น ๊ฐ์ฒด๋ ๋ฐ๋ก ๋น ๊ฐ์ฒด๋ผ๊ณ ๋ฑ๋กํด์ผ ์ฃผ์ ํ ์ ์๋ค. ์ฝ๋๊ฐ ๊ฐ๊ฒฐํ๋ค๋ ์ฅ์ ์ด ์์ผ๋ ์ถ์ฒํ๋ ๋ฐฉ์์ ์๋๋ผ๊ณ ํ๋ค. ํ๋ ์ฃผ์ ์ ํตํด ์์กด์ฑ์ ์ฃผ์ ํ๊ฒ ๋๋ฉด ์ธ๋ถ์์ ์์ ์ด ๋ถ๊ฐ๋ฅํ๊ณ , ํ ์คํธ ์ผ์ด์ค๋ฅผ ์์ฑํ ๋ ๊ฐ์ฒด๋ฅผ ์์ ํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ํ๋ ์ฃผ์ ์ ํตํด ์์กด์ฑ์ ์ฃผ์ ํ๋ค๋ฉด final ํค์๋๋ฅผ ํตํ ์ ์ธ์ด ๋ถ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด๊ฐ mutable ํด์ง๋ค. ๋ํ, ์์กด์ฑ ์ฃผ์ ์ ๋จ๋ฐํ๊ฒ ๋ ์ ์๊ธฐ ๋๋ฌธ์ ๋จ์ผ ์ฑ ์์ ์์น์ ์๋ฐฐํ ์ ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์ ์ง์ํด์ผ ํ๋ค.
์ด ๋ฐฉ์์ Setter ๋ฉ์๋๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์ฃผ์ ๋ฐ๋ ๋ฐฉ์์ด๋ค. ์์ ์ฝ๋๋ฅผ ์์ ์ ์ฃผ์ ๋ฐฉ์์ผ๋ก ๋ฐ๊พธ์๋ฉด
private OwnerRepository owners;
public setOwnerController(OwnerRepository clinicService) {
this.owners = clinicService;
}
์ด๋ฐ ์ฝ๋๊ฐ ๋ ๊ฒ์ด๋ค. Setter ๋ฉ์๋๋ ๊ด๊ณ๋ฅผ ์ฃผ์ ๋ฐ๋ ๊ฐ์ฒด์ ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ด ์๊ธฐ ๋๋ฌธ์ ํ์ํ ๊ฒฝ์ฐ๋ง ์ฌ์ฉํด์ผ ํ๋ค. ํ์ง๋ง ๋ณดํต์ ๊ฒฝ์ฐ ๊ฐ์ฒด๊ฐ ๋ณ๊ฒฝ๋ ์ผ์ด ์๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํ ์ผ์ด ๋๋ฌผ๋ค. ๋ณ๊ฒฝ ๊ฐ๋ฅ์ฑ์ ์ด์ด๋๊ฒ ๋๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ ์ํ์ด ๋๊ธฐ ๋๋ฌธ์ ์ฌ์ฉ์ ์ง์ํด์ผ ํ๋ค.
์ด ๋ฐฉ์์ ์์ฑ์๋ฅผ ํตํด ๊ฐ์ฒด๋ฅผ ์ฃผ์ ๋ฐ๋ ๋ฐฉ์์ด๋ค. ๋งจ ์ฒ์์ ์๊ฐํ ์ฝ๋๊ฐ ์์ฑ์ ์ฃผ์ ์ ์ฌ์ฉํ ์ฝ๋์ด๋ค. ์์ฑ์๋ ๊ฐ์ฒด๊ฐ ์์ฑ๋ ๋ ํ ๋ฒ๋ง ํธ์ถ๋๋ ํน์ฑ์ด ์๊ธฐ ๋๋ฌธ์ immutable ํ๋ค. final ํค์๋๋ก ์ ์ธํ ์ ์๋ค. ์ด ๋ฐฉ์์ ์ฃผ์ ๋ฐ์ ๊ฐ์ฒด๊ฐ ๋ถ๋ณ์ด์ด์ผ ํ๊ฑฐ๋, ๋ฐ๋์ ๊ฐ์ฒด์ ์ฃผ์ ์ด ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉํ๊ฒ ๋๋ค. ๋ค๋ฅธ ๋ฐฉ์๋ค์ Spring๊ณผ ๊ฐ์ ํ๋ ์์ํฌ์์ ๋์ํ๊ธฐ ๋๋ฌธ์ ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ๊น๋ค๋กญ๋ค. (์์กด์ฑ ์ฃผ์ ์ ํ๋ ์์ํฌ์์ ๋ด๋นํ๋๋ฐ ํ ์คํธ ์ฝ๋๋ ํ๋ ์์ํฌ์์ ๋์ํ๋ ๊ฒ์ด ์๋๊ธฐ ๋๋ฌธ) ํ์ง๋ง ์์ฑ์ ์ฃผ์ ๋ฐฉ์์ ์ด์ฉํ๋ค๋ฉด ํ ์คํธ ์ฝ๋ ์์ฑ์ด ์ฝ๋ค. ๋ํ ๊ฐ๋ฐ์์ ์ค์๋ก ์ํ ์ฐธ์กฐ๋ฅผ ํ๊ฒ ๋ ๊ฒฝ์ฐ ๋ค๋ฅธ ๋ฐฉ์๋ค์ ๋ฐํ์ ์๋ฌ๊ฐ ๋๋ ๋ฐ๋ฉด ์์ฑ์ ์ฃผ์ ๋ฐฉ์์ ์ปดํ์ผ ์๋ฌ๊ฐ ๋๊ธฐ ๋๋ฌธ์ ์๋ฌ๋ฅผ ์์ ํ๊ธฐ ๋ ์ข๋ค.
๊ฐ์์ ์ฅ๋จ์ ์ด ์์ง๋ง ์์ฑ์ ์ฃผ์ ๋ฐฉ์์ด ์ฅ์ ์ด ์กฐ๊ธ ๋ ๋ง๊ธฐ ๋๋ฌธ์ ์์ฑ์ ์ฃผ์ ๋ฐฉ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ ๊ฒ ๊ฐ๋ค. ์ถ๊ฐ๋ก ๋กฌ๋ณต(Lombok)์ @RequiredArgsConstructor ์ด๋ ธํ ์ด์ ์ ์์ฑ์๋ฅผ ์์ฑํ์ง ์์๋ ์์์ ๋ง๋ค์ด ์ฃผ๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํ๊ธฐ ํธ๋ฆฌํ๋ค. ๋กฌ๋ณต์ ์ฌ์ฉํ๊ธฐ ์ํด์๋ ๊ฐ์ฒด๋ฅผ ์ฃผ์ ํ ๋ณ์๋ฅผ final๋ก ์ ์ธํ๊ณ ๊ทธ ์์ ์์ ์ด๋ ธํ ์ด์ ์ ๋ถ์ฌ์ฃผ๋ฉด ๋๋ค.
@InitBinder๋ ์์ํ ์ด๋ ธํ ์ด์ ์ด์๋ค. ์ง๊ธ๊น์ง (๋ง์ด ํด๋ณธ ๊ฑด ์๋์ง๋ง) ์งํํ๋ ํ๋ก์ ํธ์์๋ ์ปจํธ๋กค๋ฌ์ ๊ตฌ์ฑ์ ๋ฐ์ดํฐ๋ฒ ์ด์ค ๊ด๋ จ ์๋น์ค ๊ฐ์ฒด๊ฐ ์๊ณ @GetMapping์ด๋ @PostMapping์ ์ด๋ ธํ ์ด์ ๋ค์ ์ฌ์ฉํด์ ๊ฒฝ๋ก ์ค์ ์ ํด์ฃผ๊ณ ๊ฒฝ๋ก์ ๋ํ ์ฒ๋ฆฌ๋ฅผ ์ด๋ป๊ฒ ํ ์ง ์ฝ๋๋ฅผ ์์ฑํ๋ ๊ฒ ๋ค์๋ค. ์ด ์ด๋ ธํ ์ด์ ์ด ์ด๋ค ์ญํ ์ ํ๊ณ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ๊ถ๊ธํด์ ์ฐพ์๋ดค๋ค.
@InitBinder ์ด๋ ธํ ์ด์ ์ @Controller๋ @ControllerAdvice ํด๋์ค๊ฐ ๊ฐ์ง ์ ์๊ณ , WebDataBinder๋ฅผ ์ด๊ธฐํํ๋ค. ์ฝ๊ฒ ๋งํด ํด๋ผ์ด์ธํธ๋ก๋ถํฐ ๋ค์ด์ค๋ ๋ฆฌํ์คํธ ํ๋ผ๋ฏธํฐ๋ฅผ ๋ชจ๋ธ ๊ฐ์ฒด์ ๋ฐ์ธ๋ฉํ๋ค๋ ์๋ฏธ์ด๋ค. ๋ชจ๋ ์์ฒญ ์ ์ @InitBinder๊ฐ ๋ถ์ ๋ฉ์๋๋ฅผ ์คํํ๋ค๊ณ ํ๋ค.
setAllowedField์ setDisallowedField๋ฅผ ํตํด ํ์ฉํ ํ๋, ํ์ฉํ์ง ์์ ํ๋๋ฅผ ์ค์ ํ ์ ์๋ค. addCustomFormatter๋ฅผ ํตํด ํ๋์ ํ์์ ์ง์ ํ ์๋ ์๋ค. ๋ํ, addValidators๋ฅผ ํตํด ์ ํจ์ฑ ๊ฒ์ฆ์ ํ ์ ์๋ค. ์ด ๋ฐ์๋ ์ฌ๋ฌ ๋ฉ์๋๊ฐ ์์ด ์ฌ๋ฌ ์ค์ ์ฌํญ์ ์ง์ ํ ์ ์๋ค.
Pet Clinic์์๋ setDisallowedField์ addValidators๋ฅผ ์ฌ์ฉํ๊ณ ์๋ค. addValidators๋ ์ ์ฐ๋์ง ์ดํด๊ฐ ๊ฐ๋๋ฐ setDisallowedField๋ ์ ์ฌ์ฉํ๋์ง ์ดํด๊ฐ ์ ๊ฐ์ ์ฐพ์๋ดค๋๋ฐ ๋ค๋ค ์ฌ์ฉ๋ฒ๋ง ์๋ ค์ฃผ๊ณ ์ ์ฐ๋์ง๋ ์๋ ค์ฃผ์ง ์๋๋ค. ์ค๊น...? ์์ด๋ ํ๋๋ ์์ฒญ์ด ๋ค์ด์๋ ์๋ฒ์์ ๊ฒฐ์ ํ๋ ๊ฐ์ด๊ธฐ ๋๋ฌธ์ ๊ทธ๋ฐ๊ฐ..? ์๋ฌดํผ @InitBinder๋ ๋ ์ฐพ์๋ด์ผ ํ ๊ฒ ๊ฐ๋ค.
์ง๊ธ๊น์ง ๋ดค์๋ @ModelAttribute ์ด๋ ธํ ์ด์ ์ ๋ฉ์๋์ ํ๋ผ๋ฏธํฐ๋ก ์ฃผ์ด์ง๋ ๊ฐ์ ๋ถ์ด์๋ ๊ฒฝ์ฐ๋ง ๋ดค์๋ค. ํ์ง๋ง Pet Clinic์์ ์ฌ์ฉํ๋ ๊ฒ์ ๋ฉ์๋ ์์ ๋ถ์ด์์๋ค. ์ด๋ @InitBinder๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก ์์ฒญ์ด ๋ค์ด์์ ๋ @ModelAttribute๊ฐ ์์ฒญ ์ฒ๋ฆฌ ์ ๋จผ์ ์คํ๋๋ค. @InitBinder๊ฐ ๋ค์ด์ค๋ ๊ฐ์ฒด๋ฅผ ๋ด์ ๋ ์ฌ์ฉํ๋ค๋ฉด @ModelAttribute๋ ๋ฉ์๋์ ๋ฐํ ๊ฐ์ ํด๋ผ์ด์ธํธ์ ๋ณด๋ผ model ๊ฐ์ฒด์ ๋ด๋ ์ญํ ์ ํ๋ค.
Controller๋ค์ ๋ณด๋ฉฐ ์์ํ ๊ฐ๋ ๋ค์ ์ ๋ฆฌํ๋ค ๋ณด๋ ๊ธ์ด ๊ธธ์ด์ก๋ค. Pet Clinic์ Controller ๋ถ์์ ๋ค์ ๊ธ์์ ํ ์์ ์ด๋ค. ๊ฐ์ฒด์ ์์กด์ฑ์ ์ฃผ์ ํ ๋ ์์ฑ์ ๋ฐฉ์์ ์ฌ์ฉํ๋ ๊ฒ์ด ์ฅ์ ์ด ๋ง๋ค๋ ๊ฒ์ ์๊ฒ๋์ด ์ข์๋ค. ๊ทธ๋ฐ๋ฐ @InitBinder๋ ์ ํจ์ฑ ๊ฒ์ฌ ์ธ์ ์ด๋ค ์ด์ ๋ก ์ฌ์ฉํ๋์ง ์์ง ๊ฐ์ด ์ ์์ ๋ ์์๋ด์ผ ํ ๊ฒ ๊ฐ๋ค.
๊ฐ์ฒด ์์ฑ์ ์ฃผ์
-
https://programforlife.tistory.com/111
@InitBinder -
https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-initbinder
https://goodgid.github.io/Spring-MVC-InitBinder/
https://stackoverflow.com/questions/3801477/why-setdisallowedfields-for-id-spring-petclinic-example
@ModelAttribute -
https://memo-the-day.tistory.com/200