문제 상황을 설명드리겠습니다. page 정보를 받아서 게시글 리스트, 페이지 정보를 View로 전달하는 Controller 코드 입니다. @GetMapping("/posts") public String getPosts(@RequestParam("page") String page, Model model) { // 사용자가 입력한 page문자열과 모든 post의 개수를 매개변수로 받아서 page 정보 생성 // 사용자가 입력한 page값을 검증 후 올바른 Page 정보를 반환한다. // "@#$", "hello" 같은 이상한 page값이 들어오면 모두 1로 변경한다. Page page = Page.validateAndCreate(page, postService.getPostsCount()); // page 정보를 사용하여 해당 page에 속하는 post들을 반환한다. List<Post> posts = postService.getPostList(page); // view로 데이터를 전달한다. model.addAttribute("page", page); model.addAttribute("posts", posts); } 처음에는 위 방식으로 코드를 작성했습니다. 그런데 page정보 뿐 아니라, 다른 sorting정보, searching정보 등 여러 매개변수들이 들어오다 보니, Controller 코드가 복잡해진다고 느꼈습니다. 간단한 예시 코드는 아래와 같습니다. @GetMapping("/posts") public String getPosts(@RequestParam("page") String page, @ModelAttribute("sort") Sort sort, @ModelAttribute("search") Search search, .... 등등 , Model model) { // 여러가지 전처리 로직들 Page page = Page.validateAndCreate(page, postService.getPostsCount()); Sort sort = Sort.validateAndCreate(sort, ... ) Search search = Search.validateAndCreate(search, ...) ....등등 // 위에서 생성한 정보들을 바탕으로 DB에 쿼리를 날려 posts 데이터를 받아온다. List<Post> posts = postService.getPostList(page, sort, search, ...등등); // view에 필요한 데이터를 전달한다. model.addAttribute("page", page); model.addAttribute("posts", posts); model.addAttribute("sort", sort); ... 등등 } 예시 코드는 문제상황 설명을 위해서 깔끔하게 작성했으나, 실제로는 제 부족한 실력 탓에 지저분합니다. 저는 Controller 코드를 지저분하게 만드는 원인으로 여러가지 전처리 로직들 (ex. Page.validateAndCreate(...) 코드들) View에 필요한 데이터들을 전달하는 model.addAttribute(...) 코드들 때문이라고 생각했습니다. 위 문제에 대한 해결방안으로 저는 ArgumentResolver를 사용하는 것을 떠올렸습니다. page에 대해서 @PageInfo라는 애노테이션을 정의하고, 이 애노테이션이 달린 매개변수에 대해서 1.여러가지 전처리 로직들을 수행해주고, 2.View에 자동으로 데이터들을 전달해주는, ArgumentResolver를 만들어주었습니다. Page에 대한 ArgumentResolver 코드는 다음과 같습니다. @RequiredArgsConstructor @Component public class PageRequestArgumentResolver implements HandlerMethodArgumentResolver { // 이 부분이 걱정입니다! ArgumentResolver가 특정 Service클래스에 의존해도 될까요? private final QuestionService questionService; @Override public boolean supportsParameter(MethodParameter parameter) { // @PageInfo를 가지고 있는 경우만 적용. boolean hasPageInfoAnnotation = parameter.hasParameterAnnotation(PageInfo.class); // 타겟변수가 Page 타입인 경우만 적용. boolean isPageClass = parameter.getParameterType().equals(Page.class); return hasPageInfoAnnotation && isPageClass; } @Override public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { // url에서 page문자열 정보를 추출. String pageString = webRequest.getParameter("page"); // page문자열 정보를 검증 및 생성. Page page = Page.validateAndCreate(pageString, questionService.provideAllQuestionsCount()); // mavContainer에 해당 정보를 넣어서 View로 자동전달. if (mavContainer != null) mavContainer.addAttribute("page", page); // 컨트롤러의 매개변수에 page정보를 바인딩. return page; } } 위 처럼 page정보 뿐 아니라, 다른 자주쓰는 매개변수들에도 ArgumentResolver를 정의하고 적용하면, 아래와 같이 Controller코드가 굉장히 깔끔해진다고 느꼈습니다. @GetMapping("/posts") public String getPosts(@PageInfo Page page, @SortInfo Sort sort, @SearchInfo Search search, ... 등등, Model model) { // 여러가지 전처리 로직들은 ArgumentResolver가 해주기 때문에 코드가 사라집니다. // 비즈니스 로직을 수행합니다. List<Post> posts = postService.getPostList(page, sort, search, ...등등); // View에 필요한 데이터도 ArgumentResolver의 mavContainer를 통해서 자동 전달됩니다. // 컨트롤러에서 관심이 있는 posts 정보만 전달합니다. model.addAttribute("posts", posts); } 그런데 이게 정말 좋은 코드인지 판단이 잘 서질 않습니다. 그리고 ArgumentResolver가 다른 Service 클래스에 의존을 해도 되는지가 의문입니다. AI에게 물어보니, 순환참조 문제가 발생할 수 있기 때문에 웬만해서는 하지 말라고하는데...
[질문 내용] ResponseStatusException에 세개의 파라미터가 담기는데, 세번째 파라미터가 무엇인지 정확히 이해가 가지 않습니다. 실제로 /api/response-status-ex2가 호출 되었을 때, IlleagalArgumentException이 발생한다면, 그 대신에 HttpStatus.NOT_FOUND(404)를 내보내주고, "error.bad"를 메시지로 내보내준다는 뜻이 맞나요?
너무 잦은 질문 죄송합니다. 몇번을 돌려봐도 리턴이 헷갈리네요 재귀함수를 통해 int res = 15 를 구한다음 메인함수에 int sum=nSum(n)에 들어 가는거 같은데 res가 갑자기 nSum에 리턴이 되는걸 어떻게 이해해야 될지 모르겠습니다. 첫번째 호출->자기자신 호출까지는 이해했는데 결과값이 리턴하는 순서? 공식?이 잘 정립이 안되네요 ㅠㅠ
토큰을 통해서 제 고유아이디를 알아내야되는데 반환되는것이 하나도 없음 안녕하세요.. 지금 인프런을 통해서 강의를 듣고있는데, 모르는것이 많아서 댓글 질문 남깁니다.. 참고로 저는 Mac, visual code 사용하고있습니다. 현재, 진행되고있는 부분은 텔레그램봇을 통해서 몇개의 채팅 이후 반환값을 받아서 제 고유아이디를 알아내야되는데, 아래와 같이 코딩을 하여서 실행하였으나, 반환되는것이 하나도 없습니다. 문제가 무엇인지 알려주시면 너무 감사드리겠습니다. import telegram import asyncio bot = telegram.Bot (token='제 토큰') async def main(): updates = await bot.getUpdates() for i in updates: print(i) asyncio.run (main())
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] flush()를 할 때 영속성 컨텍스트 스냅샷이 갱신되는 지 확인받고 싶습니다. 다른 질문에서 해당 내용을 찾지 못했고, Baeldung과 같은 사이트, 또는 다른 블로그 글들에서 이와 같은 내용을 확인할 수 있는 곳이 없어 ChatGPT를 통해 확인했지만, 여전히 확신이 서는 곳에서 답변을 받은 것이 아니기에 질문 남겼습니다. 다음과 같은 코드를 실행할 때, EntityTransaction tx = em.getTransaction(); tx.begin(); // id는 1L, name은 AAA인 Member 엔티티 Member memberA = new Member(1L, "AAA"); em.persist(memberA); em.flush(); memberA.setName("NOTA"); tx.commit(); flush를 직접 호출하는 시점은 영속성 컨텍스트에는 memberA에 대한 엔티티는 있지만 스냅샷은 없는 상태로, flush()가 수행되면서 데이터베이스와의 동기화를 위해 INSERT 쿼리문이 날라갑니다. 제가 생각하기에는 이 때(첫번째 flush()), memberA에 대한 스냅샷이 생성되어야 memberA.setName()을 수행하면서 변경감지를 통해 비교할 대상인 스냅샷이 존재할 수 있다고 생각합니다. 그렇기에 commit()을 호출할 때, flush()가 자동으로 호출되면서 비교할 스냅샷을 통해 UPDATE 쿼리문을 생성할 수 있다고 생각했습니다. 이를 통해 제가 확인하고 싶은 것은 다음 2가지인데, 맞는지 확인 부탁드립니다. flush() 호출 시 영속성 컨텍스트에서 스냅샷이 갱신된다. persist() 시에는 스냅샷이 생성되지 않는다. 관련 자료를 확인하고 싶은데 혹시 이를 확인할 수 있는 자료가 있다면 알려주시면 감사하겠습니다. 강의 잘 보고 있습니다!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 인텔리제이로 화살표를 눌러서 스프링 애플리케이션 서버를 실행한다는 것은, 자바 JVM 내부에서 스프링 서버가 뜨는거라고 생각하면 되려나요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 순수 JDBC 강의까지 듣고 질문이 생겨 올립니다~ DB커넥션을 얻어 애플리케이션이 DB 서버에 "소켓"으로 연결된다고 하는데, 이 의미가 "네트워크 상에서 돌아가는 두 개의 프로그램 간 양방향 통신" 을 할 수 있게 소켓이라는 통(?)이 생겨서 연결된다고 보면 되려나요? 그리고, application.properties에 url에 jdbc:h2:tcp://localhost/~/test 이렇게 적으면 소켓 연결이라고 하셨는데 이 url에 대한 더 자세한 이해를 하고 싶은데 이 url이 정확히 어떤 의미일까요? tcp는 OSI 7계층에서 어렴풋이 들어온 용어 같습니다.
django-crispy-form에서 {% include 와 with %} 다음과 같이 에러가 나타나고, {% include "_crispy_form.html" %} with 절을 제외하니 정상 동작합니다. 정확한 이유는 모르겠으나, 문법이 그 사이에 바뀐 것일 수도 있고 해서 일단 공유하는 마음으로 질문드립니다. 감사합니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문 전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] 여기에 질문 내용을 남겨주세요. [12:42]에서 " main 스레드는 TIMED_WATING 상태에서 RUNNABLE 상태로.. ." 설명과 함께 마우스 포인터로 가리키신 pdf 에서는 work 스레드 라고 표기되어 있습니다. 설명에 혼란이 있어서 제가 인터럽트 호출 부분을 다음과 같이 이해한 게 맞는지 확인 부탁드립니다..! 0. work 스레드 동작 main() 스레드 안에서 thread.start(); 호출(work 스레드 호출)한다. 1. main() 스레드 동작 Thread.sleep(4000)을 호출하여 TIMED_WAITING 상태로 들어간다. (4초 대기) 2. thread.interrupt() 호출 4초 뒤 main() 스레드가 깨어나고(RUNNABLE 상태), 바로 아래 코드인 thread.interrupt() 호출한다. -> 이때 work 스레드는 Thread.sleep(3000)으로 인해 TIMED_WAITING 상태였는데, main() 스레드의 인터럽트 신호로 인해 InterruptException이 발생하여 RUNNABLE 상태로 즉시 변경된다. 3. InterruptException 처리 work 스레드는 catch 블록에서 InterruptException 예외 처리 수행한다. 인터럽트 호출했다고 InterruptException 예외가 반드시 나는 것은 아니다. 설명에서 InterruptException 예외 발생한 이유는 main() 스레드에서 4초 대기 후 work() 스레드 인터럽트 호출할 때, work 스레드 상태가 TIMED_WAITING 였기 때문이다. work 스레드는 인터럽트 호출로 인해 TIMED_WAITING -> RUNNABLE 상태로 즉시 변경되고, work 스레드의 인터럽트 상태는 초기화 되어 false를 반환한 것이다. 이렇게 이해하면 될까요..?!
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. @Pattern을 @NotBlank와 쓰면 에러 메세지가 같이 나오고 @NotNull와 같이 쓰면 순서가 @Pattern의 에러먼저 적용 됩니다. 순서를 설정하고 하나만 나오게 하려면 validator를 따로 만들어야만 가능한가요? 아니면 스프링에서 따로 제공하는 기능이 있을까요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. JPA활용2편과 JPA 데이터 강의를 보면 DTO를 직접 반환하는 부분에서 질문드립니다. 강의 수강이전에 repository에서 가져온 Entity를 직접조회하여 가져온 값을 service계층에서 lombok의 builder어노테이션을 이용하여 DTO형태로 직접조립하여 클라이언트에게 반환하는 API를 주로 구성했습니다. 근데 실무에서는 주로 위와 같은 방법이 아니라 repository계층에서 DTO를 직접 불러와서 조립하는 방식을 선호되나요?
[질문 내용] 여기에 질문 내용을 남겨주세요. 7:36에서 obj1, obj2를 출력하는데, obj1, obj2의 객체 정보가 출력이 되었는데, 이유가 메인메서드 처음부분에, obj1과 obj2의 객체가 만들어 지는데, 이때 obj1의 객체 안에는(obj1, Object)클래스 정보가들어있고 obj2객체 안에는(obj2, Object)클래스정보가 들어있는데 System.out.println()메서드 안에 객체를 넣으면 내부에서 자동적으로 객체명.toString()메서드가 실행이 되는데, 자식클래스(obj1, obj2)모두가 toString()을 오버라이딩 하지 않아, Object의 toString()이 호출이 되는데, 호출하는 변수가 각각 obj1, obj2여서 호출하는 변수 타입의 객체 정보가 출력이 된다. 맞나요? 잠시 헷갈렸는데 맞을까여?
A problem occurred configuring root project 'hello-spring'. > Could not resolve all artifacts for configuration 'classpath'. > Could not resolve org.springframework.boot:spring-boot-gradle-plugin:3.4.1. Required by: root project : > org.springframework.boot:org.springframework.boot.gradle.plugin:3.4.1 > Dependency requires at least JVM runtime version 17. This build uses a Java 8 JVM. * Try: > Run this build using a Java 17 or newer JVM. > Run with --stacktrace option to get the stack trace. > Run with --info or --debug option to get more log output. > Run with --scan to get full insights. > Get more help at https://help.gradle.org . Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0. You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins. For more on this, please refer to https://docs.gradle.org/8.11.1/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation. 인텔리제이에서 open 폴더로 hellospring 열었는데 해당 오류가 뜨네요 이거 뭔가요?
[질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. "초과 스레드가 작업을 처리할 때 마다 시간은 계속 초기화된다" 7:36초에 말씀을 해주셨는데, 한가지 궁금한 점이 생겨 질문 드립니다! 큐가 가득 차서 초과 스레드가 이미 만들어 졌다고 가정한 상황입니다. 이후에 작업이 없어서 큐가 비어있다고 가정을 하겠습니다. 즉, 상황은 큐가 비어있고, 스레드 풀에 기본 스레드 2개, 초과 스레드 2개가 있습니다. 이 때, Executors 에 새로운 작업이 들어오면 이 작업은 무조건 기본 스레드가 초과 스레드 보다 먼저 작업을 수행하게 되나요? 만약, 기본 스레드가 먼저 작업을 무조건 수행하게 된다면 이는 BlockingQueue의 내부 구현인 ReentrantLock 과 Condition 으로 인해 WAITING인 기본 스레드 부터 깨우게 되는 것인가요?
강의 잘 듣고있습니다. 현재 service단의 update메서드에는 merge로 병합처리를 하고있지만 accountRepository에서 findById와 같이 수정할 account객체를 찾아내서 영속화를 시켜준뒤에 수정을 하면 dirty checking으로 인한 수정법이 더 안전한 방법일까라고 생각이되서 질문드립니다.