인프런 커뮤니티 질문&답변
안녕하세요 질문입니다
해결된 질문
작성
·
382
2
=========================================
[질문 템플릿]
1. 강의 내용과 관련된 질문인가요? (예/아니오)
2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)
3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)
[질문 내용]
여기에 질문 내용을 남겨주세요.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class BoardForm {
private Long id;
private String name;
private String title;
private String content;
public BoardForm(Long id, String name, String title, String content) {
this.id = id;
this.name = name;
this.title = title;
this.content = content;
}
public static BoardForm createBoardForm(Board board){
return new BoardForm(board.getId(), board.getName(), board.getTitle(),board.getContent());
}
위처럼 @NoArgsConstructor(access = AccessLevel.PROTECTED)일떄는 문제가 없는데
패키지를 옮기다보니 엑세스레벨을 퍼블릭으로 바꾸엇더니 값이 들어오질않습니다.
혹시나해서 다시 컨트롤러와 같은 패키지에 폼클래스를 옮기고 해봐도 안되서 실험을 이것저것해보니
같은패키지에 잇더라도 엑세스레벨이 퍼블릭이면 html로 부터 값이 계속 null이 들어오고 다시 프로펙트로바꾸면 값이들어옵니다
퍼블릭이 더 넓은개념인데 왜 값이 안들어오고 프로텍트로 하면 들어오는지 아무리 찾아봐도 나오질않아서 질문드려요
1.같은 패키지에 컨트롤러와 폼클래스가 있을경우 폼클래스 기본생성자에노테이션을 public으로하면 왜 값을 html로부터
받지못하고 protect로 해야 받아지는지 궁금합니다
2.패키지를 옮기면 프로텍트를 못쓰니 컨트롤러와 같은패키지에 폼클래스들을 무조건 두어야하는건가요?
3.그리고 추가적으로 entity클래스도 기본적으로 기본생성자어노테이션을 protected로 설정하는걸로 알고있는데요(무분별한 외부접근을 막기위해) entity패키지를 만들어 entity들을 같이 모아야하다보니 또 protected를 쓸수가 없는데
패키지를 entity, controller, form을 다 나누어서 두는게 맞는거같은데 접근제한자문제 때문에 protected를 쓰면 같은패키지에 둬야하고 public으로 해야 각각 다른패키지에 둘수잇는지 이문제는 어떻게 해야할지요
감사합니다
답변 1
1
안녕하세요. 김윤호님, 공식 서포터즈 y2gcoder입니다.
1.
=> 기본적으로 @ModelAttribute 를 통해 객체를 바인딩하기 위해서는 두 가지 방식이 가능합니다.
1) 기본생성자 + Setter
2) 해당 파라미터들을 매개변수로 하는 생성자
둘 중 1번방식이 더 우선순위를 가집니다.
김윤호님의 코드를 보니 그동안 @ModelAttribute에 바인딩할 때 기본생성자가 protected로 되어있어 2번 방식으로 했고, public으로 접근제어자를 풀어주셨을 때는 스프링이 1번방식으로 바인딩하려고 했으나 Setter가 없어 null로 값이 들어갔던 것으로 보입니다.
해당 과정을 보고 싶으시다면 Form 객체에서 lombok 대신 직접 생성자를 생성하신 뒤 생성자 두 개에 브레이크 포인트를 거신 후 디버그 모드로 애플리케이션을 실행하시고 postman으로 요청을 보내보시면 확인 가능합니다.
2.
=> 1. 에 따르면 그렇지는 않으니 패키지는 바꿀 수 있습니다. 다만 Controller > Service > Repository로 의존성이 이어지고 있는데 Repository에서 Controller 패키지 쪽에 있는 무언가를 import 한다면 패키지 의존성에 순환관계가 생깁니다. 이렇게 되면 나중에 프로젝트를 멀티모듈 구조로 바꾸기 위해 Service와 Repository만 분리할 때 Controller 패키지에서 import 해와서 사용하던 것 때문에 굉장히 귀찮아질 수 있습니다. 사용 범위와 가까이 두는 게 좋습니다.
3.
=> 생성자를 protected로 둬도 다른 생성자를 public으로 열어두신다면 다른 패키지에서 사용할 수 있습니다.
감사합니다.
안녕하세요!
1. protected 생성자로 해두시면 당연히 같은 패키지에서는 protected 생성자를 사용할 수 있습니다. 그러나 요청에 넘어온 파라미터들을 @ModelAttribute로 설정한 객체에 매핑해주는 역할을 해주는 것은 같은 패키지에 없습니다. 그래서 protected 생성자를 사용할 수 없어 2번 방식으로 바로 넘어갑니다. setter까지 있는지 체크하고 넘어가는 것이 아니라 protected 생성자를 사용할 수 없으니 다른 public 생성자를 찾게 됩니다.
2. 사실 form 객체나 dto 객체는 사용하는 곳만 명확히 제한해준다면 접근제어를 엄격하게 해줄 필요는 없습니다. 그래서 영한님도 DTO 류의 객체를 만드실 때는 실제로 @Data(안에 @Setter가 있습니다) 와 기본 생성자(생성자를 명시적으로 만들지 않으면 기본 생성자를 가지고 있습니다)를 많이 사용하신다고 종종 답변해주셨습니다. 저도 그렇고요. 엄격한 제한과 유연성 사이의 트레이드 오프 사이에서 선택하는 문제라고 생각합니다. 저라면 2번과 같이 사용해야한다면 public으로 풀 것 같습니다.
3. 지금 김윤호님께서 그렇게 사용하고 계십니다. 기본생성자는 protected 로 막고 있고, 모든 파라미터를 다 넣어야 하는 생성자는 public 으로 사용하고 계시지요. public으로 만든 생성자를 사용하시면 됩니다.
감사합니다!
안녕하세요 답변감사드립니다 한가지만 추가로 질문드리고 싶어요 나머지는 전부 이해햇습니다
그러나 요청에 넘어온 파라미터들을 @ModelAttribute로 설정한 객체에 매핑해주는 역할을 해주는 것은 같은 패키지에 없습니다
--->@ModelAttribute로 설정한 객체에 매핑해주는 역할을 해주는 것
이 역할을 해주는것이 스프링자체에 내장되어있는 어떤 인터페이스나 클래스인거같은데
이게 프로텍트로 설정된 기본생성자에에 접근할수없다 라고 이해했는데 맞게이해한걸까요?






