묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결다양한 사례로 익히는 SQL 데이터 분석
CLI로 ga_export.sql 쉽게 불러오기
안녕하세요 강사님, 오늘부터 새로 강의를 듣게 되었는데 완강 목표로 열심히 듣겠습니다 ㅎㅎ강의 초반 환경설정에서 ga_export.sql이 large text여서 Dbeaver에서 스크립트 실행할 때 java heap space 부족 에러가 발생하더라고요.이 때 터미널로 쉽게 불러올 수 있는 방법을 찾았고, 다른 수강생분들에게도 도움이 될 것 같아 공유드립니다.아래 스샷처럼 터미널에서 sudo -iu postgres psql 입력 후 \i [ga_export.sql이 위치한 경로] 를 입력하면 쉽게 ga 데이터를 불러올 수 있습니다.
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
실무에서 지연로딩이 사용되는 경우
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (아니요)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]강의를 보고 엔티티를 설계하여 프로젝트를 진행하고 있습니다. 강의에서 말씀해주신대로 모든 FetchType을 LAZY로 하여 개발하고 있는데 문득 지연로딩이 실제로 어떤 상황에 필요한지가 궁금해졌습니다.강의에서 말씀해주신대로 연관관계 매핑 데이터를 즉시 가져오지 않고 필요할 때 사용할 수 있도록 할 때 지연로딩을 사용한다는 것은 이해했습니다.실무에서 어떤 상황에 적용되는지 찾아보니, 여러 이미지들을 스크롤하면서 이미지를 실제로 화면에서 보게 될 때 사용하면 효율적이라는 포스팅을 보았습니다.그런데 또 실무에서는 OSIV를 off한다고 보았습니다. OSIV가 off라면 영속성 컨텍스트가 Service, Repository에서만 살아있게 되어 어쨌든 Service 단에서 모두 처리해야 하는데 그렇다면 지연로딩이나 즉시로딩이나 별 차이가 없는 것 아닌가요?? 혹시 제가 잘못 알고 있는 것이 있는지, 어떤 상황에서 지연로딩을 사용하는 것이 좋은지 궁금합니다. 감사합니다:)
-
미해결CSS 레이아웃 - flex & grid
flex-box 하위 요소 아이템들은 자동적으로 높이값 flex-box 높이값과 같아진다고했는데,
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요 강의를 듣던중 flex-box 안에 있는 하위 요소들이 자동적으로 flex-box 높이 값을 먹는다고 했는데 실제로, <ul class="container"> <li class="item">호랑이</li> <li class="item">고양이</li> <li class="item">냥냥이</li> <li class="item">강아지</li> <li class="item">고슴도치</li> </ul> .container { display : flex} 적용했을경우 li 태그들이 container 와 높이가 같은걸 확인 할 수있었습니다. 그런데 왜 <div class="container"> <div class="item">호랑이</li> <div class="item">고양이</li> <div class="item">냥냥이</li> <div class="item">강아지</li> <div class="item">고슴도치</li> </div>인경우 container 하위 요소 div 들은 자신의 높이값을 유지하나요 ?
-
해결됨그림으로 쉽게 배우는 네트워크
허브와 전이중통신
그러면 현재 UTP 케이블로도 허브를 통해서는 전이중 통신이 불가능한게 맞는 건가요 선생님?
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
데이터베이스 연동 후 회원 등록 문제
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]안녕하세요. 강사님의 강의를 쭉 따라들으며 진행하던 중, 데이터베이스까지 연동을 하여 localhost:8080에 회원 목록이 뜨는 것을 확인했습니다.근데 회원 가입 페이지에서 shkim99라는 이름을 입력하고 엔터를 누른 뒤, localhost:8080 페이지로 갔다가 회원 목록을 눌러보니까 위 사진처럼 인덱스 번호가 2가 아닌 33으로 할당되어 있더라구요... 왜 그런걸까요??코드도 처음부터 끝까지 김영한 강사님과 똑같이 설정했습니다. 그리고 추가적으로 이번 강의의 내용은 실무에서 사용하지 않는 건가요?? 강사님께서 처음에 강의 시작하실 때 "고전 방식이라 우리 선배들은 이렇게 개발했구나~ 하면서 편하게 들으세요." 라고 하셨는데 이번 강의 내용 전체에 대한 말씀이신지 궁금하네요.
-
미해결[자동화 완전 정복] 인스타그램 휴대폰, 웹 자동화 프로그램 개발
윈도우와 맥 환경이 다른 점이 많아서 초기 환경설정부터 막혀있습니다 ㅜ
selenium 이랑 chromedriver_autoinstaller 도 다 인스톨되어있는데 왜 저렇게 노란줄이 나오는걸까요?reportMissingImports [부울 또는 문자열, 선택 사항]: 가져온 Python 파일 또는 유형 스텁 파일이 없는 가져오기에 대한 진단을 생성하거나 억제합니다. 이 설정의 기본값은 입니다 "error". 라는 오류라고 합니다....
-
미해결[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
'circle' 부분에서 질문
안녕하세요._CustomGoogleMap에서 circle를 전달 받을때circles: Set.from([circle],)이런식으로 Set을 하셨는데, 따로 이렇게 하신 이유가 있을까요? {circle} 이렇게 하는게 더 낫지 않나 싶어서요. 감사합니다
-
미해결홍정모의 따라하며 배우는 C++
5.4 goto
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요.안녕하세요 강의를 수강 중인 학생입니다. 다름이 아니라 만약 if문을 이용해서 어떤 조건을 만든 다음, 해당 조건이 성립하면 밑의 코드들을 몇 개 뛰어넘고 다른 코드로 바로 이동하기 위해서는 goto 말고 다른 방법이 있을까요??
-
해결됨홍정모의 따라하며 배우는 C언어
9-8. factorial 예제
제가 factorial 예제를 제대로 이해했는지 몰라서 질문드립니다. #define CRTSECURE_NO_WARNINGS#include <stdio.h> long loop_factorial(int n);long recursive_factorial(int n); int main(){ int num = 5; printf("%d\n", loop_factorial(num)); printf("%d\n", recursive_factorial(num)); return 0;} // (1) 반복문 factoriallong loop_factorial(int n){ long ans; for (ans = 1; n > 1; n--) ans *= n; return ans;} // (2) 재귀 호출 factoriallong recursive_factorial(int n){ if (n > 0) return n * recursive_factorial(n - 1); else return 1;} 해당 예시 코드에서 (2)번 재귀 호출 factorial 예제 과정에 대해 설명해보겠습니다. (1)처음 n에 argument 5가 대입되면, 0보다 큰 조건을 충족하므로 5 * recursive_fatorial(4)가 반환됩니다.(2)이후 recursive_factorial(4)가 실행되고, 역시 0보다 큰 조건을 충족하므로 4 * recursive_factorial(3)이 반환됩니다.(3)이 과정 끝에 recursive_factorial(0)은 조건을 충족하지 못해 1을 반환합니다.(4)그렇게 마지막에 반환된 recursive_factorial(0)부터 다시 역순으로 값이 반환됩니다.(5)1(f(0)) >> 1 * 1(f(0)) >> 2 * 1(f(1)) >> 3 * 2(f(2)) > > 4 * 6(f(3)) >> 5 * 24(f(4)) >> 120(f(5)) 의 순으로 값이 반환되어 결국 main() 함수에서 recursive_factorial(5)의 값은 120이 출력됩니다.늘 친절한 답변 감사합니다.
-
미해결10주완성 C++ 코딩테스트 | 알고리즘 코딩테스트
3-D 반례 부탁드립니다..
- 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 예제는 통과되었는데 틀려서 어디가 틀렸는지 계속 찾아보았지만 못 찾아 질문 남깁니다.http://boj.kr/1e440eca5c9e4ac69c978a0f9289603b
-
미해결[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
섹션 21. 캘린더 스케쥴러 오류 문의드립니다.
색상 상태관리 부분을 듣고 있습니다. 똑 같이 따라했는데요. 아래 내용과 같이 FutureBuilder를 사용하여 똑같이 따라 했는데도 불구하고 null이 리턴되어 오류가 납니다. future: GetIt.I<LocalDatabase>().getCategoryColors() 에서 강사님 강의에서는 데이터를 가지고 오는데, 제가 만든 코드에서는 null이 리턴되네요. 혹시 몰라 main.dart에서 GetIt.I<LocalDatabase>().getCategoryColors() 를 실행해 보고, 결과를 보면 정상적인 데이터가 들어옵니다.뭐가 문제일까요?main.dartimport 'package:calendar_schedule_exam/database/drift_database.dart'; import 'package:calendar_schedule_exam/screen/home_screen.dart'; import 'package:drift/drift.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; import 'package:intl/date_symbol_data_local.dart'; const DEFAULT_COLORS = [ // 빨강 'F44336', // 주황 'FF9800', // 노랑 'FFEB3B', // 초록 'FCAF50', // 파랑 '2196F3', // 남 '3F51B5', // 보라 '9C27B0', ]; void main() async { WidgetsFlutterBinding.ensureInitialized(); await initializeDateFormatting(); final database = LocalDatabase(); GetIt.I.registerSingleton<LocalDatabase>(database); final result = GetIt.I<LocalDatabase>().getCategoryColors(); final colors = await database.getCategoryColors(); if (colors.isEmpty) { for (String hexCode in DEFAULT_COLORS) { await database.createCategoryColor( CategoryColorsCompanion( hexCode: Value(hexCode), ), ); } } runApp(MaterialApp( theme: ThemeData( fontFamily: 'NotoSans', ), home: HomeScreen(), )); } schedule_bottom_sheet.dartimport 'package:calendar_schedule_exam/component/custom_text_field.dart'; import 'package:calendar_schedule_exam/const/colors.dart'; import 'package:calendar_schedule_exam/database/drift_database.dart'; import 'package:calendar_schedule_exam/model/category_color.dart'; import 'package:flutter/material.dart'; import 'package:get_it/get_it.dart'; class ScheduleBottomSheet extends StatefulWidget { const ScheduleBottomSheet({super.key}); @override State<ScheduleBottomSheet> createState() => _ScheduleBottomSheetState(); } class _ScheduleBottomSheetState extends State<ScheduleBottomSheet> { final GlobalKey<FormState> formKey = GlobalKey(); int? startTime; int? endTime; String? content; int? selectedColorId; @override Widget build(BuildContext context) { final bottomInset = MediaQuery.of(context).viewInsets.bottom; return SafeArea( bottom: true, child: GestureDetector( onTap: () => FocusScope.of(context).requestFocus(FocusNode()), child: Container( height: MediaQuery.of(context).size.height / 2 + bottomInset, color: Colors.white, child: Padding( padding: EdgeInsets.only(bottom: bottomInset), child: Padding( padding: const EdgeInsets.only(left: 8.0, right: 8.0, top: 16.0), child: Form( key: formKey, autovalidateMode: AutovalidateMode.always, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _Time( onStartSaved: (newValue) { startTime = int.parse(newValue!); }, onEndSaved: (newValue) { endTime = int.parse(newValue!); }, ), SizedBox(height: 16.0), _Content( onSaved: (newValue) { content = newValue; }, ), SizedBox(height: 16.0), FutureBuilder<List<CategoryColor>>( future: GetIt.I<LocalDatabase>().getCategoryColors(), builder: (context, snapshot) { print(snapshot.data); if (snapshot.hasData && selectedColorId == null && snapshot.data!.isNotEmpty) { selectedColorId = snapshot.data![0].id; } return _ColorPicker( colors: snapshot.hasData ? snapshot.data! : [], selectColorId: selectedColorId!, ); }), SizedBox(height: 16.0), _SaveButton( onPressed: onSavePressed, ), ], ), ), ), ), ), ), ); } void onSavePressed() { if (formKey.currentState == null) { return; } if (formKey.currentState!.validate()) { formKey.currentState!.save(); } else { print('에러가 있습니다.'); } } } class _Time extends StatelessWidget { final FormFieldSetter<String> onStartSaved; final FormFieldSetter<String> onEndSaved; const _Time( {super.key, required this.onStartSaved, required this.onEndSaved}); @override Widget build(BuildContext context) { return Row( children: [ Expanded( child: CustomTextField( label: '시작 시간', isTime: true, onSaved: onStartSaved, )), SizedBox(width: 16.0), Expanded( child: CustomTextField( label: '마감 시간', isTime: true, onSaved: onEndSaved, ), ), ], ); } } class _Content extends StatelessWidget { final FormFieldSetter<String> onSaved; const _Content({super.key, required this.onSaved}); @override Widget build(BuildContext context) { return Expanded( child: CustomTextField( label: '내용', isTime: false, onSaved: onSaved, ), ); } } class _ColorPicker extends StatelessWidget { final List<CategoryColor> colors; final int selectColorId; const _ColorPicker( {super.key, required this.colors, required this.selectColorId}); @override Widget build(BuildContext context) { return Wrap( spacing: 8.0, runSpacing: 10.0, children: colors.map((e) => rendColor(e, selectColorId == e.id)).toList(), ); } Widget rendColor(CategoryColor color, bool isSelected) { return Container( decoration: BoxDecoration( shape: BoxShape.circle, color: Color(int.parse('FF${color.hexCode}', radix: 16)), border: isSelected ? Border.all(color: Colors.black, width: 1.0) : null, ), height: 32, width: 32); } } class _SaveButton extends StatelessWidget { final VoidCallback onPressed; const _SaveButton({super.key, required this.onPressed}); @override Widget build(BuildContext context) { return SizedBox( width: double.infinity, child: ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: PRIMARY_COLOR, ), onPressed: onPressed, child: Text('Save'), ), ); } } drift_database.dartimport 'dart:io'; import 'package:calendar_schedule_exam/model/category_color.dart'; import 'package:calendar_schedule_exam/model/schedule.dart'; import 'package:drift/drift.dart'; import 'package:drift/native.dart'; import 'package:path/path.dart' as p; import 'package:path_provider/path_provider.dart'; part 'drift_database.g.dart'; @DriftDatabase( tables: [ Schedules, CategoryColors, ], ) class LocalDatabase extends _$LocalDatabase { LocalDatabase() : super(_openConnection()); // insert schedules Future<int> createSchedule(SchedulesCompanion data) => into(schedules).insert(data); // insert categoryColors Future<int> createCategoryColor(CategoryColorsCompanion data) => into(categoryColors).insert(data); // select all categoryColors Future<List<CategoryColor>> getCategoryColors() => select(categoryColors).get(); @override // TODO: implement schemaVersion int get schemaVersion => 1; } LazyDatabase _openConnection() { return LazyDatabase(() async { final dbFolder = await getApplicationDocumentsDirectory(); final file = File(p.join(dbFolder.path, 'db.sqlite')); return NativeDatabase(file); }); }오류내용Launching lib/main.dart on iPhone 14 Pro Max in debug mode... Running Xcode build... Xcode build done. 7.8s [VERBOSE-2:FlutterDarwinContextMetalImpeller.mm(35)] Using the Impeller rendering backend. Debug service listening on ws://127.0.0.1:61505/HeTRp4ZQphA=/ws Syncing files to device iPhone 14 Pro Max... flutter: null ======== Exception caught by widgets library ======================================================= The following _TypeError was thrown building FutureBuilder<List<CategoryColor>>(dirty, state: _FutureBuilderState<List<CategoryColor>>#41541): Null check operator used on a null value The relevant error-causing widget was: FutureBuilder<List<CategoryColor>> FutureBuilder:file:///Users/choiwooin/dev/flutterProject/calendar_schedule_exam/lib/component/schedule_bottom_sheet.dart:57:21 When the exception was thrown, this was the stack: #0 _ScheduleBottomSheetState.build.<anonymous closure> (package:calendar_schedule_exam/component/schedule_bottom_sheet.dart:68:59) #1 _FutureBuilderState.build (package:flutter/src/widgets/async.dart:612:55) #2 StatefulElement.build (package:flutter/src/widgets/framework.dart:5198:27) #3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:5086:15) #4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:5251:11) #5 Element.rebuild (package:flutter/src/widgets/framework.dart:4805:7) #6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:5068:5) #7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:5242:11)
-
해결됨[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
섹션18 영상통화 HomeScreen설계 중 에러
Error: unable to locate asset entry in pubspec.yaml: "asset/NotoSansKR-Black.otf".Target debug_android_application failed: Exception: Failed to bundle asset files.FAILURE: Build failed with an exception.* Where:Script 'C:\flutter\packages\flutter_tools\gradle\flutter.gradle' line: 1201* What went wrong:Execution failed for task ':app:compileFlutterBuildDebug'.> Process 'command 'C:\flutter\bin\flutter.bat'' finished with non-zero exit value 1* Try:> 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.orgBUILD FAILED in 12sException: Gradle task assembleDebug failed with exit code 1
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
포트폴리오 관련 질문
강의의 중고마켓 포트폴리오를 만들고 있는 수강생입니다해당 포트폴리오는 배포를 못한다고 알고 있는데, 배포링크 없는 프로젝트를 면접관이 안좋게 보지 않을지 걱정됩니다(git소스코드와 함께 readme에 gif, 기타 설명은 첨부하려고 합니다)그래서 다 수강한 후에 강의의 프로젝트와 함께, 배포까지 하는 새 프로젝트를 만들어볼까 생각중인데이경우 파이어베이스나 node.js를 활용해서, 제가 직접 기본적인 백엔드만 구축하려고 하는 새 프로젝트가 취업에 도움이 될지 궁금합니다.. 비효율적인가 싶기도 하고요아니면 다른 좋은 방법이 있을까요..?
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트
makemigrations 실행 시 TypeError: 'module' object is not iterable 오
안녕하세요. 강사님.instagram 앱 생성 과 모델 생성 후 Migration 실행이 잘 안되네요.요런 에러를 만나고 있는데요. 실행 환경 문제 같기도 한데, 해결 방법을 잘 모르겠네요. 좀 힌트가 없을까요? ㅜㅜ
-
해결됨실무 환경 그대로 주문게시판 만들기 웹개발 기초 마스터
팝업 종료 콜백
부모에서 자식 팝업을 띄울 때,this.gfnOpenPopup("popup", "Board::OB_001_02.xfdl", oArg, sPopupCallBack, oOption);이렇게 사용한다고 하셨는데,sPopupCallBack 사용예시가 있을까요? 팝업 내에서 서버호출 후에 콜백함수 예시는 있는데, 자식 팝업에서 부모로 콜백시키는 함수(sPopupCallBack) 는 있는데 예시는 없어서요. 자식 팝업에서 수정완료 후 this.close(); 하면서 부모의 그리드(주문내역 조회)를 reload 하고싶습니다.
-
해결됨실무 환경 그대로 주문게시판 만들기 웹개발 기초 마스터
주문 수정 구현 강의 중 xml update 태그
주문 수정 구현 강의 중 xml에 update 쿼리 작성시 <update> 대신 <insert> 태그를 사용한 이유가 따로 있을까요?
-
미해결스프링부트 시큐리티 & JWT 강의
권한 인증 403가 뜹니다
https://github.com/bgseong/Security-test public class JwtAuthorizationFilter extends BasicAuthenticationFilter { private TokenService tokenService; public JwtAuthorizationFilter(AuthenticationManager authenticationManager, TokenService tokenService) { super(authenticationManager); this.tokenService = tokenService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { super.doFilterInternal(request, response, chain); String token = tokenService.resolveToken(request); if(token == null){ chain.doFilter(request, response); return; } if (tokenService.validateToken(token)) { Authentication authentication = tokenService.getAuthentication(token); SecurityContextHolder.getContext().setAuthentication(authentication); System.out.println(SecurityContextHolder.getContext().getAuthentication()); } chain.doFilter(request,response); } }@EnableWebSecurity @Configuration @RequiredArgsConstructor @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig { @Autowired TokenService tokenService; @Autowired CorsConfig corsConfig; @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{ http .csrf().disable() .httpBasic().disable() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .formLogin().disable() .apply(new MyCustomDsl()) .and() .authorizeHttpRequests(authorize -> authorize .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // 특정 정적 리소스 허용 .requestMatchers("/api/v1/user/**").hasAnyRole("ADMIN", "MANAGER") .requestMatchers("/api/v1/manager/**").hasRole("ADMIN") .requestMatchers("/api/v1/admin/**").hasRole("ROLE_ADMIN") .anyRequest().permitAll()); return http.build(); } public class MyCustomDsl extends AbstractHttpConfigurer<MyCustomDsl, HttpSecurity> { @Override public void configure(HttpSecurity http) throws Exception { AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager.class); http .addFilter(corsConfig.corsFilter()) .addFilter(new LoginFilter(authenticationManager,tokenService)) .addFilter(new JwtAuthorizationFilter(authenticationManager,tokenService)); } } }@Component public class TokenService implements InitializingBean { private final UserRepository usersrepository; private final Logger logger = LoggerFactory.getLogger(TokenService.class); private static final String AUTHORITIES_KEY = "auth"; private final String secret; private final long accessTokenValidityInMilliseconds; private final long refreshTokenValidityInMilliseconds; public static final String AUTHORIZATION_HEADER = "Authorization"; public static final String REFRESHTOKEN_HEADER = "RefreshToken"; private Key key; public TokenService( UserRepository usersrepository, @Value("${spring.jwt.secret}") String secret, @Value("${spring.jwt.token-validity-in-seconds}") long tokenValidityInSeconds) { this.usersrepository = usersrepository; this.secret = secret; this.accessTokenValidityInMilliseconds = tokenValidityInSeconds * 500; this.refreshTokenValidityInMilliseconds = tokenValidityInSeconds * 1000 * 336; } @Override public void afterPropertiesSet() { byte[] keyBytes = Decoders.BASE64.decode(secret); this.key = Keys.hmacShaKeyFor(keyBytes); } public String createAccessToken(PrincipalDetails principalDetails) { return createAccessToken(principalDetails.getUser().getEmail(), principalDetails.getAuthorities()); } public String createRefreshToken(PrincipalDetails principalDetails) { return createRefreshToken(principalDetails.getUser().getEmail(), principalDetails.getAuthorities()); } public String createAccessToken(String email, Collection<? extends GrantedAuthority> inputAuthorities) { String authorities = inputAuthorities.stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); long now = (new Date()).getTime(); String accessToken = Jwts.builder() .setSubject(email) .claim(AUTHORITIES_KEY, authorities) .signWith(key, SignatureAlgorithm.HS512) .setExpiration(new Date(now + this.accessTokenValidityInMilliseconds)) .compact(); return accessToken; } public String createRefreshToken(String email, Collection<? extends GrantedAuthority> inputAuthorities) { String authorities = inputAuthorities.stream() .map(GrantedAuthority::getAuthority) .collect(Collectors.joining(",")); long now = (new Date()).getTime(); String Token = Jwts.builder() .setSubject(email) .claim(AUTHORITIES_KEY, authorities) .signWith(key, SignatureAlgorithm.HS512) .setExpiration(new Date(now + this.refreshTokenValidityInMilliseconds)) .compact(); return Token; } public Authentication getAuthentication(String token) { Claims claims = Jwts .parserBuilder() .setSigningKey(key) .build() .parseClaimsJws(token) .getBody(); User user = usersrepository.findByEmail(claims.get("sub",String.class)); Collection<? extends GrantedAuthority> authorities = Arrays.stream(claims.get(AUTHORITIES_KEY).toString().split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); PrincipalDetails principal = new PrincipalDetails(user); return new UsernamePasswordAuthenticationToken(principal, null, authorities); } public String resolveToken(HttpServletRequest request) { String bearerToken = request.getHeader(AUTHORIZATION_HEADER); if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) { return bearerToken.substring(7); } return null; } public boolean validateToken(String token) { try { Jwts.parserBuilder().setSigningKey(key).build().parseClaimsJws(token); return true; } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { logger.info("worng JWT sign"); } catch (ExpiredJwtException e) { logger.info("expire JWT"); } catch (UnsupportedJwtException e) { logger.info("No support JWT"); } catch (IllegalArgumentException e) { logger.info("JWT is worng"); } return false; } }이렇게 구성해 놨습니다. 그런데 모든 권한이 적용된 url에 접근을 하면 403 에러가 뜹니다.필터에서 SecurityContextHolder를 출력하면 아래와 같이 출력이 되는 걸 확인했고[Principal=com.securitytest.Securitytest.auth.PrincipalDetails@45095607, Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_ADMIN]]컨트롤러에서 PrincipalDetails를 호출해보니, null이라서 오류가 난다고 뜹니다. 무엇이 문제일까요ㅠㅠ..
-
해결됨실전! FastAPI 입문
AssertionError: Expected 'undone' to be called once. Called 0 times.
def test_update_todo(client, mocker): ''' 특정 객체 update 테스트 # 200 ''' mocker.patch( "main.get_todo_by_todo_id", return_value= ToDo(id=1, contents="todo", is_done=True), ) undone = mocker.patch.object(ToDo, "undone") mocker.patch( "main.update_todo", return_value=ToDo(id=1, contents="todo", is_done=False), ) # API 호출 여부 response = client.patch("/todos/1", json={"is_done": False}) undone.assert_called_once_with() assert response.status_code == 200 # 성공 assert response.json() == {"id": 1, "contents": "todo", "is_done": False} # 성공 # Resetting the mock before the next scenario # 404 mocker.patch( "main.get_todo_by_todo_id", return_value=None, ) response = client.patch("/todos/1", json={"is_done": True}) assert response.status_code == 404 assert response.json() == {"detail": "ToDo Not Found"} pytest 시 아래와 같은 에러가 발생합니다. 강사님 코드와 상이한 부분도 없고 로직도 맞게 작성한 것 같은데 undone이 한번도 호출이 되지 않았다고 합니다.During handling of the above exception, another exception occurred: client = <starlette.testclient.TestClient object at 0xffff89948640>, mocker = <pytest_mock.plugin.MockerFixture object at 0xffff89004e50> def test_update_todo(client, mocker): ''' 특정 객체 update 테스트 # 200 ''' mocker.patch( "main.get_todo_by_todo_id", return_value= ToDo(id=1, contents="todo", is_done=True), ) undone = mocker.patch.object(ToDo, "undone") > print(undone.assert_called_once_with()) E AssertionError: Expected 'undone' to be called once. Called 0 times. tests/test_main.py:106: AssertionError ========================================================== short test summary info ========================================================== FAILED tests/test_main.py::test_update_todo - AssertionError: Expected 'undone' to be called once. Called 0 times. ======================================================== 1 failed, 5 passed in 0.18s ======================================================== #
-
해결됨PM을 위한 데이터 리터러시(프로덕트 데이터 분석)
A/B 테스트 설계시에 최소 샘플 사이즈의 달성이 너무 빠른 기간에 이루어지면 어떻게 하는게 좋나요?
안녕하세요! 강의 잘 듣고 있습니다. A/B 테스트 실험 기간에 대해 헷갈리는 부분이 있는데요!A/B 테스트 시에 검정력 분석(power-analysis)를 통해 통계적인 유의미함을 판단 가능한 최소 샘플 사이즈를 정하고, 그에 따라 며칠동안 테스트를 하는게 좋을지 정해놓고 테스트를 하는 것으로 알고 있습니다!여기서 궁금한 부분은 샘플 사이즈 계산기(검정력 분석)를 통해 나온 최소 샘플을 너무 단기간에 달성한다면 얼마 동안 실험을 지속하는게 좋을지인데요.예를 들어 샘플 사이즈 계산기를 통해, 최소 샘플 사이즈와 우리 서비스의 DAU 등을 고려해서 필요한 실험 기간이 "3일"이라는 결과가 나왔다면, 과연 3일만 실험하고 끝내면 되는지 입니다.이 때, '3일만 실험을 하면 너무 짧지 않나..? 단 3일 동안의 유저가 우리 서비스의 전체 유저들을 대표한다고 볼 수는 없는 것 같아. 게다가 평일과 주말의 유저 특성이 다른 부분도 고려를 해야지. 실험 기간을 7일로 해야겠다.' 라는 생각이 들었다고 가정해볼게요.최소 샘플 사이즈를 달성한 3일이 되었을 때 아래와 같은 결과가 나왔습니다. (아래 구체적인 값들은 예시일 뿐입니다!)A군과 B군의 전환율은 각 0.1%, 0.18%로 그 차이는 0.08%인데요. 이 때는 p-value가 0.1303으로 통계적으로 유의미한 차이가 아니라는 결과가 나왔습니다.그런데 7일이 지났을 때는 아래와 같은 결과가 나왔습니다.A군과 B군은 샘플 사이즈가 각 10,000명에서 20,000명으로 증가했을 뿐, 전환율은 각 0.1%, 0.18%로 그 차이가 0.08%로 이전과 동일했는데 샘플 사이즈가 증가했다는 이유로 p-value 0.0324가 되어 통계적으로 유의미한 차이라는 결과가 나타났어요.이런 경우에는 어떻게 해석을 해야 하는 걸까요..?3일의 결과(통계적으로 유의미한 차이가 아니다.)로 의사결정한다면 '3일은 너무 짧지 않나..? 그 3일 동안 접속한 유저가 우리 서비스의 유저를 대변한다고 볼 수 있을까?'라는 생각이 들 것 같고7일의 결과(통계적으로 유의미한 차이다.)로 의사결정한다면 '원래 통계적인 차이가 없는데, 내가 표본을 더 많이 수집함으로써 통계적으로 유의미한 차이가 있다고 만들어낸 것은 아닐까?(p-hacking은 아닐까?)'라는 생각이 들 것 같아요.
-
미해결프로그래밍 시작하기 : 파이썬 입문 (Inflearn Original)
맥에서 code 실행
파이썬을 처음 배우는 거라 첫 강의를 들었습니다!잘 실행되었는데 노트북을 껐다 키기만 하면 터미널에서 code를 쳤을 때 명령이 없다고 뜹니다그래서 vs code에서 shell command를 installed하면 EACCES: permission denied, unlink '/usr/local/bin/code'라고 뜹니다어떻게 해야 하나요?