안녕하세요 커넥션 풀 강의 부분을 듣고 질문사항이 생겼습니다. 일반적으로 TCP커넥션이라 함은, 소켓(src ip, src port, dst ip, dst port 조합으로 구분)을 통하게 되는데 결국 클라이언트와 서버 1대1 관계에서 TCP 커넥션이 하나 생기지 않습니까? (src ip, src port, dst ip, dst port가 모두 같을 경우에 해당) 하지만 커넥션 풀 개념에서는 커넥션 풀에 여러개의 커넥션이 존재하게 됩니다. 여기서 다음과 같이 의문점이 생겼습니다. DB커넥션과 TCP커넥션은 다른 개념으로 생각해야 할 게 맞는건지(TCP커넥션 하나에 여러개의 DB커넥션이 포함되는 느낌?) 위 질문이 맞다면 DBMS 단에서 커넥션 풀의 여러 커넥션들을 구분하는 기준은 소켓이 아니라 세션ID같은 정보일 것으로 확인되는데 맞을까요? 트랜잭션 개념에 의하면 같은 커넥션(세션)으로 일련의 쿼리들을 전송해야 하는데, 커넥션과 세션은 1대1로 매핑되는 개념으로 알고 있습니다. 세션은 DBMS단에서 세션ID로 식별을 한다고 생각하면 커넥션 풀의 커넥션은 어떤 세션과 매핑이 될지에 대한 정보를 어떻게 표현되어지고 있는지 궁금합니다. 커넥션 풀 구현체(히카리 등)에서 정의한 커넥션 객체에 세션ID라는 필드가 있는 건지... 추가질문 JDBC 기반으로 메시지를 보낼 때 프로토콜이 JDBC인 것으로 알고있는데 wireshark같은 네트워크 패킷 프로그램으로 확인해본 결과 JDBC나 mysql이라는 프로토콜은 필터링되지 않고 TCP로 필터링되어 확인됩니다. 결국 JDBC나 mysql 같은 프로토콜은 TCP의 payload부분을 커스터마이징하여 구현된 프로토콜인것으로 예측이 되는데(사실 payload 부분이 암호회되어 확인할 수 없음) 맞는 사실일까요? 위 질문이 맞다면 DB접근에 대한 프로토콜은 애플리케이션 레벨 프로토콜을 사용하지 않고 TCP로만 데이터를 보내는 것으로 해석이 되는데 맞을까요? (JDBC나 mysql 같은 프로토콜이 L7 프로토콜인 것으로 생각했었습니다...) 감사합니다!
안녕하세요 강사님. 이번 수업 너무 잘 들은 학생입니다. 다름이 아니라 JWT Token 을 필터단에서 Security에게 인가처리를 맡기기 위해 Security Context 에 Authentication을 저장한다고 하셨습니다. 이는 스프링 내 세션에 인증 객체를 저장해 두는 것으로 이해를 하였습니다. 1.수업중에도 설명해주셨듯이, 토큰을 사용하는 것은 세션에 인증 객체를 저장하지 않도록 해서 서버적으로 부하가 걸리는 상황을 방지하는 점이 큰 장점으로 이해하였으나, 결국 시큐리티에 인가를 맡기려면 세션에 저장하는 방법 밖에 없는지 궁금합니다. 필터들 사이에서 Authentication 정보를 주고 받아야 하니 스프링 시큐리티를 사용하려면 세션 저장 말고는 방법이 없는걸까요? 2.계속 생각하다보니 또 궁금해진 사항인데, [SecurityContextHolder 에 세션 정보를 저장해두는 것이 SpringSecurity 가 일반적으로 채택하고 있는 formLogin 방식에서 사용하는 세션 저장 방식]인 것으로 이해를 했습니다. 이 때, 왜 이 부분이 계속 세션을 저장해서 서버적으로 부하가 걸리게 하는 건지 잘 이해를 못한 것 같습니다. Authentication 과정을 살펴보면 그 때 인증을 하기 위해 형성한 Authentication 객체는 그 요청을 처리하기 위해 Thread Local 에 있는 SecurityContextHodler 에 저장을 해두고 인가를 처리하게 됩니다. 하지만 그 과정을 끝내고 나면 Holder를 비워주고, THread도 종료되기 때문에 서버 자체에는 딱히 저장되는 것은 없지 않나요? 보안적인 측면 외의 SESSION 방식의 단점을 잘 이해하지 못한 것 같습니다. 간략하게 라도 도움주시면 감사할 것 같습니다. 2번을 먼저 이해해보는게 1번을 이해하는데 도움이 될 것 같긴 하네요. 강의도 너무 잘들었습니다. 미리 감사드립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 같은 질문글의 import hello.core.member.Member; 부분은 추가해도 안먹힙니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예 [질문 내용] 여기에 질문 내용을 남겨주세요. 스프링부트 3.0, JDK17 사용중입니다. AOP 코드를 넣지않고, 스프링 빈 클래스가 잘 찍히는지 확인해보다가. 강의 설명과 다르게, AOP 설정을 넣지 않았는데도 프록시객체가 찍힙니다.
안녕하세요 클라이언트 요청시 핸들러와 어댑터가 호출되는 흐름이 제가 이해한게 맞는지 질문드리고 싶어요 springmvc(강의)에서는 RequestMappingHandlerMapping 클래스를 이용해서 어댑터를 찾았는데요 @Controller public class MyController { @RequestMapping("/hello") public ModelAndView hello() { return new ModelAndView("hello"); } 위 코드대로 질문을 드려보면요 로컬에서 localhost:8080/hello 요청하면 dispatcher servlet이 우선 RequestMappingHandlerMapping 빈을 이용해서 MyController을 얻게 되고, 그리고 RequestMappingHandlerAdapter 빈을 이용해서 어댑터를 얻어서 어댑터가 MyController의 hello 메소드를 실행한다. 이게 맞나요? 근데 어댑터는 구현한적이 없는데 어떻게 실행한다는것인지 ..ㅎㅎ
우선 화면에서는 html ,자바스크립트 ,제이쿼리 ,타임리프만을 사용해보려고 하고있습니다 (화면에서 ajax 사용했습니다) 아래 2가지 상황에서 화면으로 어떻게 값을 가져와서 사용해야하는지 잘모르겠습니다... ㅠㅠㅠ 컨트롤러에서 @ResponseBody가 붙은 메소드에서 데이터를 Map으로 리턴하고 있습니다 그랬을때 화면에서는 어떻게 받아서 사용해야할지 모르겠습니다.. 컨트롤러에서 @ResponseBody가 붙지 않는 메소드에서는 모델에 담은 데이터가 Map이고 그 Map안에서 특정한 하나의 키에 Value가 배열이고 그 안에 또 Map이 있는 경우에는 어떻게 가져와야할까요?? 배열이 있는부분은 반복문을 써서 전부 화면에서 보여주고 싶습니다
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) build.gradle까지 했는데 CoreApplication 없어서 강의보고 CoreApplication 생성해보니 에러 뜨더라구요 https://drive.google.com/file/d/1VEjp2fk8EanR4O3tORA_nKa4wWMlasFv/view?usp=sharing
제가 이해한 바로는 Java코드 내에 직접 html을 써서 view를 제공해줬는데 이게 아무래도 하나하나 치는게 불편하다보니 JSP가 등장했고 이를 통해 java에서 html을 쓰는게 아니라 html코드 내에 중요한 부분에만(for를 이용한 동적 활용이나 repository 데이터 조회 등 ?) java코드를 씀으로써 좀 더 코드를 간결하게 만들수 있다는 것 같은데 맞나요 ?? jsp와 타임리프는 둘다 뷰를 그리는 도구이다... ???
안녕하세요 강의 완강 후 따로 프로젝트를 만들어 보던 중 궁금한 게 생겨서 질문 드립니다. PostMapping으로 등록할 때 CreateRequest라는 별도의 클래스를 만들어 주어서 파라미터로 받았는데 이 CreateRequest안에 List를 받아야 할 경우가 있다면 어떻게 해줘야 하는지 잘 모르겠습니다. Product 클래스 입니다. Module 클래스 입니다. 하나의 Product에 여러 개의 Module이 들어갈 수 있기 때문에 ProductModule 클래스를 만들어줬습니다. 이러한 경우에서 Product를 등록할 때 아래와 같이 넘겨주고 싶으면 CreateProductRequest 에서 List를 어떤식으로 받아줘야 하나요? 아래와 같이 해봤는데 잘 안되는 것 같아서요...
관련 질문에 대한 답변을 읽어봤는데도 이해가 가지 않아서 질문드립니다. 커맨드와 쿼리를 분리해야한다는 CQS를 설명하신 말이었어요. 내부변경이 일어나는것은 커맨드, 명령어라고 부른다 커맨드는 결과값을 그대로 반환하면안된다 내부변경이 일어나지않는 것은 쿼리라고 부른다. 쿼리는 결과값을 반환한다 -> 1. 커맨드에서 결과값을 반환하면 안되는 이유가 뭘까요? update 메서드 안에서도 결국은 update하는것(커맨드)과 findOne(쿼리)하는 코드가 모두 들어가있는거잖아요? 근데 이게 왜 cqs를 지킨 사례인거죠? @Transactinal public vodi update(Long id, String name){ memberService.update(id,name); Member member = memberService.findOne(id); rreturn ~~~; }
강의도중에 설명해주시긴 했는데 그래도 이해가 덜 가서 질문드립니다 membersaveDto만있으면 memberupdatedto를 만들지 않아도돼요 둘다 만들게 되면 코드의 중복이 발생하는것아닌가요? save와 update는 아예다른것이기때문에 중복이 발생해도 상관이 없는걸까요? 아예다른것이라기엔 update에도 있고 save에도 있는 필드에 변화가 생겼을때 둘다 수정을 해주어야해요 그럼 수정해야할 포인트가 늘어나는건데도 updateDto를 생성해주는게 맞는걸까요?
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 우선 객체의 생성과 초기화를 분리하자는 글엔 완전 공감합니다. 근데 동시에 궁금한 점도 몇개 생겼습니다 외부에서 접근가능한 setter를 계속 열어주어야 하는데 괜찮나요? 생성하고자 하는 객체의 인스턴스 변수에 final 못 붙이지 않나요? @Component일 경우 final 못쓰니 @RequiredArgsConstructor 적용 못하는 문제도 있을 거 같아요
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? 예 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예 3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예 [질문 내용] 강의에서는 개발과 테스트 코드가 모두 동일한 h2 DB 기반으로 구현이 되는데 실무에서는 테스트 코드에 대한 DB 연결을 어떤식으로 하게되는지 궁금합니다. 예를 들어 실제 개발은 A 서버의 mysql 을 사용하고 테스트는 로컬의 h2 로 별도로 연결을 하는지, 아니면 동일한 서버(환경)에서 테스트용 테이블들만 별도로 만들어서 하는지, 또는 모든 환경을 동일하게 하고 테스트 코드만 인메모리에서 실행되게 하는지, 실제 개발 시에는 테스트 코드에 대한 서버, DB 구성 방법이 궁금합니다.
[질문 내용] 여기에 질문 내용을 남겨주세요. public Member login(String loginId, String password) { return memberRepository.findByLoginId(loginId) .filter(member -> member.getPassword().equals(password)) .orElse(null); } 여기서 filter앞에 stream를 안 써준 이유가 뭔가요?? java8메소드를 사용하기 위해서는 stream을 앞에 선언해줘야 한다고 알고 있었는데요
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 안녕하세요 타임리프 - 기본기능 강의중 식 기본 객체 예제 실습 중 표현식 오류가 나서 질문 드립니다. 오류내용은 다음과 같습니다. org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#request" (template: "basic/basic-objects" - line 11, col 7) at org.thymeleaf.spring6.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:292) ~[thymeleaf-spring6-3.1.0.RELEASE.jar:3.1.0.RELEASE] ...중략 Caused by: java.lang.IllegalArgumentException: The 'request','session','servletContext' and 'response' expression utility objects are no longer available by default for template expressions and their use is not recommended. In cases where they are really needed, they should be manually added as context variables. at org.thymeleaf.standard.expression.StandardExpressionObjectFactory.buildObject(StandardExpressionObjectFactory.java:207) ~[thymeleaf-3.1.0.RELEASE.jar:3.1.0.RELEASE] at org.thymeleaf.spring6.expression.SpringStandardExpressionObjectFactory.buildObject(SpringStandardExpressionObjectFactory.java:110) ~[thymeleaf-spring6-3.1.0.RELEASE.jar:3.1.0.RELEASE] at org.thymeleaf.DialectSetConfiguration$AggregateExpressionObjectFactory.buildObject(DialectSetConfiguration.java:777) ~[thymeleaf-3.1.0.RELEASE.jar:3.1.0.RELEASE] at org.thymeleaf.expression.ExpressionObjects.getObject(ExpressionObjects.java:108) ~[thymeleaf-3.1.0.RELEASE.jar:3.1.0.RELEASE] at org.thymeleaf.spring6.expression.ThymeleafEvaluationContext.lookupVariable(ThymeleafEvaluationContext.java:134) ~[thymeleaf-spring6-3.1.0.RELEASE.jar:3.1.0.RELEASE] at org.springframework.expression.spel.ExpressionState.lookupVariable(ExpressionState.java:146) ~[spring-expression-6.0.2.jar:6.0.2] at org.springframework.expression.spel.ast.VariableReference.getValueInternal(VariableReference.java:76) ~[spring-expression-6.0.2.jar:6.0.2] at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:112) ~[spring-expression-6.0.2.jar:6.0.2] at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:338) ~[spring-expression-6.0.2.jar:6.0.2] at org.thymeleaf.spring6.expression.SPELVariableExpressionEvaluator.evaluate(SPELVariableExpressionEvaluator.java:265) ~[thymeleaf-spring6-3.1.0.RELEASE.jar:3.1.0.RELEASE] ... 58 common frames omitted 2022-12-08T22:59:02.658+09:00 ERROR 8488 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: org.thymeleaf.exceptions.TemplateProcessingException: Exception evaluating SpringEL expression: "#request" (template: "basic/basic-objects" - line 11, col 7)] with root cause java.lang.IllegalArgumentException: The 'request','session','servletContext' and 'response' expression utility objects are no longer available by default for template expressions and their use is not recommended. In cases where they are really needed, they should be manually added as context variables. at org.thymeleaf.standard.expression.StandardExpressionObjectFactory.buildObject(StandardExpressionObjectFactory.java:207) ~[thymeleaf-3.1.0.RELEASE.jar:3.1.0.RELEASE] at org.thymeleaf.spring6.expression.SpringStandardExpressionObjectFactory.buildObject(SpringStandardExpressionObjectFactory.java:110) ~[thymeleaf-spring6-3.1.0.RELEASE.jar:3.1.0.RELEASE] at org.thymeleaf.DialectSetConfiguration$AggregateExpressionObjectFactory.buildObject(DialectSetConfiguration.java:777) ~[thymeleaf-3.1.0.RELEASE.jar:3.1.0.RELEASE] ...중략 해당 내용을 해석해보니 더이상 #request와 같은 표현식은 제공이 안되고 수동적으로 변수를 주입해서 사용하라는 것 같습니다. (modelAttribute로 request를 넘겨줘보니 출력이 잘되는걸 확인했습니다.) 혹시라도 제가 실수를 해서 표현식이 안되는 것인지 아니면 진짜로 더이상 이런 표현식을 제공하지 않는 것인지 궁금합니다. 항상 좋은 강의 감사합니다
안녕하세요. 로드맵 수강하고 토이 프로젝트 진행 중인데 궁금한 점이 계속 나오네요.. 일반적으로 사용하는 표현 - 비즈니스 - 도메인 계층 구조에서 비즈니스 정책을 검증하는 위치와 관련해서 질문 드립니다. 예를 들어 사용자용 게시글 삭제 API는 현재 요청 사용자가 게시글의 작성자가 맞는지 검사합니다. 이 검증 작업을 서비스 계층에서 처리했습니다. public class PostService { private final PostRepository postRepository; // 게시글 삭제 기능 public void deletePost(Long postId, Long currentMemberId) { // 엔티티 조회 후 게시글 작성자가 현재 요청 사용자( currentMemberId )와 일치하는지 검사 Post post = postRepository.findById(postId); if (!post.getWriter().getId().equals(currentMemberId)) { // 작성자가 아니면 예외 발생 } post.delete(); } } 이 메서드를 사용자 API 컨트롤러에서는 잘 사용했는데, 관리자 API는 게시글 작성자 검증이 필요 없다 는게 문제였습니다. 사용자 및 관리자용 API 컨트롤러에서 호출하는 것은 결국 '게시글 삭제'라는 동일한 기능이므로 하나의 서비스 클래스에서 제공하는 게 맞다 판단하여 deletePost() 메서드에서 수행하던 유효성 검증 로직을 사용자 API 컨트롤러로 이관했습니다. public class PostController { private final PostService postService; // 실제 코드는 아니며 설명용 코드입니다. // 예를 들어 currentMemberId의 경우 실제론 @AuthenticationPrincipal 등을 통해 얻습니다. @DeleteMapping("/{postId}") public void delete(Long currentMemberId, @PathVariable Long postId) { Post post = postService.findPost(postId); if (!post.getWriter().getId().equals(currentMemberId)) { // 작성자가 아니면 예외 발생 } postService.deletePost(postId); } } 이렇게 구성하니 PostService 를 사용자 API 컨트롤러에서도, 관리자 API 컨트롤러에서도 사용 가능했지만.. 표현 계층에서 비즈니스 정책을 검증하니 구조가 이상한 것 같아서 질문 드립니다. '게시글을 삭제하려는 사용자가 게시글의 작성자인가?' 를 확인하는 작업은 비즈니스 정책에 의한 작업이라 생각합니다. 그러므로 서비스 계층에서 검사하는 게 맞다 생각되는데, 관리자 API에서 사용하기 불편하더라구요. 이런 경우 구조를 어떻게 가져가시나요? PostService 는 비즈니스 로직만 처리하고, PostUserService 같은 래퍼 서비스를 만들어 검증 부분을 처리할까 했는데, 썩.. 맘에 들진 않았습니다. 예시처럼 정책 검증을 컨트롤러에서 수행한다 가정하면, 제 코드의 경우 PostService.findPost() 메서드에 @Transactional(readOnly=true) 를 적용한 상태라 deletePost() 메서드에서 SELECT 쿼리를 또 실행합니다. @Transactional(readOnly=true) 은 정말 필요한 곳에만 선택적으로 적용하시나요? 아니면 읽기 전용 메서드는 별도로 구분하시나요? '서비스는 최대한 비즈니스 로직만 수행하고, 정책 유효성 검증은 다른 위치에서 진행하는 것이 좋다'라는 분들도 있던데, 보통 어떤 식으로 처리하시나요?
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] HttpEntity는 HTTP 메시지를 편하게 조회할 수 있게 해준다고 알고 있습니다. httpEntity.getBody() 바디 내용을 조회한 다음 HttpMessageConverter가 HelloData의 객체로 변경해줬다고 생각하는게 제대로 이해한게 맞나여?