묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결토비의 스프링 부트 - 이해와 원리
스프링에 삭제/수정을 시 방어 코드 로직이 있을 까요?
스프링에 삭제/수정을 시 방어 코드 로직이 있을 까요?안녕하세요 토비님 ~ 오더 삭제를 위한 매핑 정보@RequestMapping(value ="/경로/{오더번호}" 삭제로직 mvc 공부하다가 궁금한점이 있어 문의 드립니다 위와 같은 삭제 로직 호출 부분이 있다고 가정 할 때 웹, 스프링 공부를 한 사람이 악의 적인 의도를 갖고클롬 개발자도구를 사용해서 오더 삭제 URI 주소를 확인 유추하게 되어 악의적으로 자기 오더가 아닌 오더번호 or 오더Seq를 쿠팡/배달의민족 등 삭제 시도 공격을 할 수 있을 거라고 생각해봤습니다 물론 삭제 로직 에사용자의 로그인 정보 나 롤 정보를 담은SQL에 WHERE 조건은 집어 넣을 수 있습니다 이런 악의적인 공격을 피해 갈 수 있는 다른 스프링의 기능이 있을 지 궁금 합니다 감사합니다 수고하세요.--█●●--------------------------------------------#delete#update#수정#삭제#방어#로직#방법#부트#스프링#스프링부트#spring#sping-boot#springboot#토비
-
미해결스프링부트 시큐리티 & JWT 강의
네이버 response 에 구글 이메일이 들어가 있는데
네이버로 회원가입 시getAttributes() 안 response 의 email에 구글메일이 들어가있는데왜그런지 아시는분 계신가요?
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
리눅스 mysql 8.0 설치 에러
같은 환경에서 mysql 설치시에# mysql . sudo yum install mysql-community-server -y 이부분 설치 명령어를 입력하면$ sudo yum install mysql-community-server -y Last metadata expiration check: 0:59:00 ago on Sun Apr 2 13:16:56 2023. Error: Problem: conflicting requests - nothing provides libcrypto.so.10()(64bit) needed by mysql-community-server-8.0.11-1.el7.x86_64 - nothing provides libssl.so.10()(64bit) needed by mysql-community-server-8.0.11-1.el7.x86_64 - nothing provides libcrypto.so.10(libcrypto.so.10)(64bit) needed by mysql-community-server-8.0.11-1.el7.x86_64 - nothing provides libssl.so.10(libssl.so.10)(64bit) needed by mysql-community-server-8.0.11-1.el7.x86_64 - nothing provides libcrypto.so.10()(64bit) needed by mysql-community-server-8.0.12-1.el7.x86_64 - nothing provides libssl.so.10()(64bit) needed by mysql-community-server-8.0.12-1.el7.x86_64 - nothing provides libcrypto.so.10(libcrypto.so.10)(64bit) needed by mysql-community-server-8.0.12-1.el7.x86_64 - nothing provides libssl.so.10(libssl.so.10)(64bit) needed by mysql-community-server-8.0.12-1.el7.x86_64 - nothing provides libcrypto.so.10()(64bit) needed by mysql-community-server-8.0.13-1.el7.x86_64 - nothing provides libssl.so.10()(64bit) needed by mysql-community-server-8.0.13-1.el7.x86_64 - nothing provides libcrypto.so.10(libcrypto.so.10)(64bit) needed by mysql-community-server-8.0.13-1.el7.x86_64 - nothing provides libssl.so.10(libssl.so.10)(64bit) needed by mysql-community-server-8.0.13-1.el7.x86_64 . . . . 이런식으로 충돌하는요청이 생겼다고 뜨는데 알아보니 라이브러리가 안깔려있어서 그렇다는 말도있고 어떤부분이 문제인지를 잘 모르겠어요 ㅠ...다시 처음부터 해봐도 해결이 안되고 다른 블로그 찾아봐도 아직 해결이 안되요gcc 라이브러리를 설치해야하나요? ㅠ
-
미해결스프링 핵심 원리 - 기본편
프로토타입 스코프 10분 56초
@Autowired 하니깐 저는 빨간색으로 줄쳐지는데 이거 왜이런건가요?
-
미해결스프링 핵심 원리 - 기본편
런타임 구현객체 결정에 대하여
안녕하세요 영한강사님! 매번 큰 도움을 받고있습니다.이번 질문은 '객체 지향 설계와 스프링' 챕터의 마지막 소 챕터인 '객체 지향 설계와 스프링'의 4:40초 대 언급하신 말씀에 대한 질문입니다.말씀하신 바로는 런타임에 클라이언트가 의존하는 인터페이스의 구현체가 바뀔 수 있다고 하셨는데, 문맥에 따라서 구현객체가 바뀔 수 있다는 뜻인가요? 예를 들어주신 MemoryMemberRepository와 JdbcMemberRepository도 런타임에 바뀌어서 들어갈 수 있다고 하셨는데, 저는 컴파일 시점에 구현체가 결정되야 한다고 생각했거든요. 아니면 제가 런타임에 대해 오해를 하고 있는걸까요?항상 감사합니다 ^^
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
application.yml 작성 오류
5분쯤에 application.yml 작성할 때 오류가 생겨 질문 드립니다. mysql은 잘 설치되어있는 것 같습니다감사합니다.
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
JdbcMemberRepository 에러 부분 캡쳐 해서 올립니다.
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]오류 나는 부분이 빨간 줄 쳐져 있는 두 부분인데 왜 그런걸까요?
-
미해결스프링 시큐리티 OAuth2
0auth2.0 roles의 이해
키 클락을 로컬 8080으로 띄워서 강의처럼 실습을 하고 있습니다roles1번 을 통해 user 로 로그인 바로 리다이렉트 http:localhost:8081 로 넘어가고grant access 화면이 뜨지 않는데 왜 그런건가요 ?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
인텔리제이에서 실행할 때와 터미널에서 실행할 때 차이
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]인텔리제이에서 실행 터미널에서 실행/hello 들어 갔을 때 터미널에서 실행할 때는 띄워주지 않는데 왜 그럴까요그리고 libs에 hello-spring-0.0.1-SNAPSHOT-plain.jar파일이 추가로 더 있던데 어떤 역활인지 궁금합니다
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
gradlew build 에러
해당 에러 관련 질문글과 블로그를 읽어보고 아래와 같이 환경변수 설정까지 완료했습니다.JAVA_HOME은 C:\Program Files\Java\jdk-11\bin아래는 PATH(CLASS_PATH도 설정한 경우도 있어 %JAVA_HOME%\lib 로 추가했습니다.) 또한 java -version과 javac -version은 아래와 같이 출력됩니다.그러고 나서 hello-spring directory로 가서 gradlew build를 하면 계속해서 아래와 같은 오류가 발생합니다.어디가 문제인지 알려주시면 감사하겠습니다.
-
해결됨스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
controller - service -repository 와 MVC
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]앞서 들었던 controller - service -repository 개념과 MVC 개념의 정리가 잘 안되서 그런데controller는 frontServlet으로 생각하면 되고 ,service,repository는 핸들러라 생각하면 되나요?그리고 servlet이랑 자바빈 이랑은 다른 개념인가요?
-
미해결스프링 핵심 원리 - 기본편
김영한님 효율적인 로드맵이 뭔가요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요. 지금 다음으로 강의에서는 기본편인 여기까지만 듣고 바로 JPA로 넘어가서 야생형으로 학습하시는걸 추천하셨는데, 유튜브 영상을 보면 고급전까지 스프링 강의를 다 들은다음에 JPA로 넘어가라고하시네요? 제가 이해를 잘못한건가요? 아니면 말씀이 달라지신건지요
-
미해결토비의 스프링 부트 - 이해와 원리
서버운영중 오류 예외 발생시 원인 찾는 방법 문의 드립니다
안녕하세요 토비님~이번에도 강의 내용과 상관 없는 질문 드립니다 시스템을 운영하면서 예상치 못한 에러상황이나자바소스 예외 상황이 발생 했을 때 예외가 발생한 자바소스는 어떤 자바파일 이며그 특정 자바 파일 몇번째 라인에서 왜? 오류나 예외가 발생했는지로그를 담아 db에 넣고 싶습니다. 그러면 개발자 입장에서 원인 찾아 소스 수정하는게 빠를 테니까요..(서버에 남는 로그파일에서 찾아서 로그를 다시 다운받아서 찾아 보는 것 보다 db 테이블에서 clob 으로 레고드를 남기고 찾아서, 따라 가는게 이득이라고 생각했습니다 ) 구글링해보니 우선 아파치 ExceptionUtils 부분이 있어아래 이미지와 같이 적용을 했는데 토비님이 실무에서 사용하고 계시는 다른 쉽고 좋은 베스트 방법이 있진 않을까 문의 드립니다 급한 질문 아닙니 시간 나 실 때알려주시면 감사하겠습니다. 수고하세요.--█●●--------------------------------------------#Exception #Error#예외#처리#원인#로그#부트#spring#sping-boot#springboot#토비--█●●--------------------------------------------
-
해결됨스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
인터셉터에서 HTTP 메서드를 구분하는 방법이 있을까요?
[질문 내용]안녕하세요! 강의 잘 듣고 있습니다!!다름이 아니라 restful하게 url을 설계하려 하면 url경로는 같지만 http 메서드를 다르게 하여 구분을 하는 경우가 많은 거 같습니다.이 경우 InterceptorRegistry를 통해 PathPattern을 구분하는 것 처럼 http메서드 또한 메서드 별로 구분하는 방법이 있는지 궁금합니다.감사합니다!
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
이 코드를 그대로 사용해서 S3 업로드가 가능한가요?
결국 종착지는 S3에 올려서 사용하는 건데,이 코드를 그대로 사용해도 문제 없나요?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
JdbcMemberRepository에서 어디가 잘못된걸까요?
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용].중간에 conn 부분이랑 맨아래 throws SQLException 쪽에 빨간줄이 그어 있긴하는데 같은 코드인것 같은데 어디서 잘못된건지 잘 모르겠습니다. 제가 작성한 코드는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 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(); } } @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); } private void close(Connection conn) throws SQLException { DataSourceUtils.releaseConnection(conn, dataSource); } }
-
미해결스프링 핵심 원리 - 기본편
컴포넌트 스캔 - 필터 수강 중 질문
안녕하세요. 스프링 핵심 원리 기본편 중 컴포넌트 스캔의 필터 강의를 수강하던 중 에러가 생겼습니다. 에러는 해결했지만 궁금한 점이 생겨 질문 드립니다. 구분선을 기준으로 안에 있는 말들은 모두 상황의 이해를 돕기 위한 말들이니 질문만 보고 싶으시면 구분선 밖 마지막 말만 보셔도 괜찮으실 거라 생각합니다. 제가 작성한 코드는 다음과 같고 강의의 제목과 같이 컴포넌트 스캔의 필터 부분을 학습하기 위한 예제 코드입니다. package hello.core.scan.filter; import java.lang.annotation.*; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface MyIncludeComponent { }MyIncludeComponent라는 애노테이션을 생성하고 package hello.core.scan.filter; import org.springframework.stereotype.Component; @MyIncludeComponent public class BeanA { }위와 같이 해당 애노테이션이 붙는 클래스 BeanB를 생성하고 package hello.core.scan.filter; import org.assertj.core.api.Assertions; import org.junit.jupiter.api.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.FilterType; import static org.assertj.core.api.Assertions.*; import static org.springframework.context.annotation.ComponentScan.*; public class ComponentFilterAppConfigTest { @Test void filterScan(){ ApplicationContext ac = new AnnotationConfigApplicationContext(ComponentFilterAppConfig.class); BeanA beanA = ac.getBean("beanA", BeanA.class); assertThat(beanA).isNotNull(); // BeanB beanB = ac.getBean("beanB", BeanB.class); } @Configuration @ComponentScan( includeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyIncludeComponent.class), excludeFilters = @Filter(type = FilterType.ANNOTATION, classes = MyExcludeComponent.class) ) static class ComponentFilterAppConfig{ } }위와 같이 테스트 코드를 만들어 실행하였습니다.ComponenScan을 이용해 MyIncludeComponent 애노테이션이 붙은 클래스를 자동으로 빈으로 등록시키고 조회하는 테스트 코드입니다.(MyExcludeComponent 애노테이션이나 해당 애노테이션을 붙힌 BeanB 클래스는 현재 질문과 관계가 없다고 판단해 코드를 생략하였습니다.)그런데 해당 테스트 코드를 실행하니 beanA라는 이름의 빈을 컨테이너에서 찾을 수 없다는 에러가 떴습니다.여러 방법으로 찾아보던 중 @ComponentScan 애노테이션의 includeFilters 속성과 @MyIncludeComponent 애노테이션을 올바르게 사용하여도, BeanA 클래스가 스프링 컨테이너에 등록되지 않는 경우가 생길 수 있고 이를 해결하기 위해선 @Component 애노테이션이나 @Service, @Repository 등과 같은 스프링이 제공하는 스테레오 타입 애노테이션 중 하나를 BeanA 클래스에 추가하여 해당 클래스를 스프링 빈으로 등록해야 한다는 해결책을 발견했고 그대로 따라했습니다. BeanA 클래스에 @Component 애노테이션을 붙혀 테스트 코드를 그대로 다시 실행하였고 에러는 해결이 되었습니다. 그래서 BeanA 클래스의 @Component 애노테이션을 다시 제거한 후 테스트 코드를 돌렸는데 성공하였습니다. 이런 일이 왜 발생하는지 제대로 이해가 안 되어서 질문 드립니다.@ComponentScan 애노테이션의 includeFilters 속성과 @MyIncludeComponent 애노테이션을 올바르게 사용하여도, BeanA 클래스가 스프링 컨테이너에 등록되지 않는 경우가 생길 수 있는 것인가요? 또 어떤 원리로 이렇게 등록이 안 되는 경우가 생기는지가 궁금합니다!
-
해결됨스프링 핵심 원리 - 기본편
LogDemoService 의 필요 이유
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? 예2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? 예3. 질문 잘하기 메뉴얼을 읽어보셨나요? 예[질문 내용]안녕하세요! 좋은 강의 잘 보고 있습니다. 감사합니다.LogDemoController 에서 MyLogger 의 log 함수를 통해 로그를 잘 출력하는 부분은 이해하였습니다. 다만 LogDemoService 가 왜 필요한지는 잘 모르겠더라구요. (제가 Spring 초보라서 그런듯합니다만 ^^;;)@Controller @RequiredArgsConstructor public class LogDemoController { private final LogDemoService logDemoService; private final MyLogger myLogger; @RequestMapping("log-demo") @ResponseBody public String logDemo(HttpServletRequest request) { String requestURL = request.getRequestURL().toString(); myLogger.setRequestURL(requestURL); myLogger.log("controller test"); logDemoService.logic("testId"); return "OK"; } }
-
미해결스프링 MVC 1편 - 백엔드 웹 개발 핵심 기술
getClass()와 .class의 차이
실수로 LogTestController.class 를 getLogger의 파라미터로 넣어줬더니 debug와 trace 의 로깅은 찍히지 않더라구요 getClass()를 파라미터로 넣으니 잘 되던데 어떤 차이가 있는 건가요 ?
-
해결됨스프링 핵심 원리 - 기본편
중복 타입 조회
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]1. "타입으로 조회시 같은 타입이 둘 이상 있으면, 중복 오류가 발생한다" 예제의 경우 memberRepository1()과 memberRepository2()에 return 값이 둘다 MemmoryMemberRepository()여서(둘다 타입이 memberRepository여서) 타입 중복이 된것으로 이해했는데 맞을까요? 2. "특정 타입을 모두 조회하기"에서 key값은 빈 이름이고, value값인 beansOfType.get(key)값은 빈 객체가 맞을까요?