묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
해결됨스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
HelloSpringApplication 실행시 오류 (빌드 실패)
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]Java 17 버전, spring Boot 3.xx인것 확인 후 강의 영상 그래도 Run HelloSpringApplication 를 하였는데 실행 시간이 너무 오버되어 임의로 중지하였더니 해당 문구가 뜹니다. 해결 방안을 알 수 있을까요 ? 실행하기 전,cannot access java.lang.object해당 오류가 떴는 데 무시하고 실행하였더니 이렇게 된것 같아 이 문구가 원인인 것 같긴 합니다..
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
paramet vs response body
안녕하세요. 수업 너무 잘 듣고있습니다.다름이 아니고 특정 url에서 값을 요청하거나 응답한다고 할 떄, 값을 언제 http paramter로 받아야하는지와 http body로 받아야하는지에 대한 차이를 알고싶습니다. 파라미터는 값이 객체가 아니고 단순히 변수일 때 혹은 받아야하는 개수가 적을 때 라고 생각이 되는데, 혹시 이 이유도 맞는지, 그리고 또 다른 이유들이 어떤 것이 있는지가 궁금합니다. 감사합니다 ㅎㅎ
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
list와 arraylist
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]public List<Member> findAll() { return new ArrayList<Member>(store.values());}에서 method의 return type을 ArrayList의 상위 인터페이스인 List로 지정한 이유가 궁금합니다. MemeberRepository interface가 재사용될 때, list를 implement하는 다른 class들도 반환 type으로 사용할 수 있게 하기 위한 이유인가요? 특별한 이유가 있는 것인지 궁금합니다.
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
핸들러 매핑과 핸들러 어댑터들도 모두 스프링 빈으로 등록되나요?
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]스프링 부트를 사용하면 자동으로 핸들러 매핑과 핸들러 어댑터, 뷰 리졸버 등 여러 가지를 등록해 준다고 하셨는데 저는 처음에 '등록'이라는 의미를 DispatcherServlet에 있는private List<HandlerMapping> handlerMappings;private List<HandlerAdapter> handlerAdapters;private List<ViewResolver> viewResolvers; 이 List에 저장한다는 의미로만 생각했었습니다.그런데 강의가 진행되면서 설명해 주신 내용 중, 다음 코드처럼 스프링 부트에서 InternalResourceViewResolver를 스프링 빈으로 등록해 주듯이 @Bean ViewResolver internalResourceViewResolver() { return new InternalResourceViewResolver("/WEB-INF/views/", ".jsp"); } } 핸들러 매핑과 핸들러 어댑터들도 스프링 빈으로도 등록되는 건가요? 즉,핸들러 매핑, 핸들러 어댑터, 뷰 리졸버들은 스프링 빈으로 등록되고뷰는 기본적으로 스프링 빈으로 등록되지 않지만(https://www.inflearn.com/course/lecture?courseSlug=%EC%8A%A4%ED%94%84%EB%A7%81-mvc-1&unitId=71204&tab=community&q=782881&category=questionDetail) 원한다면 따로 스프링 빈으로 등록할 수도 있다.(BeanNameViewResolver를 사용할 때) 이렇게 생각해도 되는지 궁금합니다.
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
th:action 질문드립니다
상품 등록 버튼을 눌렀을 때, items/add로 이동하는 걸th:action 대신th:onclick="|location.href='@{/basic/addForm.html}'|"로 적어도 되나요? 단순히 url 이동이 아니라, 상품 등록 버튼을 눌렀을 때, 상품을 실제로 저장하는 액션이 있기 때문에 th:action을 사용해야 하는 것인가요? 상품 등록 버튼을 눌렀을 때의 결과를 작업하는 것인데,<button class="w-100 btn btn-primary btn-lg" type="submit">상품 등록 </button>여기가 아닌, <h4 class="mb-3">상품 입력</h4> <form action="item.html" th:action method="post">여기서 처리하는지 궁금합니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
회원 웹 기능 - 홈 화면 추가 강의 초반에
회원 가입 란을 누르면 회원이름 작성란이 떠야 하는데 다른게 뜨네요.. 나머지는 동일하게 작성한 듯 한데 뭐가 문제인지 모르겠네요ㅜ
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
gradle 오류입니다
지원 중단된 기능이 있는거같은데 이거 어떻게 해야할까요...?gradlew clean build 해도 안되고 build 폴더만 지우고 해도 안됩니다... 버전을 바꿔야할까요(두 번째 사진은 --warning-mode all 를 사용해 deprecated된 기능을 확인한 것입니다)=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
open build.gradle을 해야하는 이유
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요 프로젝트 생성하다가 궁금증이 생겼습니다github에 studySpring 이라는 레포를 생성해서 그 안에 hello-spring을 넣으려고 인텔리제이에서 studySpring을 clone하고 그 안에 hello-spring을 넣었습니다. 그리고 jdk 21ver을 설치해주었는데 이상태에선 HelloSpringApplication.java가 실행이 되지 않았습니다.여기서 open -> hello-spring ->build.gradle을 열어야 HelloSpringApplication.java가 실행되던데 이유가 궁금합니다 !!+) studySpring 폴더안에서 hello-spring -> HelloSpringApplication.java 를 실행하는 방법은 없나요? 현재는 hello-spring의 build.gradle을 열어야만 실행됩니다
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
maven 빌드에러가 계속 납니다
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]해당 maven 빌드에러가 계속 나서 ./gradlew.clean도 해보고 의존도 업데이트도 터미널에서 해봤는데, 계속 동일 오류가 납니다
-
미해결스프링 DB 1편 - 데이터 접근 핵심 원리
DELETE문 테스트 하는 부분 질문드립니다.
항상 강의 잘 듣고 있습니다 🙂다름이 아니라 이번 강의에서는 이전에 배웠던 assertThrows를 사용하시지 않고 assertThatThrownBy를 사용하셨는데 이 둘은 결국 하는 일이 같은 것이 아닌가 해서 질문드립니다. 강사님께서 강의 중 작성하신 코드와 제가 작성한 기존의 assertThrows를 이용한 코드가 정확히 같은 것이 맞는가해서 질문드립니다.// 강사님 (assertThatThrownBy) assertThatThrownBy(() -> repository.findById(member.getMemberId())).isInstanceOf(NoSuchElementException.class); // AssertThrows (내 버전) assertThrows(NoSuchElementException.class, () -> repository.findById(member.getMemberId()));
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
스프링 부트 3.x버전쓰고 강의대로 했는데 NullPointException 나시는분들을 위해
위에 처럼 NullPointerException 나시고 PostMan에 어떠한 것도 호출되지 않거나 기존에 만들었던 Error 500 html 페이지가 뜨시는 분들 강의자료에 있는 2.x 버전대의 javax.~을 복사붙여넣기 하시면 안됩니다스프링부트 3버전대부터 javax가 아닌 jakatra로 바뀌었기 때문에 RequestDispatcher 참고하셔도 좋고 아래에 있는 코드를 복사해서 쓰세요 public static final String ERROR_EXCEPTION = "jakarta.servlet.error.exception"; public static final String ERROR_EXCEPTION_TYPE = "jakarta.servlet.error.exception_type"; public static final String ERROR_MESSAGE = "jakarta.servlet.error.message"; public static final String ERROR_REQUEST_URI = "jakarta.servlet.error.request_uri"; public static final String ERROR_SERVLET_NAME = "jakarta.servlet.error.servlet_name"; public static final String ERROR_STATUS_CODE = "jakarta.servlet.error.status_code";
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
안녕하세요, 컨트롤러의 구현 방법에 대한 질문입니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요, 강의를 들으면서 영한님께서 작성해주신 코드 뿐만 아니라, 그동안 공부했던 방법을 활용하여 다르게 표현할 방법이 없을지를 항상 고민하며 강의를 수강하고 있습니다.(강의를 열심히 수강중인 것으로 생각해주시면 감사하겠습니다 ㅎㅎ..)물론 설명을 너무 잘해주셔서, 강의의 내용과 흐름은 이해할 수 있었는데요, 이 과정에서 몇몇 궁금한 것이 생겨 질문드리게 되었습니다.메서드 파라미터 사용 이 코드는, v4에서의 프론트 컨트롤러 코드인데요, 저는 "메서드 파라미터는 변경하지 않는 것이 좋다"라고 알고 있는데, 그래서 controller.process(paramMap,model) 에서 model이 변경(정확히는 참조는 바뀌지 않지만 컬렉션 내부 내용의 변화)되는 부분이 조금 어색하게 느껴지는 것 같습니다. 그래서 드리는 질문은, 저는 v3에서의 프론트 컨트롤러 코드 흐름이 더 쉽게 와닿는 느낌인데요, 영한님께서는 각각의 컨트롤러에서 ModelView를 생성하지 않는 장점이 더 크다고 판단하신 건지 궁금합니다.2. 인터페이스의 디폴트 메서드 사용 이 코드는, v5의 Adaptor의 구현 클래스에 공통적으로 정의되는 createParamMap() 메서드인데요! 인터페이스의 디폴트 메서드를 활용하면 V3, V4에서의 코드 중복을 해결할 수 있을 것 같다는 생각이 들었습니다.그래서 궁금한 점은, 나중에 createParamMap()을 사용하지 않는 어댑터를 추가할 수 있으니 중복을 감안하고 V3, V4에 각각 정의하는 것이 좋은 방법인지, 혹은 V3, V4에는 코드가 중복되니 코드 중복 제거 차원에서 디폴트 메서드로 정의하는 것이 좋은지에 대한 의견이 궁금합니다. 읽어주셔서 감사합니다. 즐거운 하루 보내세요!
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
서블릿 관련하여 제가 이해한 내용 중에 틀린 부분이 있는지 궁금합니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용] 서블릿을 따로 공부한 적이 없어서 구글링을 조금 해 봤지만 제대로 이해한 건지 확신이 안 갑니다. 제가 이해한 내용 중 오류가 있는지 궁금합니다. 아래 코드는 강의에서 사용했던 코드입니다.@WebServlet(name = "requestBodyJsonServlet", urlPatterns = "/request-body-json") public class RequestBodyJsonServlet extends HttpServlet { . . . } RequestBodyJsonServlet이 서블릿인 이유는 HttpServlet를 상속했기 때문이며, @WebServlet 때문에 서블릿인 것은 아니다. 하지만 서블릿으로서 동작하려면 @WebServlet이 필요하다. @WebServlet은 이 서블릿에 URL을 매핑하기 위함이며, @ServletComponentScan이 서블릿을 서블릿 컨테이너에 등록할 때도 @WebServlet이 붙은 클래스들을 서블릿 컨테이너에 등록한다. RequestBodyJsonServlet이 HttpServlet를 상속하여 서블릿의 조건을 만족하고, @WebServlet을 클래스 레벨에 붙임으로써, @ServletComponentScan에 의해 서블릿 컨테이너에 등록될 수 있게 되었지만 스프링 빈으로 등록된 것은 아니다. DispatcherServlet은 스프링 빈으로 등록된다. 저는 이렇게 이해했는데 틀린 내용이 있는지 궁금합니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
Assertions static import
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오) 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) 예[질문 내용]여기에 질문 내용을 남겨주세요.static import를 하려하는데 assertj가 아닌 junit경로만 나와요 어떻게 해결해야하나요?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
순수 JDBC 코드 복붙 후 에러가 발생했습니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 순수JDBC 리포지토리 구현 코드를 그대로 복붙했고, 스프링 설정 변경 코드 또한 동일하게 수정을 하였습니다.선생님께서는 DB 연결이 잘되어 넘어가던데 저는java: exporting a package from system module java.net.http is not allowed with --release라는 에러가 뜨네요 ㅠㅠ 구글링해서 자바 버전을 17로 해보기도 하고 11버전으로 바꿔보기도 했는데도 에러가 여전히 나옵니다 ㅠㅠ --release 옵션 생략하기 위해 java {sourceCompatibility = '17'modularity.inferModulePath = false}를 설정했는데도 고쳐지지않네요 ㅠㅠ또 어디를 수정해봐야할까요? package hello.hellospring.repository; import hello.hellospring.domain.Member; import org.springframework.jdbc.datasource.DataSourceUtils; import javax.sql.DataSource; import java.sql.*; import java.util.ArrayList; import java.util.List; import java.util.Optional; public class JdbcMemberRepository implements MemberRepository { private final DataSource dataSource; public JdbcMemberRepository(DataSource dataSource) { this.dataSource = dataSource; } @Override public Member save(Member member) { String sql = "insert into member(name) values(?)"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); pstmt = conn.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS); pstmt.setString(1, member.getName()); pstmt.executeUpdate(); rs = pstmt.getGeneratedKeys(); if (rs.next()) { member.setId(rs.getLong(1)); } else { throw new SQLException("id 조회 실패"); } return member; } catch (Exception e) { throw new IllegalStateException(e); } finally { close(conn, pstmt, rs); } } @Override public Optional<Member> findById(Long id) { String sql = "select * from member where id = ?"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); pstmt = conn.prepareStatement(sql); pstmt.setLong(1, id); rs = pstmt.executeQuery(); if(rs.next()) { Member member = new Member(); member.setId(rs.getLong("id")); member.setName(rs.getString("name")); return Optional.of(member); } else { return Optional.empty(); } } catch (Exception e) { throw new IllegalStateException(e); } finally { close(conn, pstmt, rs); } } @Override public List<Member> findAll() { String sql = "select * from member"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); pstmt = conn.prepareStatement(sql); rs = pstmt.executeQuery(); List<Member> members = new ArrayList<>(); while(rs.next()) { Member member = new Member(); member.setId(rs.getLong("id")); member.setName(rs.getString("name")); members.add(member); } return members; } catch (Exception e) { throw new IllegalStateException(e); } finally { close(conn, pstmt, rs); } } @Override public Optional<Member> findByName(String name) { String sql = "select * from member where name = ?"; Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); pstmt = conn.prepareStatement(sql); pstmt.setString(1, name); rs = pstmt.executeQuery(); if(rs.next()) { Member member = new Member(); member.setId(rs.getLong("id")); member.setName(rs.getString("name")); return Optional.of(member); } return Optional.empty(); } catch (Exception e) { throw new IllegalStateException(e); } finally { close(conn, pstmt, rs); } } private Connection getConnection() { return DataSourceUtils.getConnection(dataSource); } private void close(Connection conn, PreparedStatement pstmt, ResultSet rs) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (pstmt != null) { pstmt.close(); } } catch (SQLException e) { e.printStackTrace(); } try { if (conn != null) { close(conn); } } catch (SQLException e) { e.printStackTrace(); } } private void close(Connection conn) throws SQLException { DataSourceUtils.releaseConnection(conn, dataSource); } }package hello.hellospring; import hello.hellospring.repository.JdbcMemberRepository; import hello.hellospring.repository.MemberRepository; import hello.hellospring.service.MemberService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.sql.DataSource; @Configuration public class SpringConfig { private final DataSource dataSource; @Autowired public SpringConfig(DataSource dataSource) { this.dataSource = dataSource; } @Bean public MemberService memberService(){ return new MemberService(memberRepository()); } @Bean public MemberRepository memberRepository(){ return new JdbcMemberRepository(dataSource); } }plugins { id 'java' id 'org.springframework.boot' version '3.2.1' id 'io.spring.dependency-management' version '1.1.4' } group = 'hello' version = '0.0.1-SNAPSHOT' java { sourceCompatibility = '17' modularity.inferModulePath = false } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter-thymeleaf' implementation 'org.springframework.boot:spring-boot-starter-web' implementation 'org.springframework.boot:spring-boot-starter-jdbc' runtimeOnly 'com.h2database:h2' testImplementation 'org.springframework.boot:spring-boot-starter-test' } tasks.named('test') { useJUnitPlatform() }
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
h2.sh 실행 문제
강의에 나온대로 따라하고 ./h2.sh 를 실행했는데 웹페이지가 안뜨고 계속 이런 에러만 나더라구요ㅜ어떻게 해결을 해야될지 모르겠습니당..
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
강의자료대로 프로젝트 생성하였고, 설정에서 build and run using을 gradle로 그대로 두었는데 다음과 같은 에러가 발생합니다.
강의자료대로 프로젝트 생성하였고, 설정에서 build and run using을 gradle로 그대로 두었는데 다음과 같은 에러가 발생합니다.build and run using를 인텔리제이로 변경하고 실행할 시에는이게 뜨고 바로 종료됩니다. 다른 모든 프로젝트에서도 이와 같은 에러가 발생하는데, 해결방법 알려주시면 감사하겠습니다.
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
FrontControllerServletV4 와 model
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]FrontControllerServletV4에서 아래 코드 부분에서 model 을 직접 생성해 view에 넘겨주는데 model 은 controller.process 를 통해 controller 에 paramMap과 model 을 넘겨 model 값을 설정합니다. 그 후 다시 프론트 컨트롤러에서 model 정보도 같이 view로 render 해주는데 이때 model 의 값이 채워져있는건가요?제가 생각하기로는 controller.process 를 통해 model 의 값이 채워지지만 viewName 만 반환해 결국 프론트 컨트롤러의 map 은 초기화 상태 그대로인것 같아서요:)이러면 model 을 View 에 넘기는 것이 의미가 없지 않나요?@Override protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String requestURI = request.getRequestURI(); ControllerV4 controller = controllerMap.get(requestURI); if (controller == null) { response.setStatus(HttpServletResponse.SC_NOT_FOUND); return; } Map<String, String> paramMap = createParamMap(request); Map<String, Object> model = new HashMap<>(); String viewName = controller.process(paramMap, model); MyView view = viewResolver(viewName); view.render(model, request, response); }
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
메세지 소스 설정
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.여기서 메세지 소스를 설정한다는 의미가 무엇인지 자세히 모르겠습니다. 예를 들어 example이라고 등록을 하면 example_en.properties example_ko.properties 이렇게 작동한다는 것인가요?
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
스프링 프레임워크 동작 구조 정리
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요 !![1] 요청 시에 @RequestBody와 HttpEntity를 안 쓰는 경우 , 응답 시에 @ResponseBody와 HttpEntity를 안 쓰는 경우[2] 요청 시에 @RequestBody와 HttpEntity를 쓰는 경우 , 응답 시에 @ResponseBody와 HttpEntity를 쓰는 경우이 두 가지 케이스로 나누어 스프링 프레임워크의 동작 구조를 정리해보았는데 제가 이해하는 게 맞는지 너무 길지만 한번만 피드백해주시면 감사하겠습니다 !![1]요청 : 파라메터 타입에 @RequestBody X 이거나 HttpEntity X의 경우응답 : 반환 값에 @ResponseBody X 이거나 HttpEntity X의 경우 1. 클라이언트의 요청 2. DispatcherServlet를 호출(urlPatterns = /* 경로이기 때문) 3. HandlerMapping의 가장 우선순위에 있는 구현체인 RequestMappingHandlerMapping을 통해 @Controller이 붙은 클래스의 객체를 매핑 정보로 활용 4. doDispatch()의 getHandler()에서 해당 매핑 정보의 컨트롤러 객체 반환 5. doDispatch()의 getHandlerAdapter()을 통해 HandlerAdapter을 호출 후 컨트롤러를 처리할 수 있는 어댑터 있는지 검증(supports()) 후 어댑터 호출(handle()) 6. 이때 컨트롤러는 @Controller의 @RequestMapping이 붙어있으므로 HandlerAdapter의 가장 우선순위의 RequestMappingHandlerAdapter 어댑터 구현체가 호출되는 것! 7. 어댑터는 컨트롤러의 파라메터에 해당되는 객체가 ArgumentResolver의 구현체로 존재하는지 검증(supportsParameter()) 후 존재하면 생성(resolveArgument()) 8. 어댑터는 생성된 객체를 컨트롤러의 파라메터에 주입하면서 컨트롤러 호출 9. 컨트롤러는 로직 수행 후 return 값(객체)을 어댑터에 반환 10. 어댑터는 ResultValueHandler 호출하면서 반환값에 해당되는 객체가 존재하는지 검증(supportsReturnType()) 후 존재하면 생성(handleReturnValue()) 11. 어댑터는 생성된 객체 및 논리적 뷰 이름으로 초기화된 ModelAndView 객체 생성 후 DispatchServlet에 반환 12. DispatchServlet에서 ViewResolver에 논리적 뷰 이름을 넘겨주면서 호출 13. ViewResolver에선 논리적 뷰 이름을 물리적 뷰 경로로 바꿔주고 그 값으로 초기화된 View 객체 반환 14. DispatchServlet에서 View객체 이용해서 render() 호출 15. JSP 뷰 템플릿이었으면 render()에서 JSP 코드로 포워드 후 랜더링하고 나머지 타임리프 같은 뷰 템플릿이면 render() 받자마자 바로 화면 랜더링 [2]요청 : 파라메터 타입에 @RequestBody O 이거나 HttpEntity O의 경우응답 : 반환 값에 @ResponseBody O 이거나 HttpEntity O의 경우 1. 클라이언트의 요청 2. DispatcherServlet를 호출(urlPatterns = /* 경로이기 때문) 3. HandlerMapping의 가장 우선순위에 있는 구현체인 RequestMappingHandlerMapping을 통해 @Controller이 붙은 클래스의 객체를 매핑 정보로 활용 4. doDispatch()의 getHandler()에서 해당 매핑 정보의 컨트롤러 객체 반환 5. doDispatch()의 getHandlerAdapter()을 통해 HandlerAdapter을 호출 후 컨트롤러를 처리할 수 있는 어댑터 있는지 검증(supports()) 후 어댑터 호출(handle()) 6. 이때 컨트롤러는 @Controller의 @RequestMapping이 붙어있으므로 HandlerAdapter의 가장 우선순위의 RequestMappingHandlerAdapter 어댑터 구현체가 호출되는 것! 7. 어댑터는 컨트롤러의 파라메터에 해당되는 타입의 객체가 ArgumentResolver의 구현체로 존재하는지 검증(supportsParameter()) 8. ArgumentResovler이 검증하던 중 컨트롤러의 파라메터 타입이 @RequestBody 혹은 HttpEntity임을 감지하고 RequestResponseBodyMethodProcessor 구현체가 동작하며 HTTP 메시지 컨버터 호출 9. RequestResponseBodyMethodProcessor 구현체는 HTTP 메시지 컨버터의 canRead()를 통하여 파라메터의 클래스 타입과 미디어 타입(Content-Type)을 검증하고 조건 만족하면 read()를 통해 HTTP 메세지 바디에 있는 데이터 변환 10. RequestResponseBodyMethodProcessor 구현체는 변환된 객체를 어댑터에 반환 11. 어댑터에선 반환된 객체를 컨트롤러의 파라메터에 주입하면서 컨트롤러 호출 12. 컨트롤러는 로직 수행 후 return 값(객체)을 어댑터에 반환 13. 어댑터는 ResultValueHandler 호출하면서 해당 반환값이 존재하는지 검증(supportsReturnType()) 14. 이때 ResultValueHandler에선 컨트롤러의 반환값이 @ResponseBody , HttpEntity임을 감지 후 RequestResponseBodyMethodProcessor 구현체가 동작하며 HTTP 메시지 컨버터를 호출 15. RequestResponseBodyMethodProcessor구현체는 HTTP 메시지 컨버터의 canWrite()를 통하여 파라메터 클래스 타입과 HTTP 요청 메시지에서의 미디어 타입(Accept)을 검증하고 조건 만족하면 write() 수행 16. write()에선 데이터를 변환하여 HTTP 응답 메세지 바디에 삽입 후 응답 메세지 클라이언트에게 반환감사합니다 !! 그리고 만약 제가 정리한 부분이 맞다면 HTTP API 방식으로 동작하는 경우 맨 마지막 16번에서 write() 이후에 만들어진 응답 메세지를 어디서 클라이언트에게 반환하는 건지 궁금합니다 !