킬구형 5장. 작전2: Run Squad 장악 작전 공부중인데, Process finished with exit code 0 이라는 문구 자체가 나오질 않아. 혹시나 싶어서 새 프로젝트 만들어서 시도해봐도 마찬가지고,, 윈도우 11, java 17에 org.springframework.boot:spring-boot-starter-batch:3.5.7 환경에서 개발중인데 혹시 버전이나 OS 문제일까?? 아니면 뭔가 설정을 빼먹은건지 모르겠네.. 혹시 몰라서 application.yaml 설정도 첨부해 spring: application.name: demo output.ansi.enabled: always datasource: url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 driver-class-name: org.h2.Driver username: sa password:
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. 1. 강의 내용과 관련된 질문을 남겨주세요. 2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요. (자주 하는 질문 링크: https://bit.ly/3fX6ygx) 3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요. (질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG) 질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요. ========================================= [질문 템플릿] 1. 강의 내용과 관련된 질문인가요? (예/아니오) 2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오) 3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오) [질문 내용] 여기에 질문 내용을 남겨주세요. 이 부분에서 Student student를 선언하고 new Student();를 안했는데 어떻게 바로 .name같은 거를 사용할 수 있는 건가요? 다른 부분에서는 꼭 객체를 먼저 생성해야 접근을 할 수 있는데 이 함수에서는 왜 가능한건가요? static void initStudent(Student student, String name, int age, int grade) { student.name = name; student.age = age; student.grade = grade; }
[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
강의 따라서 프로젝트를 진행하다가 '출근 가능/불가능 확인 로직'에서 문제를 발견했습니다. 이것저것 시도하다가 드디어 해결해서 과정 공유해봅니다. 기존 코드 /// 기존의 initState() @override void initState() { super.initState(); // (아마도) 이 시점에서 오류 발생 ↓ Geolocator.getPositionStream().listen((eventPosition) { // 목적지 위치 var start = defaultLatLng; // 현재 위치 var end = LatLng(eventPosition.latitude, eventPosition.longitude); /// 거리 구하기 var distance = Geolocator.distanceBetween( start.latitude, start.longitude, end.latitude, end.longitude, ); /// 거리가 `boundary` 내부에 들어오는지 확인 setState(() => mayChoolCheck = distance <= boundary); }); } /// 위젯 빌드 @override Widget build(BuildContext context) { /// AppBar: 제목 & 액션 버튼1 var appBar = AppBar( title: Text( '오늘도 출근', style: TextStyle(color: Colors.blue, fontWeight: FontWeight.w700), ), centerTitle: true, // 안드로이드 설정 actions: <Widget>[ /// 원래 위치로 돌아오기 버튼 IconButton( onPressed: returnToMyLocation, icon: Icon(Icons.my_location), color: Colors.blue, ), ], ); return Scaffold( backgroundColor: Colors.white, appBar: appBar, /// 권한 요청을 위한 빌더 body: FutureBuilder<void>( future: checkPermission(), // 위치 권한 묻기 대화상자는 이 시점에 생성됨 builder: (context, snapshot) { if (snapshot.hasError) { return Center(child: Text('${snapshot.error}')); } // 이하 위젯 생성 코드... }, ), ); } /// Future<void> checkPermission() async { /// 위치 서비스 활성화 여부 var isLocationServiceEnabled = await Geolocator.isLocationServiceEnabled(); /// 활성화되지 않았다면 에러 발생 (앱이 현재 위치를 사용할 수 없으므로) assert(isLocationServiceEnabled, '위치 기능을 활성화하지 않았습니다.'); /// 권한 상태 확인 var checkedPermission = await Geolocator.checkPermission(); if (checkedPermission == LocationPermission.denied) { checkedPermission = await Geolocator.requestPermission(); } /// 시뮬레이션 상 `checkedPermission`이 위치 권한 허용 상태가 아니면 에러 유도 assert( checkedPermission == LocationPermission.always || checkedPermission == LocationPermission.whileInUse, '위치 권한을 허용해주세요.', ); } 오류 추적 오류의 원인은 'User denied permissions .. device's location.' 즉, 사용자가 위치 권한을 아직 허용하지 않은 시점에 위치 권한이 필요한 함수를 호출하려고 함. [ERROR:flutter/runtime/dart_vm_initializer.cc(40)] Unhandled Exception: User denied permissions to access the device's location. E/flutter (13339): #0 GeolocatorAndroid.getPositionStream.<anonymous closure> (package:geolocator_android/src/geolocator_android.dart:201:9) E/flutter (13339): #1 Stream.handleError.<anonymous closure> (dart:async/stream.dart:961:16) E/flutter (13339): #2 HandleErrorStream.handleError (dart:async/stream_pipe.dart:303:17) ... #0 에서 이미 getPositionStream().<anonymous closure> 로 추적한 걸로 보아, Geolocator.getPositionStream() 함수 호출 시점에 오류 발생한 것이 분명함. 문제의 원인과 해결책 (일부 ChatGPT의 도움을 받음) 문제의 가장 중요한 핵심은, 처음 앱 실행 시 위치 권한 확인 로직이 완전히 끝나기 전에 위치 권한 허용 이 이루어지지 않으므로, 앱 재시작 이전까지 '사용자 현재 위치 추적 기능'이 활성화되지 않고, 추가로 관련 함수에서 오류 발생 가능성이 있음. 그러므로 checkPermission() 함수는 initState() 에서 최초 한 번만 실행하고, Geolocator.getpositionStream() 함수는 따로 분리하여 checkPermission() 이 정확히 끝난 시점에 실행되도록 로직을 변경함. 1. checkPermission() 의 리턴 타입을 Future<void> 에서 Future<bool> 로 변환 /// 위치 권한 확인 및 부여 함수 Future<bool> checkPermission() async { /// 위치 서비스 활성화 여부 var isLocationServiceEnabled = await Geolocator.isLocationServiceEnabled(); assert(isLocationServiceEnabled, '위치 기능을 활성화하지 않았습니다.'); /// 권한 상태 확인 var checkedPermission = await Geolocator.checkPermission(); if (checkedPermission == LocationPermission.denied) { checkedPermission = await Geolocator.requestPermission(); } /// 위치 권한 허용 여부를 리턴 return checkedPermission == LocationPermission.always || checkedPermission == LocationPermission.whileInUse; } 2. initState() 에서 checkPermission() 과 addSubscription() 함수를 차례로 실행 ( .then() 메소드 활용) @override void initState() { super.initState(); checkPermission().then((permitted) { if (permitted) addSubscription(); }); } /// addSubscriptsion 함수 void addSubscription() { /// 리스너 함수: 출근체크 가능 여부 확인하기 Geolocator.getPositionStream().listen((eventPosition) { // 목적지 위치 var start = defaultLatLng; // 현재 위치 var end = LatLng(eventPosition.latitude, eventPosition.longitude); /// 거리 구하기 var distance = Geolocator.distanceBetween( start.latitude, start.longitude, end.latitude, end.longitude, ); /// 거리가 `boundary` 내부에 들어오는지 확인 setState(() => mayChoolCheck = distance <= boundary); }); } 3. 위젯 재빌드 시 FutureBuilder 의 future 함수 재호출을 방지하기 위해 비동기 결과를 미리 필드로 빼놓기 ChatGPT는 이를 'Cashing Future' 라고 부른다고 함. (이 코드 부분에 중요한 로직이 하나 빠져서 방금 재수정했습니다.) /// 권한 확인 여부 리턴 값 late final Future<bool> permissionFuture; @override void initState() { super.initState(); /// checkPermission()의 결과를 값으로 저장 permissionFuture = checkPermission().then((permitted) { if (permitted) addSubscription(); return permitted; }); } /// 위젯 빌드 @override Widget build(BuildContext context) { /// AppBar: 제목 & 액션 버튼1 var appBar = AppBar(...); return Scaffold( backgroundColor: Colors.white, appBar: appBar, /// 권한 요청을 위한 빌더 body: FutureBuilder<bool>( future: permissionFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting || !snapshot.hasData) { return ColoredBox( color: Colors.blue, child: Center(child: CircularProgressIndicator()), ); } /// snapshot.data가 false 값인 경우는 사용자가 위치 권한 요청을 거부했을 때 if (snapshot.hasError || snapshot.data! == false) { return Center(child: Text('위치 권한을 허용해주세요.\n${snapshot.error}')); } /// 이하 위젯 생성 코드 ... }, ), ); } 이렇게 했을 때 앱 삭제 후 다시 빌드 했을 때, 그리고 재시작 했을 때도 정상적으로 잘 작동했습니다. 코드가 많이 훼손된 느낌도 들긴 하지만.. 나름대로 공부가 돼서 기분은 좋네요. 주저리주저리 쓰느라 정신 없었는데.. 잘 이해가 안 되거나 하고 싶은 피드백이 있다면 꼭 말씀해주세요! 아무쪼록 끝까지 읽어주셔서 감사합니다.
package section06_Sorting_Searching.no06_fail; import java.util.*; public class Main { public int[] solution(int n, int[] arr) { int [] answer = new int[2]; for (int i = 0; i < n-1; i++) { if (arr[i] > arr[i+1] && answer[0] == 0) { // 첫번째 바뀐 지점 answer[0] = i+1; } else if (arr[i] > arr[i+1] && answer[0] != 0) { // 두번째 바뀐 지점 answer[1] = i+2; break; } if (i == n-2) answer[1] = answer[0] + 1; // 서로 인접한 상태에서 바꼈을때 } return answer; } public static void main(String[] args) { Main m = new Main(); Scanner sc = new Scanner(System.in); int n = sc.nextInt(); int[] arr = new int[n]; for (int i = 0; i < n; i++) { arr[i] = sc.nextInt(); } for (int x : m.solution(n, arr)) System.out.print(x + " "); } } 코드를 위와 같이 작성했는데 틀렸다고만 나와서 왜 틀렸는지 아무리 생각해봐도 잘 모르겠어서 질문합니다.
[코드팩토리] [초급] Flutter 3.0 앱 개발 - 10개의 프로젝트로 오늘 초보 탈출!
코드팩토리 디스코드에 질문하면 더욱 빠르게 질문을 받아 볼 수 있습니다! [코드팩토리 디스코드] https://bit.ly/3HzRzUM - 학습 관련 질문을 남겨주세요. 상세히 작성하면 더 좋아요! - 먼저 유사한 질문이 있었는지 검색해보세요. - 서로 예의를 지키며 존중하는 문화를 만들어가요. - 잠깐! 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 오타가 있었네요 ^^;; 해결 되었습니다. 안녕하세요. StatefulWidget 생성해보기 강의의 코드를 그대로 작성했는데요. 첨부 사진과 같은 에러가 발생합니다. 코드 이상은 없는듯 한데, 저장하니 에러가 발생합니다.
JobListener 를 구현하면서 동적으로 executionContext 를 밀어 넣을때 설명이 내가 이해한게 맞다면 오타가 발생한 듯 하다. 이렇게 InfiltrationPlanListener를 JobBuilder 의 listener() 메서드로 등록해주면 beforeStep() 메서드에서 동적으로 생성한 데이터를 각 Step에서 참조할 준비가 완료된다. 해당 문구의 작업은 JobExecutionListener 로 동작한 부분으로 beforeStep 이 아닌 beforeJob 에 의해서 동적으로 생성되는게 맞지 아니한가?!
킬구형 ㅎㅇ 요즘 형 spring-batch 오픈소스 이슈에서 잘 보고 있어. 진짜 형 대단한 거 같아. 형 그런데 나는 궁금한 게 있어 일단 이번에 나도 간단한 오타 수정으로 기여를 하기는 했는데 나도 이슈를 한번 찾아보고 싶은데 감이 안 잡혀서 형은 보통 이슈를 어떻게 찾는지, 아니면 오픈소스를 볼 때 팁 같은 게 있는지 궁금해.
안녕하세요, 강사님. 현재 자바 중급 2편을 이번 주 내로 수강 완료할 예정인 수강생입니다. 인프런에 올라와 있는 ‘김영한의 자바 공부법 로드맵’에서는 자바 고급 1, 고급 2를 뒤로 미루고 스프링 강의로 먼저 넘어가는 흐름을 추천해 주셨는데, 영상으로 올려주신 ‘김영한의 실전 자바 로드맵’에서는 자바 고급 1은 6강까지, 자바 고급 2는 전부 수강한 뒤 스프링으로 넘어가는 것이 최적이라고 말씀해 주셔서 두 로드맵 중 어떤 흐름을 따르는 것이 좋을지 고민되어 질문드립니다. 저의 목표는 다음과 같습니다. 올해 안에 「스프링 핵심 원리 - 기본편」까지 들어가는 것 스프링을 활용해서 직접 무언가를 개발해 보는 것 다만, 스프링을 빨리 배우고 싶으면서도 자바 기본기와 객체 지향에 대한 공부를 소홀히 하고 싶지는 않아서 인프런 로드맵처럼 자바 고급 1, 2를 건너뛰고 스프링으로 넘어가도 괜찮은 선택인지 확신이 서지 않습니다. 제 상황에서는 어느 로드맵 흐름을 따르는 것이 더 좋을지,자바 고급 1, 2를 어느 정도까지 수강한 뒤 스프링으로 넘어가는 것이 좋을지 추천해 주실 수 있을까요?
OAuthAttributes와 CustomOAuth2User 간의 차이가 궁금합니다. OAuthAttribute는 google로부터 받은 사용자 정보를 우리가 원하는 대로 확장 가능하게 하는 DTO라고 말씀해주셨고, CustomOAuth2User도 google로부터 받은 데이터 외에 별도의 사용자 정보를 추가하는 용도라고 말씀해주셨는데, 두 설명이 같은 의미처럼 느껴집니다. 두 클래스가 어떤 차이가 있는 건가요?
실전! 코틀린과 스프링 부트로 도서관리 애플리케이션 개발하기 (Java 프로젝트 리팩토링)
안녕하세요 강사님 취준생으로써 강의 들으면서 궁금한 점 질문 드립니다. 1.CustomRepository형식 과 Impl 형식이 보통 어떨때 자주 쓰이는 지 궁금해서 질문 드립니다. 2.JPA 에서 작성한 것들을 Querydsl 로 바꿀때가 그럼 ByXxx 에서 조인조건이 두개이상 들어가면 무조건 Querydsl 자바코드로 바꾸어 주는 게 좋을까요?