inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

172만명의 커뮤니티!! 함께 토론해봐요.

JdbcOAuth2AuthorizationService에서 DB에 저장시 오류 원인

해결됨

스프링 시큐리티 OAuth2

OAuth2AuthorizationService 구현체를 JdbcOAuth2AuthorizationService로 변경하였습니다. Spring Authorization Server 버전은 1.0 입니다. @Bean public OAuth2AuthorizationService authorizationService(JdbcTemplate jdbcTemplate, RegisteredClientRepository registeredClientRepository) { return new JdbcOAuth2AuthorizationService(jdbcTemplate, registeredClientRepository); } DB Schema : Spring Authorization Server 에서 제공 /* IMPORTANT: If using PostgreSQL, update ALL columns defined with 'blob' to 'text', as PostgreSQL does not support the 'blob' data type. */ CREATE TABLE oauth2_authorization ( id varchar(100) NOT NULL, registered_client_id varchar(100) NOT NULL, principal_name varchar(200) NOT NULL, authorization_grant_type varchar(100) NOT NULL, authorized_scopes varchar(1000) DEFAULT NULL, attributes blob DEFAULT NULL, state varchar(500) DEFAULT NULL, authorization_code_value blob DEFAULT NULL, authorization_code_issued_at timestamp DEFAULT NULL, authorization_code_expires_at timestamp DEFAULT NULL, authorization_code_metadata blob DEFAULT NULL, access_token_value blob DEFAULT NULL, access_token_issued_at timestamp DEFAULT NULL, access_token_expires_at timestamp DEFAULT NULL, access_token_metadata blob DEFAULT NULL, access_token_type varchar(100) DEFAULT NULL, access_token_scopes varchar(1000) DEFAULT NULL, oidc_id_token_value blob DEFAULT NULL, oidc_id_token_issued_at timestamp DEFAULT NULL, oidc_id_token_expires_at timestamp DEFAULT NULL, oidc_id_token_metadata blob DEFAULT NULL, refresh_token_value blob DEFAULT NULL, refresh_token_issued_at timestamp DEFAULT NULL, refresh_token_expires_at timestamp DEFAULT NULL, refresh_token_metadata blob DEFAULT NULL, PRIMARY KEY (id) ); authorization code 발급시 로그인 화면 계정 정보 입력 후 MariaDB에 저장할떄 .BadSqlGrammarException 예외가 발생합니다, 질문1)에러 로그를 보면 insertAuthorization 메소드에서 attribute 컬럼에 Principal Class 자체를 저장하는 과정에서 발생하고 있습니다, 다만, 퀴리를 DB에서 직접 실행하면 저장이 되는것 으로 보아 Spring JDBCTemplate에서 변환시 오루가 발생하는거 같은데 원인이 궁급합니다. private void insertAuthorization(OAuth2Authorization authorization) { List<SqlParameterValue> parameters = this.authorizationParametersMapper.apply(authorization); try (LobCreator lobCreator = this.lobHandler.getLobCreator()) { PreparedStatementSetter pss = new LobCreatorArgumentPreparedStatementSetter(lobCreator, parameters.toArray()); this.jdbcOperations.update(SAVE_AUTHORIZATION_SQL, pss); } } Caused by: java.sql.SQLSyntaxErrorException: (conn=952251) Could not convert [{"@class":"java.util.Collections$UnmodifiableMap"," java.security .Principal":{"@class":" org.springframework.security .authentication.UsernamePasswordAuthenticationToken","authorities":["java.util.Collections$UnmodifiableRandomAccessList",[{"@class":" org.springframework.security .core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"details":{"@class":" org.springframework.security .web.authentication.WebAuthenticationDetails","remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"B8C2C171954B719820D6592F6102AF9B"},"authenticated":true,"principal":{"@class":" org.springframework.security .core.userdetails.User","password":null,"username":"user1","authorities":["java.util.Collections$UnmodifiableSet",[{"@class":" org.springframework.security .core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true,"enabled":true},"credentials":null}," org.springframework.security .oauth2.core.endpoint.OAuth2AuthorizationRequest":{"@class":" org.springframework.security .oauth2.core.endpoint.OAuth2AuthorizationRequest","authorizationUri":" http://localhost:9000/oauth2/authorize","authorizationGrantType":{"value":"authorization_code"},"responseType":{"value":"code"},"clientId":"messaging-client","redirectUri":"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc","scopes":["java.util.Collections$UnmodifiableSet",["openid"]],"state":null,"additionalParameters":{"@class":"java.util.Collections$UnmodifiableMap","grant_type":"authorization_code"},"authorizationRequestUri":"http://localhost:9000/oauth2/authorize?response_type=code&client_id=messaging-client&scope=openid&redirect_uri=http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc&grant_type=authorization_code","attributes":{"@class":"java.util.Collections$UnmodifiableMap"} }}] to -4 RegisteredClientRepository는 구현체를 JdbcRegisteredClientRepository 로 변경해도 이상없이 동작 하고 있고 JdbcAuthorizationConsentService는 JdbcOAuth2AuthorizationService 오류로 동의 단게가 진행되지 않아서 확인해보지 않았습니다. 질문2)이외에도Authorization Server에서 blob 컴럼에 Class 자체를 저장하는 사례가 많이 있는데 커스참 구현체를 만들어서 Class 를 저장하지 않고 Authorization Server 필요한 항목만 JSON 으로 저장 하거나 테이블을 정규화 하여 Map 에 담아 주는것이 좋은 방법일까요? 참고로 Attribe는 JwtGenerator에서 보면 nonce 을 가지고 오고 있습니다. if (AuthorizationGrantType.AUTHORIZATION_CODE.equals(context.getAuthorizationGrantType())) { OAuth2AuthorizationRequest authorizationRequest = context.getAuthorization().getAttribute( OAuth2AuthorizationRequest.class.getName()); String nonce = (String) authorizationRequest.getAdditionalParameters().get(OidcParameterNames.NONCE); if (StringUtils.hasText(nonce)) { claimsBuilder.claim(IdTokenClaimNames.NONCE, nonce); } } 에러로그 전문 org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [INSERT INTO oauth2_authorization (id, registered_client_id, principal_name, authorization_grant_type, authorized_scopes, attributes, state, authorization_code_value, authorization_code_issued_at, authorization_code_expires_at,authorization_code_metadata,access_token_value,access_token_issued_at,access_token_expires_at,access_token_metadata,access_token_type,access_token_scopes,oidc_id_token_value,oidc_id_token_issued_at,oidc_id_token_expires_at,oidc_id_token_metadata,refresh_token_value,refresh_token_issued_at,refresh_token_expires_at,refresh_token_metadata) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)] at org.springframework.jdbc.support .SQLExceptionSubclassTranslator.doTranslate( SQLExceptionSubclassTranslator.java:101 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.support .AbstractFallbackSQLExceptionTranslator.translate( AbstractFallbackSQLExceptionTranslator.java:70 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.JdbcTemplate.translateException( JdbcTemplate.java:1538 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.JdbcTemplate.execute( JdbcTemplate.java:667 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.JdbcTemplate.update( JdbcTemplate.java:960 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.JdbcTemplate.update( JdbcTemplate.java:1015 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.security .oauth2.server.authorization.JdbcOAuth2AuthorizationService.insertAuthorization( JdbcOAuth2AuthorizationService.java:211 ) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0] at org.springframework.security.oauth2.server.authorization.JdbcOAuth2AuthorizationService.save ( JdbcOAuth2AuthorizationService.java:189 ) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0] at org.springframework.security .oauth2.server.authorization.authentication.OAuth2AuthorizationCodeRequestAuthenticationProvider.authenticate( OAuth2AuthorizationCodeRequestAuthenticationProvider.java:209 ) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0] at org.springframework.security .authentication.ProviderManager.authenticate( ProviderManager.java:182 ) ~[spring-security-core-6.0.1.jar:6.0.1] at org.springframework.security .oauth2.server.authorization.web.OAuth2AuthorizationEndpointFilter.doFilterInternal( OAuth2AuthorizationEndpointFilter.java:166 ) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .oauth2.server.authorization.web.OAuth2AuthorizationServerMetadataEndpointFilter.doFilterInternal( OAuth2AuthorizationServerMetadataEndpointFilter.java:84 ) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.authentication.logout.LogoutFilter.doFilter( LogoutFilter.java:107 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.authentication.logout.LogoutFilter.doFilter( LogoutFilter.java:93 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.csrf.CsrfFilter.doFilterInternal( CsrfFilter.java:116 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.header.HeaderWriterFilter.doHeadersAfter( HeaderWriterFilter.java:90 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.header.HeaderWriterFilter.doFilterInternal( HeaderWriterFilter.java:75 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .oauth2.server.authorization.config.annotation.web.configurers.AuthorizationServerContextFilter.doFilterInternal( AuthorizationServerContextFilter.java:61 ) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.context.SecurityContextHolderFilter.doFilter( SecurityContextHolderFilter.java:82 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.context.SecurityContextHolderFilter.doFilter( SecurityContextHolderFilter.java:69 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal( WebAsyncManagerIntegrationFilter.java:62 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.session.DisableEncodeUrlFilter.doFilterInternal( DisableEncodeUrlFilter.java:42 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.security .web.FilterChainProxy$VirtualFilterChain.doFilter( FilterChainProxy.java:374 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.FilterChainProxy.doFilterInternal( FilterChainProxy.java:233 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.security .web.FilterChainProxy.doFilter( FilterChainProxy.java:191 ) ~[spring-security-web-6.0.1.jar:6.0.1] at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate( DelegatingFilterProxy.java:351 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.web.filter.DelegatingFilterProxy.doFilter( DelegatingFilterProxy.java:267 ) ~[spring-web-6.0.4.jar:6.0.4] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( ApplicationFilterChain.java:185 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.ApplicationFilterChain.doFilter( ApplicationFilterChain.java:158 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.springframework.web.filter.RequestContextFilter.doFilterInternal( RequestContextFilter.java:100 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( ApplicationFilterChain.java:185 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.ApplicationFilterChain.doFilter( ApplicationFilterChain.java:158 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.springframework.web.filter.FormContentFilter.doFilterInternal( FormContentFilter.java:93 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( ApplicationFilterChain.java:185 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.ApplicationFilterChain.doFilter( ApplicationFilterChain.java:158 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal( CharacterEncodingFilter.java:201 ) ~[spring-web-6.0.4.jar:6.0.4] at org.springframework.web.filter.OncePerRequestFilter.doFilter( OncePerRequestFilter.java:116 ) ~[spring-web-6.0.4.jar:6.0.4] at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter( ApplicationFilterChain.java:185 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.ApplicationFilterChain.doFilter( ApplicationFilterChain.java:158 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.StandardWrapperValve.invoke( StandardWrapperValve.java:177 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.StandardContextValve.invoke( StandardContextValve.java:97 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.authenticator.AuthenticatorBase.invoke( AuthenticatorBase.java:542 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.StandardHostValve.invoke( StandardHostValve.java:119 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.valves.ErrorReportValve.invoke( ErrorReportValve.java:92 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.core.StandardEngineValve.invoke( StandardEngineValve.java:78 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.catalina.connector.CoyoteAdapter.service( CoyoteAdapter.java:357 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.coyote.http11.Http11Processor.service( Http11Processor.java:400 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.coyote.AbstractProcessorLight.process( AbstractProcessorLight.java:65 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.coyote.AbstractProtocol$ConnectionHandler.process( AbstractProtocol.java:859 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.tomcat.util.net .NioEndpoint$SocketProcessor.doRun( NioEndpoint.java:1734 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.tomcat.util.net.SocketProcessorBase.run ( SocketProcessorBase.java:52 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker( ThreadPoolExecutor.java:1191 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run( ThreadPoolExecutor.java:659 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run( TaskThread.java:61 ) ~[tomcat-embed-core-10.1.5.jar:10.1.5] at java.base/java.lang.Thread.run( Thread.java:833 ) ~[na:na] Caused by: java.sql.SQLSyntaxErrorException: (conn=952251) Could not convert [{"@class":"java.util.Collections$UnmodifiableMap"," java.security .Principal":{"@class":" org.springframework.security .authentication.UsernamePasswordAuthenticationToken","authorities":["java.util.Collections$UnmodifiableRandomAccessList",[{"@class":" org.springframework.security .core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"details":{"@class":" org.springframework.security .web.authentication.WebAuthenticationDetails","remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"B8C2C171954B719820D6592F6102AF9B"},"authenticated":true,"principal":{"@class":" org.springframework.security .core.userdetails.User","password":null,"username":"user1","authorities":["java.util.Collections$UnmodifiableSet",[{"@class":" org.springframework.security .core.authority.SimpleGrantedAuthority","authority":"ROLE_USER"}]],"accountNonExpired":true,"accountNonLocked":true,"credentialsNonExpired":true,"enabled":true},"credentials":null}," org.springframework.security .oauth2.core.endpoint.OAuth2AuthorizationRequest":{"@class":" org.springframework.security .oauth2.core.endpoint.OAuth2AuthorizationRequest","authorizationUri":" http://localhost:9000/oauth2/authorize","authorizationGrantType":{"value":"authorization_code"},"responseType":{"value":"code"},"clientId":"messaging-client","redirectUri":"http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc","scopes":["java.util.Collections$UnmodifiableSet",["openid"]],"state":null,"additionalParameters":{"@class":"java.util.Collections$UnmodifiableMap","grant_type":"authorization_code"},"authorizationRequestUri":"http://localhost:9000/oauth2/authorize?response_type=code&client_id=messaging-client&scope=openid&redirect_uri=http://127.0.0.1:8080/login/oauth2/code/messaging-client-oidc&grant_type=authorization_code","attributes":{"@class":"java.util.Collections$UnmodifiableMap"} }}] to -4 at org.mariadb.jdbc.export.ExceptionFactory.createException( ExceptionFactory.java:282 ) ~[mariadb-java-client-3.0.10.jar:na] at org.mariadb.jdbc.export.ExceptionFactory.create( ExceptionFactory.java:336 ) ~[mariadb-java-client-3.0.10.jar:na] at org.mariadb.jdbc.BasePreparedStatement.setInternalObject( BasePreparedStatement.java:1172 ) ~[mariadb-java-client-3.0.10.jar:na] at org.mariadb.jdbc.BasePreparedStatement.setObject( BasePreparedStatement.java:608 ) ~[mariadb-java-client-3.0.10.jar:na] at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.setObject( HikariProxyPreparedStatement.java ) ~[HikariCP-5.0.1.jar:na] at org.springframework.jdbc.core.StatementCreatorUtils.setValue( StatementCreatorUtils.java:415 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValueInternal( StatementCreatorUtils.java:236 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.StatementCreatorUtils.setParameterValue( StatementCreatorUtils.java:152 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.ArgumentPreparedStatementSetter.doSetValue( ArgumentPreparedStatementSetter.java:65 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.security .oauth2.server.authorization.JdbcOAuth2AuthorizationService$LobCreatorArgumentPreparedStatementSetter.doSetValue( JdbcOAuth2AuthorizationService.java:621 ) ~[spring-security-oauth2-authorization-server-1.0.0.jar:1.0.0] at org.springframework.jdbc.core.ArgumentPreparedStatementSetter.setValues( ArgumentPreparedStatementSetter.java:50 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.JdbcTemplate.lambda$update$2( JdbcTemplate.java:963 ) ~[spring-jdbc-6.0.4.jar:6.0.4] at org.springframework.jdbc.core.JdbcTemplate.execute( JdbcTemplate.java:651 ) ~[spring-jdbc-6.0.4.jar:6.0.4] ... 68 common frames omitted

  • java
  • spring
  • spring-boot
  • spring-boot
  • oauth
신석균 댓글 1 좋아요 0 조회수 1454

Window 세팅중 오류사항

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

도저히 모르겠습니다. 어제오늘 시간 다 날렸네요^^;

  • flutter
  • Flutter
  • 클론코딩
  • 클론코딩
jihuniglong 댓글 1 좋아요 0 조회수 356

id 객체에 추가할 때 null 을 넣어주신 이유가 궁금합니다!

해결됨

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]

안녕하세요. 질문이 있습니다, @Id @GeneratedValue(...) private Long id; 이렇게는 사용해봤는데 처음에 =null 을 사용하신 이유가 궁금합니다.

  • spring-boot
  • java
  • JPA
  • mysql
  • aws
  • spring
조재연 댓글 1 좋아요 1 조회수 864

초급자 질문

미해결

[코드팩토리] [입문] Dart 언어 4시간만에 완전정복

안녕하세요 dart강의로 코딩을 시작해보려고 강의를 들어봤습니다 제가 너무 초급자라서 그런지 잘 이해를 못하는 것 같은데 선행으로 하면 좋을 언어가 있을까요?

  • flutter
  • Flutter
  • 함수형-프로그래밍
  • 객체지향
  • oop
  • 함수형-프로그래밍
뮹뮹 댓글 1 좋아요 0 조회수 515

강제 지연 로딩 초기화에 관한 질문입니다.

해결됨

실전! 스프링 부트와 JPA 활용2 - API 개발과 성능 최적화

우선 2개의 질문을 참고하였습니다. 이것과 이것입니다. 두개의 글을 종합해 보면, V1에서 Order리스트를 반환할때는 Lazy방식이기 때문에 Member객체가 프록시 객체이고, Jackson이 해당 해당 객체를 접근하는 순간 초기화한다는 것입니다. 그리고 해당 프록시 객체를 JSON으로 읽을수 있도록 도와주는 것이 하이버네이트5모듈이라는 것입니다. 여기서 궁금한 점이 //강제 지연 로딩 설정 hibernate5Module.configure(Hibernate5Module.Feature.FORCE_LAZY_LOADING, true); 이 코드입니다. 해당 코드는 강제 지연 로딩 설정이라고 하는데 강의 21분 20초경 LAZY를 강제 초기화 한다고 나와있습니다. 저는 위의 코드와 for (Order order : orders) { order.getMember().getName(); order.getDelivery().getAddress(); } 이 코드가 같은 역할을 한다고 이해했습니다. 위의 두개의 코드를 삭제하면, 포스트맨으로 요청을 보냈을 때, Member, orderItems, Delivery에는 null 값이 들어갑니다. 두개의 코드중 하나를 넣으면 요청을 넣었을때 Member, orderItems, Delivery에 실제 값이 들어가게 됩니다. 하지만 위의 두 글을 종합한 내용을 보면 Jackson이 해당 해당 객체를 접근하는 순간 초기화 라는 내용이 있습니다. 그렇다면 이미 초기화 된 프록시 객체일텐데 왜 위의 강제초기화 코드를 넣어야 실제 값이 들어가게 되는지 궁금합니다. jackson이 프록시 객체에 접근할때 초기화가 되어서 두 코드를 넣지 않아도 null이 아닌 실제 값이 나와야하는 것 아닌가요? 글이 너무 길어 죄송합니다..ㅠㅠ

  • JPA
  • spring
  • jpa
  • java
  • spring-boot
양지웅 댓글 1 좋아요 2 조회수 798

@RestController, @GetMapping import가 안됩니다. ㅠ

미해결

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]

안녕하세요. 선생님 따라서 코딩중인데 구글링결과대로 시도해봐도 딱히 해결되지 않아서 질문 남겼습니다... 제목 그대로 import 자체가 되지 않아요 ㅠ

  • spring-boot
  • JPA
  • aws
  • spring
  • jpa
  • mysql
  • java
데브키맨 댓글 2 좋아요 2 조회수 3635

양방향 연관관계에 대한 질문입니다!

미해결

자바 ORM 표준 JPA 프로그래밍 - 기본편

<요구사항> 사용자가 맘에 드는 장소를 저장 할 수 있다. Place 에서 FavoritePlace 를 Join 하고 싶다. <관계도> Place(1) - (N)FavoritePlace(N) - (1)User <질문내용> Place 에는 FavoritePlace 필드가 없기 때문에 join 을 사용 할 수 가 없어서 , 양방향 매핑을 이용 하였습니다. 이럴 경우 양방향 매핑을 사용하는것이 맞는지 궁금하고, FavoirtePlace 의 상태가 변경될때의,연관관계 편의메서드를 구현하였는데 흐름은 Place 가 가지고 있는 list 를 순회하여, 바뀌기전의 FavoirtePlace 를 삭제하고 새로운 FavoirtePlace 를 add 하는 로직을 선택하였습니다. 그러다보니 수많은 List 중 FavoirtePlace 하나를 순회하여 찾아 제거 하는 작업이 조금 버거울거같다는 고민이 생겼습니다. 제가 이해한 양방향을 써야 하는 상황이 이부분이 맞는지, 위와 같은 상황에서 어떻게 해결하는게 조금 더 현명할지 조언 듣고 싶습니다! 감사합니다

  • jpa
  • java
  • JPA
dlektl6 댓글 3 좋아요 0 조회수 703

@Repository 빨간줄

미해결

자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]

BookMemoryRepository랑 BookMysqlRepository에 @Repository를 모두 붙이면 빨간줄이 강의상에선 나는데 저는 이상이 없는 데 혹시 스프링 버전 차이인건지 궁금합니다.

  • spring
  • JPA
  • java
  • aws
  • mysql
  • jpa
  • spring-boot
이진섭 댓글 2 좋아요 1 조회수 656

enum 타입으로 한글 사용하기

해결됨

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

안녕하세요, 선생님. 현재 에어코리아에서 제공하는 DB 정보들이 현재 강의와 달라서 제 나름대로 수정하여 듣고 있는데... 혹 enum에 한글 데이터를 집어 넣을 수 있는 방법이 있을까요? sidoname값은 모두 한글입니다.

  • flutter
  • 클론코딩
  • 클론코딩
  • Flutter
감사 댓글 1 좋아요 0 조회수 2835

강의 예시에 대한 답변이 궁금합니다.

미해결

Flutter 중급 2편 - 실전 앱 개발 - 미국 주식 앱 (with 클린 아키텍처)

4:20초에서 '예) 로그인 작업시 얻은 Token 정보를 LoginViewModel에서 가지고 있다.~~' 라는 질문에 대한 답변이 Token 정보가 필요한 스크린들에서 하나의 ViewModel을 공유하라는 것이 맞을까요?

  • flutter
  • Flutter
  • ios
  • android
aoddydrl119 댓글 1 좋아요 0 조회수 383

CustomScrollView 강의 문의

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

안녕하세요. 제가 Scrollable Widgets 부분까지 수강하다가 궁금한 점이 생겨서 질문드립니다. CustomScrollView 강의 첫 부분을 보면 한 화면에서 두 개의 List Widget을 한번에 스크롤하기 위해서는 CustomScrollView을 사용해야 한다고 하셨는데 해당 내용에 대한 강의는 없는 것 같아서요~ 혹시 미세먼지 앱 강의에서 해당 내용이 다뤄지는 건가요?

  • flutter
  • 클론코딩
  • 클론코딩
  • Flutter
Y samantha 댓글 1 좋아요 0 조회수 292

joincolumn 제가 이해한게 맞을까요?

해결됨

자바 ORM 표준 JPA 프로그래밍 - 기본편

학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예) [질문 내용] Joincolumn의 name속성은 그저 member테이블의 조인컬럼의 컬럼명을 지정하는것뿐 team과 매핑하는것과는 관련이없다. member와 team을 연관관계맺는것은 referencedColumnName속성이 하지만 이것을 생략하면 자동으로 team의 pk값으로 연관관계를 맺어줘서 생략한다. 이게 맞을까요?

  • jpa
  • java
  • JPA
기범 댓글 1 좋아요 0 조회수 627

WebView 실행 시 빈화면

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

안녕하세요. WebView 실행 시 시뮬레이터가 빈화면으로만 나옵니다. 그래서 블로그 말고 m.naver.com으로 하면 네이버 화면은 나오는데, 블로그만 뜨질 않습니다. 구글링을 해서 플러그인도 써보았지만 안되서 방안을 요청드립니다. 해결방안이 있을까요? 원격지원도 가능하실까요?

  • flutter
  • 클론코딩
  • 클론코딩
  • Flutter
최지수 댓글 1 좋아요 0 조회수 679

이미지 관련 질문

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

질문하기에 앞서 너무 친절한 답변 감사드립니다. 강의를 듣는도중에 이미지 관련해서 절대 배포하면 안된다고 하셨는데 깃허브에 올려도 안되는걸까요..?

  • flutter
  • 클론코딩
  • 클론코딩
  • Flutter
soulno 댓글 1 좋아요 0 조회수 280

05. AccountPage UI 작성강의 설명문의

미해결

Flutter 입문 - 안드로이드, iOS 개발을 한 번에 (with Firebase)

05. AccountPage UI 작성강의 중 강의시간 8.57분 중 SizeBox에 커서를 둔상태로 Align으로 변경하시는데 그부분에 대한 설명이 없이 바로 화면이 전환된거같아 문의드립니다.(일부분 설명생략..)

  • flutter
  • Flutter
  • android
  • ios
타릭 댓글 1 좋아요 0 조회수 391

firestore에서 List<String>을 받아오고 싶을 때

미해결

Flutter 입문 - 안드로이드, iOS 개발을 한 번에 (with Firebase)

안녕하세요. 강의를 따라 오던 중 복수의 이미지 리스트 List<String>으로 업로드하고 또 읽어올 수 있을지 궁금증이 생겨 테스트를 하던 중 도저히 해결되지 않은 문제가 있어 질문 올립니다.(업로드는 성공했습니다.) 현재 강의 코드에서 imageUrl 만 String 에서 List<String> 으로 바꿔 아래와 같이 수정했습니다. class Post { String id; String userId; String title; List<String> imageUrls; Post({ required this.id, required this.userId, required this.title, required this.imageUrls, }); factory Post.fromJson(Map<String, dynamic> json) { return Post( id: json['id'] as String, userId: json['userId'] as String, title: json['title'] as String, imageUrls: json['imageUrls'] as List<String>, ); } Map<String, dynamic> toJson() { return { 'id': id, 'userId': userId, 'title': title, 'imageUrls': imageUrls, }; } } 여기까진 문제가 없었는데, firestore에서 데이터를 불러와 List<Post>로 가공하는 부분에서 아래와 같이 에러가 발생하고 있습니다. List<Post> posts = snapshot.data!.docs.map((el) => el.data()).toList(); // type 'List<dynamic>' is not a subtype of type 'List<String>' in type cast 다음처럼 fromJson 함수를 수정해보려 했는데 해결되지 않아 질문합니다 ㅠㅠ 해결 방법이 있을까요?? import 'dart:convert'; // ... class Post { // ... factory Post.fromJson(Map<String, dynamic> jsonData) { final imageUrls = json.decode(jsonData['imageUrls']).cast<String>().toList(); return Post( id: jsonData['id'] as String, userId: jsonData['userId'] as String, title: jsonData['title'] as String, imageUrls: imageUrls, ); } (위와 같이 수정하면 type 'List<dynamic>' is not a subtype of type 'String' 이런 에러 메세지가 뜹니다.

  • flutter
  • android
  • Flutter
  • ios
윤서준 댓글 1 좋아요 0 조회수 565

맥에서 intelij 사용 단축키에 대해 알고싶습니다

미해결

자바 개발자를 위한 코틀린 입문(Java to Kotlin Starter Guide)

안녕하세요, 주제와는 좀 다른 질문인데요. 강의하시는거 보면 맥에서 intelij 를 상당히 잘 활용하신다고 느꼈습니다. 특히, 9강에서 ide 화면을 4분할로 빠르게 구성하는게 인상적이었는데, 혹시 그 방법과 단축키 알려주실수 있나요?

  • java
  • kotlin
  • oop
밗성배 댓글 1 좋아요 1 조회수 642

질문

해결됨

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

OOP 강의에서 상속 공부하던 중 의문이 생겨 질문 드립니다. void main() { print('-------------Idol-------------'); Idol apink = Idol(name: "에이핑크", members_count: 5); apink.say_name(); apink.say_members_count(); // apink.say_male(); - 이건 X print('-------------boy_group-------------'); boy_group bts = boy_group('bts',7); bts.say_name(); bts.say_members_count(); bts.say_male(); print('-------------girl_group-------------'); girl_group red_velvet = girl_group('Red Velvet',5); red_velvet.say_name(); red_velvet.say_members_count(); red_velvet.say_female(); print('-------------type_comparison-------------'); print(apink is Idol); print(apink is boy_group); print(apink is girl_group); print('-------------type_comparison2-------------'); print(bts is Idol); print(bts is boy_group); print(bts is girl_group); print('-------------type_comparison3-------------'); print(red_velvet is Idol); print(red_velvet is boy_group); print(red_velvet is girl_group); } // 상속 - inheritance // // 상속을 받으면, 부모 클래스의 모든 속성을 자식 클래스가 부여받는다. class Idol { //이름 String name; //멤버 숫자 int members_count; Idol({ required this.name, required this.members_count, }); void say_name() { print("저는 ${this.name}입니다."); } void say_members_count() { print("${this.name}은 ${this.members_count}명의 멤버가 있습니다."); } } // super가 부모를 의미하는! class boy_group extends Idol { boy_group( String name, int members_count, ) : super( name: name, members_count: members_count, ); // 밑의 super(~~) 이것이 Idol(~~) 을 의미하는 것임! 즉, 부모의 constructor 의미하는 것! void say_male(){ print("저는 남자아이돌입니다"); } } class girl_group extends Idol { girl_group( String name, int members_count, ) : super( name: name, members_count: members_count, ); // 밑의 super(~~) 이것이 Idol(~~) 을 의미하는 것임! 즉, 부모의 constructor 의미하는 것! void say_female(){ print("저는 여자아이돌입니다"); } } 여기에서는 name : name을 함으로써, 자식 class에서 받은 name을 부모 class의 name으로 복사해준다/넣어준다고 하셨는데, 그 다음 코드 void main() { TimesTwo tt = new TimesTwo(2); print(tt.calculate()); TimesFour tf = new TimesFour(2); print(tf.calculate()); } // method : function인데, class 내부에 있는! // override - 재정의 (우선시하다. 덮어쓰다) class TimesTwo { final int number; TimesTwo( this.number, ); //method int calculate() { return number * 2; } } class TimesFour extends TimesTwo { TimesFour( int number, ) : super(number); // @override //생략해도 되는데, 예의상 기입한다. int calculate() { // return super.number * 4; return super.calculate() * 2; // 이것도 가능! } } 이 내용을 보면, 부모class는 그냥 number인 것이 왜 그런 것이지 잘 이해가 안 됩니다. number:number가 아닌 이유가 어떤 것일까요?? named(required)의 여부가 이를 결정한 것일까요??

  • flutter
  • 클론코딩
  • Flutter
  • 클론코딩
kimseunghwan7777 댓글 1 좋아요 0 조회수 325

Failed to reformat code 오류

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

HomeScreen(), 할때 대문자 S가 입력이 안되고 Failed to reformat code 해당 오류가 발생됩니다ㅜㅜ찾아봐도 안나오네요..

  • flutter
  • 클론코딩
  • Flutter
  • 클론코딩
soulno 댓글 1 좋아요 0 조회수 391

flutter doctor 실행시 다름 ㅠㅠㅠ

미해결

[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!

flutter doctor 실행 했을때 이렇게 나옵니다. 2번째꺼는 저기서 말한 가이드 대로 flutter doctor --android-licenses 이렇게 나와요...ㅠㅠㅠ 그리고 마지막 [!] Android Studio (version 2022.1) ✗ Unable to find bundled Java version. 이부분은 어떻게 해결해야할지 모르겠습니다. ㅠㅠㅠㅠ

  • flutter
  • 클론코딩
  • Flutter
  • 클론코딩
mbio 댓글 4 좋아요 0 조회수 1178

인기 태그

인프런 TOP Writers

주간 인기글