묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
@CookieValue 타입 컨버팅 관련
안녕하세요. 에러 해결이 어려워 질문을 남기게 되었습니다. 11:40까지 코드를 작성하고 localhost:8080으로 들어가면 Whitelabel Error Page가 뜨는데요. String 타입을 Long타입으로 바꾸는데 실패했다는거 같은데, 9:30에 말씀하신 컨버팅 기능에서 오류가 생긴걸까요? (경고 내용 텍스트: WARN 20100 --- [nio-8080-exec-1] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.lang.Long'; nested exception is java.lang.NumberFormatException: For input string: "test"]) 이 부분을 지우면 에러가 발생하지 않습니다. @CookieValue(name = "memberId", required = false) 두 컨트롤러의 코드는 다음과 같습니다. LoginController.java package hello.login.web.login;import hello.login.domain.login.LoginService;import hello.login.domain.member.Member;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Controller;import org.springframework.validation.BindingResult;import org.springframework.validation.annotation.Validated;import org.springframework.web.bind.annotation.GetMapping;import org.springframework.web.bind.annotation.ModelAttribute;import org.springframework.web.bind.annotation.PostMapping;import javax.servlet.http.Cookie;import javax.servlet.http.HttpServletResponse;@Slf4j@Controller@RequiredArgsConstructorpublic class LoginController { private final LoginService loginService; @GetMapping("/login") public String loginForm(@ModelAttribute("loginForm") LoginForm form) { return "login/loginForm"; } @PostMapping("/login") public String login(@Validated @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response) { if (bindingResult.hasErrors()) { return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if (loginMember == null) { bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } //로그인 성공 처리 //쿠키에 시간 정보를 주지 않으면 세션 쿠키 (브라우저 종료시 모두 종료) Cookie idCookie = new Cookie("memberId", String.valueOf(loginMember.getLoginId())); response.addCookie(idCookie); return "redirect:/"; }} HomeController.java package hello.login.web;import hello.login.domain.member.Member;import hello.login.domain.member.MemberRepository;import lombok.RequiredArgsConstructor;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Controller;import org.springframework.ui.Model;import org.springframework.web.bind.annotation.CookieValue;import org.springframework.web.bind.annotation.GetMapping;@Slf4j@RequiredArgsConstructor@Controllerpublic class HomeController { private final MemberRepository memberRepository; // @GetMapping("/") public String home() { return "home"; } @GetMapping("/") public String homeLogin(@CookieValue(name = "memberId", required = false) Long memberId, Model model) { if (memberId == null) { return "home"; } //로그인 Member loginMember = memberRepository.findById(memberId); if (loginMember == null) { return "home"; } model.addAttribute("member", loginMember); return "loginHome"; }}
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
th:block 활용
th:block을 현업에서 많이 사용할까요? div두개를 큰 div나 다른 구역을 나누는 html 태그로 나누고 th:each돌리는것보다 렌더링시에 제거되는거 말고 얻을 수 있는 장점이 있을까요?
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
AOP 적용 질문
안녕하세요 AOP 중 궁금한점이 생겨 질문드립니다! [질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 질문을 쭉 봤는데 해당 내용이 없었습니다.3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)네[질문 내용] 이부분에서 찍어보면 다음과 같이 EnhancedBySpring~ 이부분이 스프링이 AOP 를 처리하기 위해 프록시로 복제된 객체로, AOP를 사용하게되면 사용된다는 내용으로 이해했습니다. 강의 자료에 보면, 다음과 같은 내용이 있는데, AOP와 관련된 코드들 (예제에서는 시간을 측정하는 코드, 시간측정하는 클래스를 주입하는 코드)을 제거 한 후에도 MemberController 에서 Service 클래스를 sout 으로 찍어볼 경우, 똑같이 EnhancedBySpring~ 하는 객체가 찍혀 나옵니다. 이 부분이 위에 AOP 적용 전 그림 에서 진짜 객체들만 사용한다는 위 그림과 과 맞지 않는데, 그렇다면 Spring 에서는 AOP 관련된 코드가 없어도 자동적으로 AOP를 위해 프록시 객체를 사용하도록 강제(?) 처리 되는건지 궁금합니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
webapp index.html 관련
webapp 폴더 추가 후index.html을 생성 후 서버를 기동시키고 접속하였을 때 Whitelabel Error Page가 발생 할 경우 입니다. Intellij에서 빈 모듈(spring-mvc) 생성 후 빈 모듈 안에서 새로운 모듈(servlet)을 생성하였을 경우 index.html에 접속이 되지 않는 것 같습니다. 실행 후 Tomcat의 로그에서도 WelcomePage 관련 로그가 출력되지 않았으며 http://localhost:8080과 http:localhost:8080/index.html에 접속할 수 없었습니다. 이후 프로젝트를 종료하고 빈 모듈(spring-mvc)이 아닌 빈 모듈 안에서 생성한 새로운 모듈(servlet)의 build.gradle을 통해 프로젝트를 새로 연 후 서버를 기동하면 WelcomePage 관련 로그가 출력 되며 http://localhost:8080에 문제없이 index.html에 접속할 수 있었습니다. 원인은 아직 잘 모르겠지만 멀티 모듈 또는 빈 모듈에서 새로운 모듈을 생성한 경우 Intellij에서 webapp을 찾지 못하는것 같습니다.
-
미해결실전! 스프링 데이터 JPA
선생님 질문이 있습니다!
안녕하세요! 강의 재밌게 수강하고 있습니다! 실례가 안 된다면 혹시 선생님께서 말씀하시는 핵심 비즈니스 로직과 화면 혹은 API에 맞춘 로직의 차이점을 간단하게 설명해주실 수 있으실까요? 저는 화면에 출력하거나 API를 만드는 게 곧 핵심 비즈니스 로직이라고 생각했는데 제가 잘못 생각하고 있었던 거 같아 혹시 도움을 받을 수 있을까 하여 질문 남기게 됐습니다 ㅠ + Trade off는 어떤 의미로 이해하면 좋을까요? ㅠㅠ P.S 비전공자로 여러 강의를 들으면서 선생님 강의 만난 게 최고의 행복인 거 같습니다! 종종 PPL 하시는 JPA 책도 잘 읽고 있는데 언젠가 기회가 되면 선생님께 싸인 받고 싶습니다 ㅋㅋㅋ 존경합니다 선생님!
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
app-plain.jar의 역할
안녕하세요, 수강 중에 궁금한 점이 있어 질문드립니다. :) 스프링 부트 프로젝트를 ./gradlew build 명령어로 빌드를 하고 나면, hello-plain.jar와 hello.jar의 두 개의 jar 파일이 생성됩니다. 구글링을 해 본 결과, 스프링 부트에서 빌드하면 Plain Archive도 함께 만들어지며 이를 방지하고 싶으면 build.gradle에 별도의 설정을 하면 되는 것, 그리고 Plain Archive가 무엇인지도 알게 되었습니다. 그런데 Plain Archive는 어디에 쓰려고 만들어진 건지, 목적이 무엇인지를 모르겠습니다. 의존성이 포함되지 않은 파일이 왜 필요한 건가요?
-
미해결스프링부트 시큐리티 & JWT 강의
BycryptPasswordEncoder 주입시 순화참조 문제
저는 mac m1버전 인텔리제이 spring boot 2.64 버전 java8 로 하고있습니다. 저도 13:41 BycryptPasswordEncoder를 주입하니 SecurityConfig와 순환참조가 걸려 진행이 되지 않았습니다. 그래서 PrincipalOauth2UserService에서 private BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder(); 이렇게 생성하여서 진행하였습니다. 혹시 강의를 보시는 다른 분들을 위해 참고 코드를 남겼습니다.
-
미해결실전! 스프링 데이터 JPA
entitygraph관련 궁금증
안녕하세요!! 만들어주신 로드맵을 열심히 공부하고 있는 학생입니다! @entityGraph와 관련하여 추가적인 궁금증이 있어 질문드립니다. 먼저 해당 내용에 대해 repository 내에서 findAll() 메소드를 상속받아, 여기에 fetch join을 부여해 주는 것으로 이해했는데요 혹시 이렇게 상속받으면 findAll 메소드 자체가 바로 fetch join을 진행하는것이 아닐까 해서요 예를 들어 A 위치에서는 member의 변수만을 필요로 하고, B 위치에서는 team까지 가져오려 하면 A에서는 LAZY로 유지되는 것이 좋고, B에서는 바로 fetch join하는 것이 나을 거라 생각하는데 위의 방식이면 둘 다 바로 fetch join을 진행할 것 같다고 생각하는데 이게 맞을까요?? 혹시 맞다면 어떤 식으로 고치는것이 더 최적화될지 궁금합니다.... --- 추가로 혹시 @entityGraph는 무조건 left outer join에서만 적용되는 것일까요??
-
미해결스프링 핵심 원리 - 기본편
자신의 클래스에서 자신을 static으로 선언하는 부분 재 질문입니다.
안녕하세요. 앞전에 질문드렸던 내용이 계속 이해되지 않아서 정리 후 재 질문 남깁니다. 먼저 제 생각은 이렇습니다. 애플리케이션이 실행되는 시점에 .java 파일은 .class파일로 바뀌어서 사용되고, static 영역에 static 변수들이 세팅됩니다. 이 두개의 경우 중 적어도 한 경우에 SingletonService 클래스의 private static final SingletonService instance = new SingletonService(); 이 코드가 실행될 수 밖에 없다고 생각합니다. 위의 그림은 해당 코드가 실행될 때를 나타내본 것입니다. 해당 그림의 인스턴스에 들어오는 값들을 보면 static 멤버변수, 메소드, 생성자 등 모든 클래스의 구성요소들이 들어오게 됩니다. 이 중 저는 static 멤버변수 부분이 의아합니다. 이에 관련되어 두가지 질문사항이 있습니다. 1. static 영역에는 50의 참조값을 가지는 instance 객체가 생성 되었습니다. 하지만 그 인스턴스 실제 값을 보면 private static final SingletonService instance = new SingletonService(); 이 코드가 들어가 있습니다. 이때 저는 `이코드가 무한 반복된다.`, 또는 `이미 instance라는 변수가 static 영역에 선언되어 있기 때문에 에러가 난다.` 두가지 중 하나의 일이 발생할 것으로 추정해 말이 안되는 코드 아닌가라는 의문이 생깁니다. 그럼에도 불구하고 잘 작동하는 것을 보니 제가 생각한 부분이 틀렸고, 모르는 부분이 존재하는 것으로 생각됩니다. 실제로 이 부분이 어떻게 동작하며 실행되는지 자세히 알고 싶습니다. 2. 두번째 질문은 private static final SingletonService instance = new SingletonService(); 이라는 줄이 실행될 때 실행 시점에 관련한 의문입니다. 이 코드가 실행될 시점은 .class 파일을 만들려고 .java 파일을 읽거나 instance 변수를 static 영역에 등록하려고 해당 코드를 실행시키거나 하는 두 시점 중 하나라고 생각이 듭니다. 두 시점 중 해당 코드가 실행되는 순간을 보면, 첫 줄에 멤버변수가 작성되어 있기 때문에 클래스의 뒷 부분인 메소드, 생성자는 아직 존재하지 않는다고 생각합니다. 그렇다면 인스턴스에 값을 채워서 참조값을 올릴때, 인스턴스에 넣을 값이 멤버변수 빼고는 존재하지 않는데 어떻게 코드가 동작하고 있는지에 관련해 의문이 남습니다. 이부분도 제가 모르는 것이 있거나 잘못 알고 있는 부분이 있는 것 같습니다. 관련된 자세한 설명과 동작방식을 알고 싶습니다. 고맙습니다.
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
왜 UUID로 find하지 않고 SESSION_COOKIE_NAME으로 find 하나요?
왜 UUID로 find하지 않고 SESSION_COOKIE_NAME으로 find 하나요? 그렇게하면 보안상 사용한다던 UUID가 의미가 없지않나요? 해킹하는 사람 입장에서는 쿠키 이름만 알아도 정보를 가져올수있으니까요
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
{itemId} 매핑원리 질문입니다.
@PostMapping("/{itemId}/edit")public String edit(@PathVariable long itemId,@ModelAttribute Item updateParam) { itemRepository.update(itemId,updateParam); return "redirect:/basic/items/{itemId}"; } 위 코드의 메서드가 실행될 때, {itemId} 에 @PathVariable long itemId 가 매핑되는데 매핑되는 원리가 궁금합니다.
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
세션 형태 관련 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 직접 만든 세션에서는 세션id로 UUID를 이용해서 랜덤한 값을 만들어서 세션 보관을 하고 이 세션id를 쿠키의 값으로 전달했는데 HttpSession의 경우는 쿠키가 다음과 같다고 하셨습니다. JSESSIONID=5B78E23B513F50164D6FDD8C97B0AD05 그럼 5B78E23B513F50164D6FDD8C97B0AD05 가 톰캣이 만든 세션id인가요? 다른 글에서 세션들을 보관하는 세션 저장소가 하나 더 있다고 봤는데 위에서 랜덤값인 세션 id가 key 이고 value가 Map(편의상 Map2) 인 Map형태의 세션 저장소가 있고 value인 Map2 또한 세션 저장소로 랜덤한 세션id 로 인증된 특정한 사용자만 사용하는건가요? Map2에서 저희가 session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember); 등록한게 있는거 같구요. 만약 제가 생각한게 맞다면 굳이 왜 이런 형태를 이용하나요? 직접 만든 Session 처럼 처음부터 랜덤한 값을 세션 키로 이용하면 Map 하나로 해결될것 같아서요.
-
미해결스프링 핵심 원리 - 기본편
안녕하세요. 아래 스윙님이 하신 질문과 동일한 질문입니다.
저도 해당 내용이 궁금해서 질문을 남기려다가 답변 내용을 보고 그렇구나 하고 넘어갔습니다. 하지만 뭔가 이상해서 질문 남깁니다. 스윙님의 질문 내용은 왜 config 클래스에 @Configuration을 붙이지 않았는데 싱글톤으로 관리가 되느냐였습니다. 그 답변은 스프링 컨테이너로 직접 등록하면 싱글톤으로 관리가 된다였구요. 그런데 다음강의의 ConfigurationSingletonTest 클래스의 configurationTest를 보고, 강의를 들으면 AppConfig에 @Configuration이 있기 때문에 싱글톤으로 관리가 되고 있다고 합니다. 또한 제거하면 유지가 되지 않는다고 하고있고요. 그 사실을 찍어서 객체 생성이 몇번 일어나는지, 객체가 동일한지로 판단하고 있습니다. 보시다시피 해당 메서드에서는 스프링 컨테이너를 통해 AppConfig를 설정 파일로 쓰고 있습니다. 그렇다면 스윙님의 질문에 대한 답변에 의하면 @Configuration이 붙던, 아니던 싱글톤이 유지되어야 하는데, 이 강의 회차의 주 내용이 @Configuration이 있기 때문에 싱글톤이 유지되고, 없다면 유지되지 않는다는 내용이라서 이부분에 대해서 재차 궁금합니다. 따라서 TestConfig에 @Configuration을 붙이지 않은 이유와 붙이지 않아도 싱글톤으로 작동한 이유가 궁금합니다. 제가 잘못 이해한 부분이 있으면 설명 부탁드리겠습니다. 감사합니다.
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
Order 생성 메서드
안녕하세요 Order 생성 메서드를 setter없이 작성해봤는데 올바르게 작성했는지 궁금해서 질문드립니다. 강의코드 /** * 생성 메서드 */public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) { Order order = new Order(); order.setMember(member); order.setDelivery(delivery); for (OrderItem orderItem : orderItems) { order.addOrderItem(orderItem); } order.setStatus(OrderStatus.ORDER); order.setOrderDate(LocalDateTime.now()); return order;} 제가 작성한 setter를 사용하지 않은 생성 메서드 public Order(Member member, Delivery delivery, LocalDateTime orderDate, OrderStatus status) { this.member = member; this.delivery = delivery; this.orderDate = orderDate; this.status = status;}public static Order createOrder(Member member, Delivery delivery, OrderItem... orderItems) { Order order = new Order(member, delivery, LocalDateTime.now(), OrderStatus.ORDER); for (OrderItem orderItem : orderItems) { order.orderItems.add(orderItem); } return order;} 이렇게 작성했습니다. 올바르게 작성했는지 궁금합니다.
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
itemRepository.save(item); 부분에서 궁금한 것이 있습니다 !
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요 영한님, 서포터즈님! 강의 너무너무 잘 보고있습니다. 다름이 아니라 itemRepository.save(item) 부분에서 궁금한게, 영한님은 따로 Item savedItem 이라는 변수를 만들어서 redirectAttributes.addAttribute("itemId", savedItem.getId()) 이렇게 사용하시는데 저는 굳이 변수를 따로 만드는게 아니라, @ModelAttribute Item item 객체를 가지고 redirectAttributes.addAttribute("itemId", item.getId()); 라고 상용해도 되지 않을까? 라는 궁금증이 생겼습니다. 실행은 문제가 없었는데, 문제될 점이 따로 있을까요 ?
-
미해결스프링 핵심 원리 - 기본편
생성자를 통한 주입 테스트 질문
OrderServiceImpl orderService = new OrderServiceImpl(memberRepository, new FixDiscountPolicy()); 이렇게 써야 하는데, OrderServiceImpl orderService = new OrderServiceImpl(new MemoryMemberRepository(), new FixDiscountPolicy()); 이렇게 써도 실행이 잘 됩니다. 위에서 new MemoryMemberRepository()를 한 후, save까지 지정한 것은 맞지만, OrderServiceImpl 을 new 로 생성하면서 생성자로 new MemoryMemberRepository를 파라미터로 전달하였으니 위에서 직접 save로 생성한 객체가 아니라 새롭게 생성된 MemoryMemberRepository가 전달되는 것 아닌가요? 그러면 널포인트가 터져야할 것 같은데 왜 테스트가 성공하나요..?
-
미해결스프링 핵심 원리 - 기본편
저도 static 선언부 이해가 안가네요..
안녕하세요. 최근에 어떤분이 질문하신 내용과 답변을 봤는데도 저렇게 선언해서 사용하는 것에 대해서 이해가 안가네요.. static에 대해서는 이해가 가고, 첨부해주신 링크도 다 읽었습니다. 하지만 강의에서 SingletonService 클래스를 작성할때 private static final SingletonService instance = new SingletonService();를 선언하고 사용하는 것에 대해서 흐름이 이해가 가질 않습니다. 메모리에 static 영역에 SingletonService 클래스와 instance라는 변수가 올라가는 것인가요? 만약 올라가던, 안올라가던 상관없이 어떤 맥락으로 자신의 클래스에서 자신의 인스턴스를 만들어서 사용하는지 모르겠습니다. 보통 클래스를 생성하면 다른 곳에서 인스턴스를 생성해 사용하는 것을 많이 봤는데요.. 자신의 클래스 첫줄에 자신을 선언한다라는게 무엇을 뜻하고, 어떻게 사용되는지 어떻게 공부해볼 수 있을까요? 왜 굳이 사용할 곳에서 인스턴스를 생성하는게 아닌 저런 방법이 사용되는지도 모르겠고, 동작 방식이나 그런걸 모르겠습니다. 저게 재귀 그런건가요? 솔직히 전 질문자님도 모르는걸 정리해서 묻기 힘든 모습이셨는데, 저도 그렇네요. 이 부분에 대해 어떻게 해결할 수 있을지 도움좀 부탁드리겠습니다. 감사합니다.
-
미해결스프링 핵심 원리 - 기본편
isNotEqualTo, isNotSameAs 두개 같은건가요?
안녕하세요. 이 두개를 구글링 해보니까 실제 값이 주어진 값과 같은지 틀린지라는 말인데, 결국 같은말 아닌가요? `==` 비교도 값만 비교하는 거니까 isEqualTo의 실제 값을 비교하는거랑 같다고 생각이드네요. 근데 만약 두개가 같다면 저렇게 중복되서 존재할 이유가 없다고 생각이 들어서 질문 남기게 됐습니다. 감사합니다.
-
해결됨실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
member는 생성 메서드를 만들지 않은 이유가 있나요?
member는 생성 메서드를 따로 만들지 않고 그냥 MemberRepository에서 저장, 조회를 했는데 Order와 OrderItem에만 생성 메서드를 만들어줬나요? 단지 단순한 로직(다른 엔티티에서 값을 가져와서 처리하는 비즈리스 로직이 없어서)이라서 Member 엔티티는 생성 메서드를 만들어 주지 않은 건가요?
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
update 로직 짤때
위 사진처럼 짜면 put으로 있던 id에 updateParam으로 덮어씌워져서 업데이트 되는거 아닌가요? 테스트도 정상적으로 작동하는데 위에 4줄로 작성하면 더 좋은점이 어떤게 있나요?