인프런 커뮤니티 질문&답변

hanul_kr님의 프로필 이미지
hanul_kr

작성한 질문수

스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술

폼을 통해 받은 데이터를, 직접 만든 Model에 매핑하는 방법

해결된 질문

작성

·

921

0

강사님 안녕하세요, 
본편 강의를 다 듣고 혼자 토이 프로젝트를 만들다가 막혀서 질문올립니다.

단순하게 Form을 통해서 데이터를 받아 처리하는 내용입니다
그런데 감이 없어 어느 방법이 나이스한 방법인지 모르겠습니다.

1. 직접 만든 모델 클래스는 아래와 같이 생겼습니다.

2. List타입의 필드는 HTML FORM의 element들에 같은 name을 가져와서 바인딩하려합니다

 @ModelAttribute는 내부적으로 set메소드를 부르니 역시나 매핑이 안 되더라구요..

그래서 생각해본 방법으로는

  1. 하나하나 RequestParam으로 받아서 처리한다 (List는 MultiValueMap으로)
  2. setMethod의 파라미터를 String으로 받아 setMethod에서 내부적으로 처리한다
  3. front 데이터를 Json으로 변환하여 파싱한다 (컨트롤러에서 Model에 접근)
  4. 커스텀 어노테이션을 만들고, HandlerMethodArgumentResolver를 implement해서 MyModelResolver를 만들고 @Configuration한다

폼을 통해 받은 데이터를 직접 만든 Model에 매핑하는 방법을
보통은 어떻게 구현하는건가요?


ps.

사실 저는..

1~3번이, 제 눈에는 코드가 안예뻐 보였습니다...
아뇨 사실은 좋은 현업 코드를 본 적이 없기 때문에 뭐가 예쁜지 안 예쁜지도 모르겠습니다
4번으로 만들면 앞단에선 지금처럼 쓰기 편하고, 스프링 내부도 공부할 수 있을 것 같아서 시도해봤습니다.

그런데,
메시지 바디로 넘어온 쿼리 파라미터형식의 methodName에 매칭되는 setMethodName이 있는지, 
데이터는 들어있는지,
데이터 타입은 뭔지, 변환해줘야하는지..
이런게 너무어렵습니다..

이렇게 하다보니 제가 뭘 모르는지도 모른다는 생각이 듭니다.

별것도 아닌 것 같은 것을 어떻게 구현하는게 좋은건지 판단도 못 하는 자신이 너무 바보같습니다ㅠㅠ

답변 3

3

hanul_kr님의 프로필 이미지
hanul_kr
질문자

넵 맨위에 영한님과, OMG님의 코드를 보구
@ModelAttribute가 컬렉션 필드를 가지는 커스텀 객체(중첩된)를  받을 수 있게 수정할 수 있었습니다

JPA강의 진짜 듣고싶어졌습니다 ㅎㅎ 

고맙습니다!!

굿굿👍
열공하세용~

hanul_kr님의 프로필 이미지
hanul_kr
질문자

