-
[๊ฐ์] ์คํ๋ง MVC 2ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์ 4SPRING/INFLEARN 2023. 3. 20. 19:49
https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-mvc-2
์คํ๋ง MVC 2ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํ์ฉ ๊ธฐ์ - ์ธํ๋ฐ | ๊ฐ์
์น ์ ํ๋ฆฌ์ผ์ด์ ๊ฐ๋ฐ์ ํ์ํ ๋ชจ๋ ์น ๊ธฐ์ ์ ๊ธฐ์ด๋ถํฐ ์ดํดํ๊ณ , ์์ฑํ ์ ์์ต๋๋ค. MVC 2ํธ์์๋ MVC 1ํธ์ ํต์ฌ ์๋ฆฌ์ ๊ตฌ์กฐ ์์ ์ค๋ฌด ์น ๊ฐ๋ฐ์ ํ์ํ ๋ชจ๋ ํ์ฉ ๊ธฐ์ ๋ค์ ํ์ตํ ์ ์
www.inflearn.com
4. ๊ฒ์ฆ1 - Validation
โป ๊ฒ์ฆ
- ์ปจํธ๋กค๋ฌ์ ์ค์ํ ์ญํ ์ค ํ๋๋ HTTP ์์ฒญ์ด ์ ์์ธ์ง ๊ฒ์ฆํ๋ ๊ฒ์ด๋ค.
- ํด๋ผ์ด์ธํธ ๊ฒ์ฆ์ ์กฐ์์ด ๊ฐ๋ฅํ์ฌ ๋ณด์์ ์ทจ์ฝํ๋ฉฐ, ์๋ฒ๋ง์ผ๋ก ๊ฒ์ฆํ๋ฉด ์ฆ๊ฐ์ ์ธ ๊ณ ๊ฐ ์ฌ์ฉ์ฑ์ด ๋ถ์กฑํด์ง๋ฏ๋ก ์ด ๋์ ์ ์ ํ ์์ด์ ์ฌ์ฉํ๋ค. ์ต์ข ์ ์ธ ์๋ฒ ๊ฒ์ฆ์ ํ์๋ค.
โป ๊ฒ์ฆ ๋ฐฉ๋ฒ๋ค
v1
error๋ฅผ Map์ผ๋ก ๋ง๋ค๊ณ ,
if๋ฌธ์ผ๋ก ๊ฒ์ฆ์ ํ ๋ค์, ์๊ธด ์ค๋ฅ๋ฅผ error Map์ ๋ด์์
model.getAttribute("error",error);๋ก ์๋ฌ ๋งต์ ๋ฃ์ด์ view ํ์ผ๋ก redirectํ๋ค.
view์์๋ ์๋์ฒ๋ผ ์๋ฌ ์ฌ๋ถ๋ฅผ ๊ฐ์ ธ์จ๋ค.
<label for="itemName" th:text="#{label.item.itemName}">์ํ๋ช </label> <input type="text" id="itemName" th:field="*{itemName}" th:class="${errors?.containsKey('itemName')} ? 'form-control field-error' : 'form-control'" class="form-control" placeholder="์ด๋ฆ์ ์ ๋ ฅํ์ธ์"> <div class="field-error" th:if="${errors?.containsKey('itemName')}" th:text="${errors['itemName']}"> ์ํ๋ช ์ค๋ฅ </div>
๋จ์ : ํ์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ฉด ์ปจํธ๋กค๋ฌ์ ๋ค์ด์ค๊ธฐ๋ ์ ์ ์๋ฌ๊ฐ ๋ฐ์ํ๊ธฐ ๋๋ฌธ์ ํ์ ์๋ฌ ์ฒ๋ฆฌ๋ฅผ ํ ์ ์๋ค.
์ค๋ณต์ด ๋ง๋ค.
๊ณ ๊ฐ์ด ์ ๋ ฅํ
v2
๋งต์ ๋ง๋ค์ง ์๊ณ , ์คํ๋ง์์ ์ง์ํ๋ BindingResult๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
ํ๋ผ๋ฏธํฐ๋ก BindingResult๊น์ง ๋ฐ์์ค๊ณ
if๋ฌธ์ผ๋ก ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ์ฌ
bindingResult.addError(new ObjectError("item", "๊ฐ๊ฒฉ * ์๋์ ํฉ์ 10,000์ ์ด์์ด์ด์ผ ํฉ๋๋ค. ํ์ฌ ๊ฐ = " + resultPrice)); ๊ผด๋ก ์๋ฌ๋ฅผ ์ฒ๋ฆฌํ๋ค.
+ ObjectError vs FieldError
ํ๋์ ์ค๋ฅ๊ฐ ์์ผ๋ฉด FieldError(์ค๋ฅ ๋ฐ์์ ์ฌ์ฉ์ ์ ๋ ฅ ๊ฐ ์ ์ง ๊ธฐ๋ฅ ์ ๊ณต)
ํน์ ํ๋๋ฅผ ๋์ด์๋ ์ค๋ฅ๊ฐ ์์ผ๋ฉด ObjectError
BindingResult⊂Errors๋ผ์ ๋ฐ๊ฟ ์จ๋ ๋์ง๋ง ๊ธฐ๋ฅ์ด ์ ์
View์์๋ ์๋์ฒ๋ผ ๊ฐ์ ธ๋ค ์ฌ์ฉํ๋ค.
<label for="itemName" th:text="#{label.item.itemName}">์ํ๋ช </label> <input type="text" id="itemName" th:field="*{itemName}" th:errorclass="field-error" class="form-control" placeholder="์ด๋ฆ์ ์ ๋ ฅํ์ธ์"> <!--th:field๋ก ์ธํด ๋ชจ๋ ๊ฒ ๋ค ๋จ--> <div class="field-error" th:errors="*{itemName}"> ์ํ๋ช ์ค๋ฅ </div>
BindingResult๊ฐ ์์ผ๋ฉด ์ค๋ฅ๊ฐ ์๊ฒจ๋ ์ปจํธ๋กค๋ฌ๋ฅผ ํธ์ถํด์ค๋ค ->์์ผ๋ฉด ์์ ์ค๋ฅํ์ด์ง๋ก ๊ฐ๋ฒ๋ฆผ
- ๋ฐ์ ->
๋ฉ์ธ์ง ํ์ผ์ฒ๋ผ errors.properties ํ์ผ์ ๋ง๋ค์ด ๋ฐ๋ก ๊ด๋ฆฌํ๋ ๋ฐฉ๋ฒ์ด ์๋ค. ๊ตญ์ ํ๋ ๊ฐ๋ฅํ๋ค.
- ๋ฐ์ ->
FieldError๋ ObjectError๋ฅผ ์์ฑํ์ง ์๊ณ
bindingResult.rejectValue("price", "range", new Object[]{1000, 1000000}, null);
์ด๋ ๊ฒ๋ง ์์ฑํ ์๋ ์๋ค.
์๋ฌ ์ฝ๋๋ errors.properties ์์ ํ๋๋ช ๊ณผ ์กฐํฉํด์ ์ฐพ์์ค๋ค.
(ex)range.item.price, range.price, range.java.lang.Integer, range)
์ฌ๋ฌ ๊ฐ ์๋ ๊ฒฝ์ฐ, ๊ตฌ์ฒด์ ์ธ ์๋ถํฐ ์ฐ์ ์์๋ก ์ฌ์ฉํ๋ค. (์ค๋ฅ ๋ฉ์ธ์ง ์ฌ์ฌ์ฉ ๊ฐ๋ฅ)
MessageCodesResolver๊ฐ ์ด๋ฐ ๊ธฐ๋ฅ์ ์ง์ํ๋ค.
โป Validatior ๋ถ๋ฆฌ
Validator๋ฅผ implementํด์ CustomValidator๋ฅผ ๋ง๋ ๋ค.
CustomValidator ์์๋ bindingResult๋ฅผ ํ๋ผ๋ฏธํฐ๋ก ๋ฐ์,
if๋ฌธ์ผ๋ก ์๋ฌ๋ฅผ ์ฒดํฌํ๊ณ ์๋ฌ๋ฅผ bindingResult์ ์ ์ฅํ๋ค.
customValidator.validate(target, bindingResult); ํ ์ค๋ก validation์ ํ ์ ์๋ค.
-๋ฐ์ ->
@InitBinder public void init(WebDataBinder dataBinder) { log.info("init binder {}", dataBinder); dataBinder.addValidators(itemValidator); }
์ validator๋ค์ ๋ฑ๋กํด๋๋ฉด,
ํ๋ผ๋ฏธํฐ์ ๊ฒ์ฆํ ๊ฐ์ฒด ์์@Validated๋ฅผ ๋ถ์์ผ๋ก์จ ๊ฒ์ฆ์ ์ ์ฉํ ์ ์๋ค.
5. ๊ฒ์ฆ2 - Bean Validation
โป Bean Validation
๊ฒ์ฆ ์ฝ๋๋ฅผ ์ ๋ ธํ ์ด์ ํ๋๋ก ๋๋ด์
๊ฒ์ฆ ์ ๋ ธํ ์ด์ ๋ชจ์:
Hibernate Validator 6.2.5.Final - Jakarta Bean Validation Reference Implementation: Reference Guide
Validating data is a common task that occurs throughout all application layers, from the presentation to the persistence layer. Often the same validation logic is implemented in each layer which is time consuming and error-prone. To avoid duplication of th
docs.jboss.org
@Data public class Item { private Long id; @NotBlank private String itemName; @NotNull @Range(min = 1000, max = 10000) private Integer price; @NotNull @Max(9999) private Integer quantity; }
๊ฒ์ฆ ์์
1. @ModelAttribute ๊ฐ๊ฐ์ ํ๋์ ํ์ ๋ณํ ์๋
1. ์ฑ๊ณตํ๋ฉด ๋ค์์ผ๋ก
2. ์คํจํ๋ฉด typeMismatch ๋ก FieldError ์ถ๊ฐ
2. Validator ์ ์ฉ-> ๋ฐ์ธ๋ฉ์ ์ฑ๊ณตํ ํ๋๋ง Bean Validation ์ ์ฉ
๋ฐ์ธ๋ฉ์ ์ฑ๊ณตํ์ง ๋ชปํ๋ฉด ์ผ๋จ TypeMismatch๊ฐ ๋จผ์ ๋ฌ๋ค
์ฃผ์ : ๊ธ๋ก๋ฒ Validator๋ฅผ ์ง์ ๋ฑ๋กํ๋ฉด Bean Validator๊ฐ ๊ธ๋ก๋ฒ Validator๋ก ๋ฑ๋ก๋์ง ์๋๋ค.
โป ObjectError
@ScriptAssert(lang = "javascript", script = "_this.price * _this.quantity >=
10000") ๋ฐฉ์์ ์ฌ์ฉํ๋ฉด ์ฒ๋ฆฌํ ์ ์๋๋ฐ, ์ต์ง์ธ ๋ถ๋ถ์ด ์ข ์๋ค. -> ์ด ๋ถ๋ถ๋ง ์๋ฐ ์ฝ๋๋ก ์ฒ๋ฆฌํ๋ ๊ฒ ์ฐจ๋ผ๋ฆฌ ๋์โป Groups
@Validated ๋ ์คํ๋ง ์ ์ฉ ๊ฒ์ฆ ์ ๋ ธํ ์ด์ ์ด๊ณ , @Valid ๋ ์๋ฐ ํ์ค ๊ฒ์ฆ ์ ๋ ธํ ์ด์ ์ด๋ค
Validated๋ groups๊ฐ ๊ฐ๋ฅํด์, Validation class๋ค์ ๋ฑ๋ก์์ผ ๋๊ณ , ํ์ํ ๊ฒ๋ง ์ฌ์ฉํ ์ ์๋ค.
@Data public class Item { @NotNull(groups = UpdateCheck.class) private Long id; @NotBlank(groups = {SaveCheck.class, UpdateCheck.class}) private String itemName; @NotNull(groups = {SaveCheck.class, UpdateCheck.class}) @Range(min = 1000, max = 10000) private Integer price; @NotNull(groups = {SaveCheck.class, UpdateCheck.class}) @Max(9999) private Integer quantity; }
@PostMapping("/add") public String addItemV5(@Validated(SaveCheck.class) @ModelAttribute Item item, BindingResult bindingResult, RedirectAttributes redirectAttributes, Model model) { @PostMapping("/{itemId}/edit") public String edit(@PathVariable Long itemId, @Validated(UpdateCheck.class) @ModelAttribute Item item, BindingResult bindingResult) {
โป Form ์ ์ก ๊ฐ์ฒด ๋ถ๋ฆฌ
์ค๋ฌด์์๋ ์ฌ์ค ๋ฑ๋ก, ์์ ์ ๊ฒฝ์ฐ ๋ฐ๋ ๋ฐ์ดํฐ๊ฐ ์์ ๋ค๋ฅด๋ค.
๋ฐ๋ผ์ groups๋ฅผ ์ฌ์ฉํ๋ ๊ฒ๋ณด๋ค ์์ ๋ณ๋์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๋ซ๋ค.
โป @ModelAttribute vs @RequestBody
(@ModelAttribute ๋ HTTP ์์ฒญ ํ๋ผ๋ฏธํฐ(URL ์ฟผ๋ฆฌ ์คํธ๋ง, POST Form)๋ฅผ ๋ค๋ฃฐ ๋ ์ฌ์ฉํ๋ค.
@RequestBody ๋ HTTP Body์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฒด๋ก ๋ณํํ ๋ ์ฌ์ฉํ๋ค. ์ฃผ๋ก API JSON ์์ฒญ์ ๋ค๋ฃฐ ๋
์ฌ์ฉํ๋ค.)RequestBody์๋ Valid, Validated๋ฅผ ์ ์ฉํ ์ ์์.
ํ์ง๋ง, @ModelAttribute ๊ฐ๊ฐ์ ํ๋ ๋จ์๋ก ์ธ๋ฐํ๊ฒ ์ ์ฉ๋จ -> ํน์ ํ๋๊ฐ ๋ฐ์ธ๋ฉ ๋์ง ์์๋ ๋๋จธ์ง ํ๋ ์ฌ์ฉ ๊ฐ๋ฅ
๋ฐ๋ฉด @RequestBody๋ HttpMessageConverter ๋จ๊ณ์์ JSON ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ฒด๋ก ๋ณ๊ฒฝํ์ง ๋ชปํ๋ฉด ์ดํ
๋จ๊ณ ์์ฒด๊ฐ ์งํ๋์ง ์๊ณ ์์ธ๊ฐ ๋ฐ์ํ๋ค. ์ปจํธ๋กค๋ฌ๋ ํธ์ถ๋์ง ์๊ณ , Validator๋ ์ ์ฉํ ์ ์๋ค.'SPRING > INFLEARN' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[๊ฐ์] ์คํ๋ง MVC 1ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์ 1 (0) 2023.03.13 [๊ฐ์] ์คํ๋ง MVC 2ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์ 5 (0) 2023.01.30 [๊ฐ์] ์คํ๋ง MVC 2ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์ 3 (0) 2023.01.13 [๊ฐ์] ์คํ๋ง MVC 2ํธ - ๋ฐฑ์๋ ์น ๊ฐ๋ฐ ํต์ฌ ๊ธฐ์ 1 (0) 2022.11.21 [๊ฐ์] ์ค์ ! Querydsl 1 (0) 2022.08.22