안녕하세요 답변감사드립니다. 답변을 읽고 잘이해가 가지않는부분을 추가질문드리겠습니다
<1번 답변>
1번방식 - 기본생성자 + Setter
2번방식 - 해당 파라미터들을 매개변수로 하는 생성자
둘 중 1번방식이 더 우선순위를 가집니다.
코드를 보니 그동안 @ModelAttribute에 바인딩할 때 기본생성자가 protected로 되어있어 2번 방식으로 했고, public으로 접근제어자를 풀어주셨을 때는 스프링이 1번방식으로 바인딩하려고 했으나 Setter가 없어 null로 값이 들어갔던 것으로 보입니다.
--->현재 같은 패키지안에 controller와 form클래스가 있는데
기본생성자를 protected나 public으로 하는 경우 모두다 1번방식에서setter를 찾지
못하니까 자연스럽게 2번방식을 사용하는줄 알았는데 답변해주신 postman실험을 해보니
public의 경우 1번방식에서 setter를 찾지못해 값이 전부null로 들어오고 2번방식으로 아예 넘어가질않습니다. protected일 경우 2번방식으로실행되어 값을받게되는데
궁금한점이 같은패키지안에 있는데
protected는 1번으로 시도해서setter가없으니 2번으로 넘어가서 값을 받아오는데
public은 1번으로 시도하다가 setter가 없으면 2번방식으로 넘어가야하는데 왜 안넘어가고 null값이 들어오는지 이해가 되질않습니다.
<2번답변>
의존성의 순환관계는 이해하였습니다. 사용범위와 가까이 두는게 좋다고하셧고
controller단에서 view로만 넘기는 용도로 form클래스를 사용하기에 controller하위 패키지에
form패키지를 만들다 보니, 수업내용에서 나온것처럼 하다보면
@GetMapping("/write")
public String boardCreateForm(Model model) {
model.addAttribute("boardForm", new BoardForm() );
return "boardhtml/boardWrite";
}
new BoardForm()의 경우에 접근자가 protected라 생성자를 사용할수없는 문제가있습니다.
<3번답변>
생성자를 protected로 둬도 다른 생성자를 public으로 열어두신다면 다른 패키지에서 사용할 수 있습니다.
--->잘 이해가 가질않습니다.ㅜ 컨트롤러단에서 다른패키지에잇는 entity나 form이나
이런걸 protected이면 사용할수가 없는데 다른생성자를 public으로 열어두라는게 무슨말씀이신지..