(❁´◡`❁)

김영한님의 프로필 이미지
김영한
지식공유자

크! OMG님 감사합니다.

3

MVC1편 강의에서 다루는 예제가 프리미티브 타입의 심플한 예제(name, age)로 강의가 구성되어 있어

조금 복잡하고 스케일이 큰 상황에서의 적용 방법이 난해하시다고 판단 되는데요.

아래 코드(MVC 패턴의 폼 데아터 처리) 보시고 본인의 프로젝트에서 적용 가능한 방법과 예제 인 것 같으면

영한님의  <실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발> 강의 보시는 걸 추천드립니다.

(해당 강의 코드 입니다.)

서버단 코드

@GetMapping(value = "/order")
public String createForm(Model model) {
List<Member> members = memberService.findMembers();
List<Item> items = itemService.findItems();

model.addAttribute("members", members);
model.addAttribute("items", items);
return "order/orderForm";
// 주문에 필요한 회원, 상품 정보를 모델에 담아 폼 데이터 화면에 내려줍니다
}

@PostMapping(value = "/order")
public String order(@RequestParam("memberId") Long memberId, @RequestParam("itemId") Long itemId,
@RequestParam("count") int count) {
orderService.order(memberId, itemId, count);
return "redirect:/orders";
} // 폼 데이터에서 선택한 항목들을 @RequestParam을 통해 받아옵니다. 만약 item을 복수로 받아 오고 싶다면
// List<Long> itemIds
로 바꾸면 될 거 같네요.

클라이언트단 코드

<form role="form" action="/order" method="post">
<div class="form-group">
<label for="member">주문회원</label>
<select name="memberId" id="member" class="form-control">
<option value="">회원선택</option>
<option th:each="member : ${members}"
th:value="${member.id}"
th:text="${member.name}" />
</select>
</div>
<div class="form-group">
<label for="item">상품명</label>
<select name="itemId" id="item" class="form-control">
<option value="">상품선택</option> <!-- 복수의 상품을 선택하고 싶다면 multipe 속성 추가(?) -->
<option th:each="item : ${items}"
th:value="${item.id}"
th:text="${item.name}" />
</select>
</div>
<div class="form-group">
<label for="count">주문수량</label>
<input type="number" name="count" class="form-control" id="count"
placeholder="주문 수량을 입력하세요">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
hanul_kr님의 프로필 이미지
hanul_kr
질문자

JPA강의를 들어야 할까 고민중이었는데 OMG님 덕분에 고민이 해결되었습니다.

프론트단의 코드까지 알려주시고 주석까지 달아주셔서 도움됐습니다 ㅠㅠ
정말 고맙습니다!

도움이 되었다니 다행이네요!
이 코드도 한번 보시겠어요? 비슷한 동작을 하는 코드인데 다른 코드를 보면 더 생각이 트이는게 있으실 거에요
간단하게 설명 드리면 1대N의 Employee(일)이 하는 Project(다) 의 관계를 포함하는 프로젝트 코드인데요
제가 위에 올린 영한님 강의 코드에서는 

@PostMapping(value = "/order")

public String order(@RequestParam("memberId") Long memberId, 
@RequestParam("itemId") Long itemId,
@RequestParam("count") int coun

이런식으로 프리미티브 타입의 id만 받아오잖아요?

근데 제가 아래에 첨부한 링크 코드에서는 이런식으로 Project를 객체로 받아올 수 있는 예제의 코드인데 영한님 MVC1편을 보셨다면 다 이해 되실거라고 생각해요.

@PostMapping("/save")
	public String createProject(Project project, @RequestParam List<Long> employees, Model model) {

JPA1편 강의 도움 많이 되실테니 꼭 보세요 ㅎㅎ

화면단 코드

https://github.com/imtiazahmad007/spring-framework-course/blob/master/src/main/resources/templates/projects/new-project.html

서버단 코드

https://github.com/imtiazahmad007/spring-framework-course/blob/master/src/main/java/com/jrp/pma/controllers/ProjectController.java

2

김영한님의 프로필 이미지
김영한
지식공유자

안녕하세요. hanul_kr님

@ModelAttribute는 중첩을 처리합니다.

1. 단순 중첩: 프로퍼티 이름. 프로퍼티 이름

2. 컬렉션 중첩: 프로퍼티 이름[index]. 프로퍼티 이름

예제로 알려드릴게요.

package com.example.modelattribute.web;

import lombok.Data;

import java.util.List;

@Data
public class UserForm {

private String username;
TeamForm team;
List<TeamForm> teams;
}

package com.example.modelattribute.web;

import lombok.Data;

@Data
public class TeamForm {

private String teamName;
}

package com.example.modelattribute.web;

import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FormController {

/**
* 폼에서 전달하는 name
* username
* team.teamName
* teams[0].teamName
* teams[1].teamName
*
*/
@PostMapping("/form/go")
public UserForm go(UserForm form) {
return form;
}

}

결과

도움이 되셨길 바래요^^

hanul_kr님의 프로필 이미지
hanul_kr
질문자

해결 했습니다.

역시 이렇게 좋은 방법이 있었군요.. 스프링에 다 구현이 돼있다는 말을 좀 더 높은 우선순위로 생각하고, 맞는 방향으로 찾았다면 다다랐을 것 같은데..제가 부족한게 너무 많습니다.

쉬는날에도 답변주신 강사님 너무너무 감사드립니다.
강사님 강의를 듣고 원리부터 적용해나가자는 생각으로 구현된 스프링 라이브러리들, 자바 타입들 등을 읽고있는데 쉽사리 읽혀지진 않습니다만, 강사님 덕분에 코딩습관이 맞는 방향으로 가고있는 것 같아 행복합니다.

JPA강의도 듣도록 하겠습니다

항상 고맙습니다

hanul_kr님의 프로필 이미지
hanul_kr

작성한 질문수

질문하기