묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
강의 들으면서 영한님께 여쭤보고 싶은게 있습니다!
강의 너무 잘 듣고 있습니다.강의 들으면서 영한님께 여쭤보고 싶은게 있습니다!MVC의 내부동작이나 스프링 프레임워크의 내부 동작은 어떤 방식으로 파악하시는지 궁금합니다.스프링 프레임워크가 너무 방대하다고 생각되서 디버깅으로 파악하기도 힘들다고 생각하는데, 어떤 방식으로 세세한 내부 구조를 파악하셨는지 궁금합니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
h2 연결
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예[질문 내용]h2로 웹사이트 들어가려는데 오류가 떠요 ㅠㅠ 왜이런거죠?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
PKIX path building failed
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]Spring Initilizr 을 통해 project generating 한 후 Intellij 에서 실행하니 초기 빌드 과정에서 아래와 같이 에러가 뜨는데요, 찾아보니 제가 지금 사내 pc 및 네트워크를 사용 중이어서 뜨는 인증서 오류인 것 같습니다. 혹시 관련하여 해결책을 주실 수 있으실까요?PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
index.html 사이트 연결할 수 없음
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]여기에 질문 내용을 남겨주세요.webapp 아래 index.html 파일 잘 위치해 있습니다.http://localhost:8080/index.html 주소로 들어가면 사이트 연결할 수 없음이라고 뜨고IDE에서 run하면 뜨는 브라우저 아이콘 4개 중 크롬을 누르게 되면 http://localhost:63342/servlet/servlet.main/webapp/index.html?_ijt=gol0djjmpsd9cm9s9v6ag90urr&_ij_reload=RELOAD_ON_SAVE위 주소로 index.html 파일이 잘 열립니다.혹시 어떤 문제 때문에 이러는 건가요?이와 연관된 문제인 건지는 모르겠으나 위에 긴 주소로 열린 index.html 파일에서 jsp 회원가입, 회원목록을 눌렀을 때도 404에러만 납니다.알려주신 위치에 디렉토리 생성하고 파일 제대로 만들었음에두요.
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
DI 적용해보기
안녕하세요. 항상 좋은 강의 감사합니다.FrontController에서 어댑터들을 DI로 적용할 수 있다고 하셔서 이를 구현해보고자 하였습니다.@WebServlet(name = "frontControllerServletV5", urlPatterns = "/front-controller/v5/*") public class FrontControllerServletV5 extends HttpServlet { ... @Autowired private Map<String, Object> handlerMappingMap; ... }처음에 컬렉션 객체들을 Bean으로 등록하여 주입받고자 HandlerMappingConfig클래스를 만들었습니다.@Configuration public class HandlerMappingConfig { @Bean public Map<String, Object> handlerMappingMap() { Map<String, Object> handlerMappingMap = new HashMap<>(); // V2 Controller handlerMappingMap.put("/front-controller/v5/v2/members/new-form", new MemberFormControllerV2()); handlerMappingMap.put("/front-controller/v5/v2/members/save", new MemberSaveControllerV2()); handlerMappingMap.put("/front-controller/v5/v2/members", new MemberListControllerV2()); // V3 Controller & V4 Controller ... return handlerMappingMap; } }그리고 제대로 주입을 받았는지 테스트하기 위해 FrontControllerServletV5 클래스의 service() 메소드에서 handlerMappingMap을 출력하도록 작성하였습니다.@WebServlet(name = "frontControllerServletV5", urlPatterns = "/front-controller/v5/*") public class FrontControllerServletV5 extends HttpServlet { ... @Autowired private Map<String, Object> handlerMappingMap; ... @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 정상적으로 주입되었는지 테스트하기 위해 출력 System.out.println("handlerMappingMap = " + handlerMappingMap); ... } }서버를 실행시켜 확인해보니 아래 그림과 같이 handlerMappingMap에 마치 컨테이너의 빈들이 다 들어온 것처럼 출력된 것을 확인할 수 있었습니다.왜 이런 현상이 나타나는지 모르겠습니다. 혹시 타입이 Map<String, Object>라 그런걸까요?감사합니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
인터셉터의 호출 순서 질문입니다.
강의를 따라가다 문득 preHandle, postHandle, afterCompletion 의 순서를 알고 싶어서 LoginCheckInterceptor 에 해당 메서드를 추가하여 로그를 찍어보았습니다.질문은 맨 밑에 있으며, 코드는 이해를 돕기 위해 첨부했습니다.LogInterceptor@Slf4j public class LogInterceptor implements HandlerInterceptor { public static final String LOG_ID = "logId"; @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler ) throws Exception { String requestURI = request.getRequestURI(); String uuid = UUID.randomUUID().toString(); request.setAttribute(LOG_ID, uuid); // @RequestMapping: HandlerMethod // 정적 리소스: ResourceHttpRequestMethod if (handler instanceof HandlerMethod) { // 호출할 컨트롤러 메서드의 모든 정보가 포함되어 있다. HandlerMethod hm = (HandlerMethod) handler; } log.info("[{}][{}] LogInterceptor preHandle", requestURI, uuid); return true; } @Override public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView ) throws Exception { String requestURI = request.getRequestURI(); String uuid = (String) request.getAttribute(LOG_ID); log.info("[{}][{}] LogInterceptor postHandle", requestURI, uuid); } @Override public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex ) throws Exception { String requestURI = request.getRequestURI(); String uuid = (String) request.getAttribute(LOG_ID); log.info("[{}][{}] LogInterceptor afterComplete", requestURI, uuid); if (ex != null) { log.error("LogInterceptor afterComplete Error: ", ex); ex.printStackTrace(); } } }LoginCheckInterceptor@Slf4j public class LoginCheckInterceptor implements HandlerInterceptor { @Override public boolean preHandle( HttpServletRequest request, HttpServletResponse response, Object handler ) throws Exception { String requestURI = request.getRequestURI(); String uuid = (String) request.getAttribute(LogInterceptor.LOG_ID); log.info("[{}][{}] LoginCheckInterceptor preHandle", requestURI, uuid); HttpSession session = request.getSession(); if (session == null || session.getAttribute(SessionConst.LOGIN_MEMBER) == null) { log.info("미인증 사용자 요청 {}", requestURI); response.sendRedirect("/login?redirectURL=" + requestURI); return false; } return true; } @Override public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView ) throws Exception { String requestURI = request.getRequestURI(); String uuid = (String) request.getAttribute(LogInterceptor.LOG_ID); log.info("[{}][{}] LoginCheckInterceptor postHandle", requestURI, uuid); } @Override public void afterCompletion( HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex ) throws Exception { String requestURI = request.getRequestURI(); String uuid = (String) request.getAttribute(LogInterceptor.LOG_ID); log.info("[{}][{}] LoginCheckInterceptor afterCompletion", requestURI, uuid); } }InterceptorConfig@Configuration public class InterceptorConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new LogInterceptor()) .order(1) .addPathPatterns("/**") // 모두 허용 .excludePathPatterns("/css/**", "/*.ico", "/error"); // BlackList registry.addInterceptor(new LoginCheckInterceptor()) .order(2) .addPathPatterns("/**") .excludePathPatterns( "/", "/members/css", "/login", "/logout", "/css/**", "*.ico", "/error" ); } }결과 1 - 미인증 사용자 요청// /items 요청 [/items][45e50a37-57a0-4298-b50e-e42141005426] LogInterceptor preHandle [/items][45e50a37-57a0-4298-b50e-e42141005426] LoginCheckInterceptor preHandle 미인증 사용자 요청 /items [/items][45e50a37-57a0-4298-b50e-e42141005426] LogInterceptor afterComplete // Redirect - /login [/login][18f052ab-b849-4690-83ec-43866660f570] LogInterceptor preHandle [/login][18f052ab-b849-4690-83ec-43866660f570] LogInterceptor postHandle [/login][18f052ab-b849-4690-83ec-43866660f570] LogInterceptor afterComplete로그상으로 LoginCheckInterceptor의 afterComplete가 누락되었습니다.결과2 - 정상 처리// /login 요청 [/login][19bad338-e02d-4bbe-8b3a-5dfc55ad4428] LogInterceptor preHandle LoginService: 'test', 'test!' login? Member(id=1, loginId=test, name=테스터, password=test!) [/login][19bad338-e02d-4bbe-8b3a-5dfc55ad4428] LogInterceptor postHandle [/login][19bad338-e02d-4bbe-8b3a-5dfc55ad4428] LogInterceptor afterComplete // Redirect - /items [/items][679dc279-ff3a-4ee3-a424-26b18ac8dbbd] LogInterceptor preHandle [/items][679dc279-ff3a-4ee3-a424-26b18ac8dbbd] LoginCheckInterceptor preHandle [/items][679dc279-ff3a-4ee3-a424-26b18ac8dbbd] LoginCheckInterceptor postHandle [/items][679dc279-ff3a-4ee3-a424-26b18ac8dbbd] LogInterceptor postHandle [/items][679dc279-ff3a-4ee3-a424-26b18ac8dbbd] LoginCheckInterceptor afterCompletion [/items][679dc279-ff3a-4ee3-a424-26b18ac8dbbd] LogInterceptor afterCompletepreHandle은 order의 순위대로 로그가 찍히는데, postHandle과 afterCompletion의 경우 order의 순위와 반대로 호출이 됩니다. 혹시 위 2개의 결과에 대한 이유를 설명해주실 수 있을까요..? 그냥 로직때문에 그런 것인지 궁금합니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
서버 단에서 input 태그의 type 속성을 확인하는법
서버는 http요청을 통해 form 태그를 이용한 데이터가 들어올 때, form 태그 내부에 있는 input 태그의 type 속성 값을 어떻게 알 수 있나요? 인코딩되는 과정에서 type 속성 값이 어딘가 저장되는 건가요?
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
7:50 api 호출시 exception이 발생하면 WebServerCustomer 클래스 호출하는 이유
안녕하세요 선생님~단순한 질문이 하나 있는데요!컨트롤러에서 Exception이 발생하면 반대로인터셉터 -> 서블릿 -> 필터 -> WAS로 예외를 넘겨주고 WAS에서 에러 페이지를 찾는다는 것에 대해서는 이해를 했는데, WebServerCustomizer 클래스를 호출한건 WebServerFactoryCustomizer라는 인터페이스를 구현했기 때문에 해당 클래스를 스프링 컨테이너가 인지하고 호출한건가요?
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
*.jsp 주소로 이동하면 jsp파일 다운로드가 됩니다
안녕하세요./jsp/members/new-form.jsp 경로로 이동하면 페이지 이동이 안되고 new-form.jsp 파일을 다운로드 하는 창이 나타납니다.영한님이 작성하신 코드를 복붙했는데도 이런 현상이 나타 납니다.왜 이러는지 이유를 모르겠습니다 ㅠㅠ
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
Spring boot 없이 thymeleaf 사용못하나요?
스프링 부트없이 Spring 사용하려하는데 jsp로 작업했던 파일을 thymeleaf로 변경하기 위해 html파일도 만들고 suffix도 변경해주었는데 아래와 같은 에러가 나옵니다.No mapping for GET /WEB-INF/view/register.htmljsp로 바꿔서 하면 잘되는데 suffix만 html로 바꾸면 페이지를 찾지를 못하네요ㅠㅠ 원래 thymeleaf가 spring boot에서만 사용가능한 것 일까요?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
h2 연결시 JDBC URL
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 안녕하세요. H2 연결할때jdbc:h2:~/test (최초 한번)이렇게 해서 ~/test.mv.db 파일 생성 되는지 확인을 했습니다.접속도 됩니다.근데, 이후부터는 jdbc:h2:tcp://localhost/~/test 이렇게 접속 하라고하는데, jdbc:h2:~/test 은 접속이 가능한데, jdbc:h2:tcp://localhost/~/test 이렇게 쓰면 Connection is broken: "java.net.SocketTimeoutException: connect timed out: localhost" [90067-200] 90067/90067 (도움말)이 에러가 뜨면서 들어가지지 않습니다.어떻게 해야할까요??
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
@Controller 사용시 HTTP 요청 과정 질문 / 핸들러 어댑터 과정
1. 클라이언트가 HTTP 요청을 한다( http://localhost:8080/springmvc/v1/members/new-form ) 2. DispatcherServlet 에서 핸들러를 조회를 한다 @Controller public class SpringMemberFormControllerV1 { @RequestMapping("/springmvc/v1/members/new-form") public ModelAndView process() { return new ModelAndView("new-form"); } } 서버에 등록되어 있는 핸들러(컨트롤러) @Controller : 핸들러 등록하기 @RequestMapping : 클라이언트가 요청한 URL 과 매핑 후 메서드를 실행한다. 3. 이 조회한 핸들러를 처리할 수 있는 핸들러어댑터를 조회하고 이 어댑터를 통해서 핸들러(컨트롤러)를 호출한다. 전 시간에는 핸들러 어댑터 리스트들을 다 만들어서 iter 돌려서 핸들러를 처리할 수 있는 어댑터를 찾고 그 핸들러 어댑터가 핸들러를 호출하도록 하였습니다 이번시간에 이 과정들은스프링 내부에서 다 해준다는 말인가요 ? 이 내부 과정들을 이해했다면 저는 @RequestMapping 으로 클라이언트의 요청과 처리할 메서드를 매핑하고 @Controller 로 핸들러를 등록하기만 하면 되는건가요?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
외부 패키지가 연결이 되지 않는다고 나옵니다.
질문은 총 2개입니다. 이 밑에 있는 사진을 참고해서 질문을 봐주시면 될 것 같습니다. 감사하겠습니다. 1. MemoryMemberRepository이 외부 패키지에서 연결이 되지 않는다고 하는데 이 말이 무엇인지 이해가 되지 않습니다. 이 문제를 어떻게 해결하면 좋을까요..? <왼쪽 오류>hello.hellospring.repository.MemoryMemberRepository is not public in hello.hellospring.repository; cannot be accessed from outside package <오른쪽 오류>java: hello.hellospring.repository.MemoryMemberRepository is not public in hello.hellospring.repository; cannot be accessed from outside package (혹시 몰라 코드도 함께 올립니다.)package hello.hellospring.service; import hello.hellospring.domain.Member; import hello.hellospring.repository.MemoryMemberRepository; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; class MemberServiceTest { MemberService memberService; MemoryMemberRepository memberRepository; @BeforeEach public void beforeEach() { memberRepository = new MemoryMemberRepository(); memberService = new MemberService(memberRepositorypository); } @AfterEach public void afterEach() { memberRepository.clearStore(); } @Test public void 회원가입() throws Exception { //Given Member member = new Member(); member.setName("hello"); //When Long saveId = memberService.join(member); //Then Member findMember = memberRepository. findById(saveId).get(); assertEquals(member.getName(), findMember.getName()); } @Test public void 중복_회원_예외() throws Exception { //Given Member member1 = new Member(); member1.setName("spring"); Member member2 = new Member(); member2.setName("spring"); //When memberService.join(member1); IllegalStateException e = assertThrows(IllegalStateException.class,() -> memberService.join(member2));//예외가 발생해야 한다. assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다."); } } memberRepository를 입력했는데 밑에 빨간줄이 뜹니다. 혹시 무엇인가 import를 해주지 않은 것인지 판단되어 ctrl+space를 눌러도 클릭되는 것은 없습니다. 그럼 왜 빨간줄이 떠있는 것인지 궁금합니다.
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
th:field와 th:value의 차이
강의를 듣던중 궁금증이 생겨 질문 드립니다.th:field에 의해서 id, name, value의 속성이 자동으로 만들어진다고 강의 교본에 나와있는데요.그럼 한 태그안에 th:field와 th:value가 동시에 있을 경우에는 어떻게 되나요? th:field에 의해 만들어진 value가 th:value에 의해 덮여지는 건가요?그리고, th:action 과 같은 속성은 태그안에 기존 속성과 타임리프 속성 둘다 존재할 경우 기존 속성을 대체하는 것으로 알고 있는데, id속성과 name 속성은 코드를 돌려보니 th:field와 동시에 존재하더라도, 대체되지 않고, 기존의 id속성, name속성이 사용되었습니다. 타임리프 속성마다 대체여부가 다른 건가요?
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
체크박스 value값이 항상 true로 되어 있는 이유
checkbox 강의를 듣던 중 의문점이 생겨 질문드립니다.아래의 코드는 강의에 사용되었던 단일 체크박스 - 판매 여부의 코드입니다.<input type="checkbox" id="open" name="open" th:field="*{open}" class="form-check-input">아래의 코드를 이용하여 실제 렌더링된 페이지의 소스를 보면,체크 하지 않을시,<input type="checkbox" id="open" name="open" class="form-check-input" disabled value="true">체크 할시,<input type="checkbox" id="open" name="open" class="form-check-input" disabled value="true" checked="checked">checked="checked"의 여부만 다르고, value는 둘다 "true"로 되어있었습니다.컨트롤러에서는 item 객체를 model에 담을 때, item.open의 값을 false(체크 안됌), true(체크 됌)으로 명확하게 설정한 후, 이를 model에 담아서 전달했을텐데, 왜 실제 렌더링된 소스에서는 둘다 value="true"로 나오는 건가요?만약에 타임리프가 item.open의 value 값을 토대로 checked="checked"를 넣어줄지를 정하는 거라면, 당연히 value에 저장되는 값이 실제 체크를 했는지에 따라 달라져야하는게 아닌가라는 생각이 들었습니다. + 강의 교본 2. 타임리프 - 스프링 통합과 폼 19페이지의 "타임 리프는 th:field에 지정한 값과 th:value의 값을 비교해서 체크를 자동으로 처리해준다" 의 설명이 너무 추상적인 것 같습니다.같은 강의 교본 4페이지를 보면 th:field가 id, name, value 속성을 모두 자동으로 만들어준다고 되어있는데, 위의 "th:field에 지정한 값"이라는 것은 정확히 무엇을 지칭하는 말인지 모르겠습니다. 좀 더 자세한 설명을 해주셨으면 좋겠습니다.
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
Hidden 필드의 중요성
히든 필드와 관련된 궁금증이 생겨 질문 드립니다.input 태그의 checkbox가 체크가 되어있지 않으면, 값 자체가 전송되지않는다고 해도, 이게 왜 서버 입장에서 문제가 되는지 잘 모르겠습니다.만약 checkbox가 체크 되어있다면, 'name=값' 의 형태로 서버로 데이터가 날라갈 것이고,checkbox가 체크 되어있지않다면, 아무런 값도 날라가지 않을 텐데,아무런 값이 날라오지 않았을 때를 서버 측에서 체크되어있지 않는 것으로 여기면 되는거 아닌가요?강의교본 2. 타임리프 - 스프링 통합과 폼 11쪽에 나와있는 "사용자가 의도적으로 체크되어 있던 값을 체크를 해제해도 저장시 아무 값도 넘어가지 않기 때문에, 서버 구현에 따라서 값이 오지 않은 것으로 판단해서 값을 변경하지 않을 수도 있다." 라는 말이 이해가 되지 않습니다.사용자가 의도적으로 체크되어 있던 값을 체크 해제해서 서버로 보냈다면, 서버측에서는 해당 체크 박스의 name으로 오는 값이 아예 없다는 것을 알 수 있을 것이고, 그럼 아무 값도 오지 않았다는 것을 체크 되어있지 않다로 여기면 될 것 같은데, 왜 굳이 히든 필드를 사용해야하는 또다른 반례가 있는지 궁금합니다.
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
private 메소드에 Optional을 적용하는 건 오버일까요?
/** * 세션 관리 매니저 */ @Component public class SessionManager { public static final String SESSION_COOKIE_NAME = "mySessionId"; private final Map<String, Object> sessionStore = new ConcurrentHashMap<>(); /** * 세션 생성 * * @param value 저장할 값 * @param resp HTTP Servlet Response */ public void createSession( Object value, HttpServletResponse resp ) { // 세션 ID를 생성하고, 값을 세션에 저장 String sessionId = UUID.randomUUID().toString(); sessionStore.put(sessionId, value); // 쿠키 생성 Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId); resp.addCookie(mySessionCookie); } /** * 세션 조회 * * @param req HTTP Servlet Request * @return 조회된 세션에 대한 정보(값) */ public Object getSession( HttpServletRequest req ) { return findCookie(req, SESSION_COOKIE_NAME) .map(value -> sessionStore.get(value.getValue())) .orElse(null); } /** * 세션 만료 * * @param req HTTP Servlet Request */ public void expire( HttpServletRequest req ) { findCookie(req, SESSION_COOKIE_NAME) .ifPresent(cookie -> sessionStore.remove(cookie.getValue())); } /** * 쿠키 찾기 * * @param req HTTP Servlet Request * @param cookieName 찾을 쿠키 이름 * @return 찾은 쿠키 */ private Optional<Cookie> findCookie( HttpServletRequest req, String cookieName ) { if (req.getCookies() == null) { return Optional.empty(); } return Arrays.stream(req.getCookies()) .filter(cookie -> cookie.getName().equals(cookieName)) .findAny(); } } 지난 강의 시간에 Optional에 대해서 말씀하셨길래 SessionManager에 한 번 적용해 보았습니다.getSession 같이 외부로 나가는 것이 아닌, 클래스 내부에서만 사용할 수 있는 findCookie에 Optional을 사용하는게 적절한지 의문이 들어 질문남겨봅니다.Optional을 찾아보니, null을 반환할 수 있는 함수에 대해 사용할 수 있으며, 파라미터보다 반환값으로 사용하는게 맞다고 얘기를 하더군요.그럼 반환값에 사용하면 위와 같이 ifPresent나 orElse를 이용해 실제 객체 값을 들고 와야하기도 해서, 지금처럼 간단한 로직에서는 굳이 Optional이 아닌, Cookie를 반환해서 if문을 이용해 null체크를 하는게 맞다고 생각은 합니다만..findCookie는 클래스내부에서 사용하는게 적절하지 않다면, getSession같이 클래스 외부에서 사용할 수 있는 메서드에 대해 반환값을 Optional로 하는 것은 적절한 사용일까요?
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
Member 객체 질문입니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요 Member 객체에 대하여 질문 있습니다.테스트 코드의 경우 Member member = new Member(); 이런식으로 Member 인스턴스를 생성해서 member.setName("spring"); 이런식으로 쓰이는건 이해가 되는데요Member 클래스 에서나 MemoryMemberRepository 에서나 따로 member라는 참조변수로 Member()라는 인스턴스(Member member = new Member();와 같은것들)를 생성하지 않았는데 바로 아랫줄에서 member.setId(++sequence);가 쓰일수 있는건지 궁금합니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
맵에서 옵션키는 윈도우에서 무슨키인가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 맥에서 옵션키가 윈도우에선 무슨키인지 모르겠네요 ^은 ctrl키인거같고 옵션키는 무슨 한자처럼인데 무슨키인가요?
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
@Data의 @RequiredArgsConstructor에 관하여 질문이 있습니다.
@Data public class ItemUpdateDto { @NotNull private Long id; @NotNull private String itemName; @NotNull @Range(min = 1000, max = 1000000) private Integer price; private Integer quantity; }이 코드를 보면 @RequiredArgsConstructor로 이용해서 생성자를 만드는 것을 확인할 수 있는데, 저 코드의 설명을 보면 final 필드나 @NonNull 애노테이션이 붙은 필드에 한해서 생성자를 만들어준다고 되어있습니다.Generates a constructor with required arguments. Required arguments are final fields and fields with constraints such as @NonNull.그런데, ItemUpdateDto에는 final 객체가 없어서 빈 생성자가 생성될거라고 예상이 됩니다. 실제로 코드에 빈 생성자를 넣으면, RequiredArgsConstructor에 빨간줄과 함께 이미 정의되었다고 표시도 됩니다.그렇다면, Spring에서 폼데이터를 받을때, 생성자가 아닌, Setter를 이용해서 주입을 받는 것일까요? 그렇다면, 저번 수업에서 말씀하신대로 실제로 사용할때는 @Data 가 아닌, Getter, Setter만 제한적으로 적용하는게 맞을까요?