안녕하세요. 선생님 수업을 통해 크롤링까지는 성공했습니다. HTTP POST 요청으로 받아왔는데요. 다만 Response가 넥사크로에서 사용하는 "SSV"형식으로 왔습니다. SSV:UTF-8ErrorCode:string=0ErrorMsg:string=Dataset:ds_PageList_RowType_TAXNO:string(255)TAXIDX:string(255)MEMBNAM:string(255)TSDATE:string(255)TSTIME:string(255)ACQBID:string(255)CARD_NAME:string(255)HID:string(255)ACQHID:string(255)TERMID:string(255)MTRCNO:string(255)CDNO:string(255)AUTHNO:string(255)ISTMMON:string(255)CURRCODE:string(255)AMT1:bigdecimal(25)AMT2:bigdecimal(25)AMT3:bigdecimal(25)ACQDATE:string(255)DDCEDI:string(255)...... <생략> 이렇게 못생긴 데이터가 왔는데요. 이걸 json으로 파싱하고싶어서요. 이리저리 혼자서 아스키코드 찾아보고 US, RS 사용해서 어떻게든 파싱은 했는데, 제가 짠 로직이 맞나 싶어서요. (일단 작동은 되는데.. ) 혹시 선생님이라면 어떻게 하실까 싶어서요. 이런걸 잘 파싱하려면 알고리즘을 공부해야되는걸까요? 아! 그리고 깃헙에 혹시 라이브러리가 있나 찾아봤는데요. 안나오더라구요. 이게 제일 슬펐어요. 그나저나 저런거 만드는 사람들은 정말 괴물같네요.. 저런걸 도대체 어떻게 만드는 걸까요? (코드가 본문에 저렇게 붙여넣어지는 기능도 신기하네요.. 저런건 또 어떻게 만드나요?)
안녕하세요 강사님.! 좋은 강의 잘 들었습니다.! 덕분에 좋은 자산을 남겨 놓을 수 있을 거 같습니다. 이번 강의에서 인수 테스트에 관한 내용은 없어서 인수 테스트에 관한 강사님의 전반적인 견해가 궁금합니다. 1) 다른 단위/통합 테스트에 비해서 인수 테스트에 대한 중요도가 낮다고 생각하시나요? 2) 현업에서 인수 테스트에 대한 비중은 어느 정도로 가지고 가시나요? 개인적으로는 가장 사용자 친화적인(?) 인수테스트도 중요하다고 생각하고 있습니다. 감사합니다.! 좋은 하루 되세요!
안녕하세요. 강의 정말 잘 보고 있습니다. 다름이 아니라 섹션9 세번째 강의 jdbc transaction manager 설정 및 테스트 하는 과정에서 마지막 부분에 첫번째 테스트는 통과 하지만 두번째 테스트는 실패합니다라고 설명 해주셨는데요, 아래 실제 콘솔을 보면 두번째 테스트가 성공 하고 첫번째 테스트가 실패 하고 있습니다. 그래서 궁금한 점은 junit에서 각 테스트는 코드상에서 위아래와 무관 하게 각 테스트 메서드가 병렬적으로 동작 하고, 그 과정에서 먼저 디비를 터치하고 트랜잭션을 완료 한 테스트가 먼저 성공 하는 것 인지 궁금 합니다.
강의에 나온 내용은 아니지만 개인적으로 개발을하다 궁금한 점이 생겨서 질문 드립니다. 조회 API를 만들 때 (GET요청)Controller단에서 파라미터를 받는 방식이 @RequestParam, @ModelAttribute 크게 2가지 있는데 2가지 방식중 어떤 방식을 선호하지는지 질문드립니다. @RequestParm을 사용했을 때는 Controller단에서 바로 직관적으로 어떤 파라미터를 받는지 확인이 가능하다는 장점이 있지만 Service단으로 파라미터를 넘겨줄 때, 하나하나 넘겨줘야해서 파라미터가 추가되었을 때 불편하다는 점이 있을 테고 @ModelAttribute를 사용했을 때는 수정에는 유리하겠지만 가독성은 떨어질 것 같다는 생각이 듭니다. 강사님은 어떤 생각을 가지고 계신지, 현업에서는 주로 어떤방식으로 개발을 하는지 의견주시면 감사하겠습니다.
컨트롤러 테스트에서 @AuthenticationPrincipal UserDetails userDetails에 해당하는 부분을 테스트하려고 하는데 계속 실패해서 질문드립니다 ㅠㅠ // 회원 탈퇴 @DeleteMapping("/{memberId}") @Tag(name = "member") @Operation(summary = "삭제 API", description = "유저를 삭제하는 API입니다.") @PreAuthorize("hasRole('ROLE_USER') or hasRole('ROLE_ADMIN')") public String remove(@PathVariable Long memberId, @AuthenticationPrincipal UserDetails userDetails) { try { String email = userDetails.getUsername(); log.info("email : " + email); String remove = memberService.removeUser(memberId, email); return remove; } catch (Exception e) { return "회원탈퇴 실패했습니다. :" + e.getMessage(); } } 이런식으로 프론트가 헤더에 accessToken을 보내주면 검증을 한 후 @AuthenticationPrincipal UserDetails userDetails이거로 정보를 가져와서 권한과 해당 유저인지 체크 후 처리하는 로직을 구성하고 있는데 이거를 테스트할 때 막혔습니다. 일단 구글에서 검색해서 나온 방법들을 다 사용해도 실패가 뜨네요. ↓구글에서 나온 방법 적용 @Retention(RetentionPolicy.RUNTIME) @WithSecurityContext(factory = WithAuthUserSecurityContextFactory.class) public @interface WithAuthUser { String user() default "test@test.com"; String role() default "USER"; } public class WithAuthUserSecurityContextFactory implements WithSecurityContextFactory<WithAuthUser> { @Override public SecurityContext createSecurityContext(WithAuthUser annotation) { String email = annotation.user(); String role = annotation.role(); MemberEntity member = MemberEntity.builder() .memberId(1L) .email(email) .memberPw("dudtjq8990!") .memberName("테스터") .memberRole(Role.valueOf(role)) .nickName("테스터") .memberPoint(0) .provider(null) .providerId(null) .address(AddressEntity.builder() .memberAddr("서울시 강남구") .memberZipCode("103-332") .memberAddrDetail("102") .build()) .build(); UserDetails userDetails = new PrincipalDetails(member); Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); SecurityContext context = SecurityContextHolder.createEmptyContext(); context.setAuthentication(authentication); return context; } } @Test @WithAuthUser void remove() throws Exception { Long id = 1L; String email = "test@test.com"; mockMvc.perform(delete("/api/v1/users/{memberId}", id) .contentType(MediaType.APPLICATION_JSON).accept(MediaType.APPLICATION_JSON)) .andExpect(status().isOk()); verify(memberService).removeUser(id, email); } org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalStateException: No primary or single unique constructor found for interface org.springframework.security .core.userdetails.UserDetails 이런 오류가 발생합니다. 찾아보니까 UserDetails를 구현한 클래스 PrincipalDetails에 생성자가 없어서 나오는 오류라고 하는데 문제는 해당 클래스에 기본 생성자가 있다는 것입니다. 생성자가 있는데 계속 없다고 에러가 발생합니다. @ㅇNoArgsConstructorㅇ
학습 관련 질문을 남겨주세요. 어떤 부분이 고민인지, 무엇이 문제인지 상세히 작성하면 더 좋아요! 먼저 유사한 질문이 있었는지 검색해 보세요. 서로 예의를 지키며 존중하는 문화를 만들어가요. 안녕하세요 선생님 강의 잘보고 있습니다. 질문드리고 싶은 부분은 강의에서 사용되는 아키텍처에 대한 것입니다. 레이어드 아키텍처라는것은 이해했지만, 패키지 구조가 생소해서 어떻게 구성되는지는 이해하기 어려운것 같습니다. 제가 아는 방식은 컨트롤러, 서비스, 리파짓토리, 도메인 패키지로 단순하게 작성하는 방법인데, 여기서 사용된 패키지 구성방식과 관련된 키워드나 레퍼런스를 얻을 수 있을가요?
글에 두서가 없어도 양해 바랍니다 이 수업 수강 이전에 코딩 문제를 풀 때 파이썬으로 재귀함수를 사용했던 적이 있습니다. 그때 알게 된것이 파이썬의 재귀함수에는 기본적으로 깊이의 제한이 있다는 것입니다. sys.recursionlimit()으로 확인해보니 재귀호출을 1000이상 못하도록 값이 제한되어 있고 이 값을 늘려서 사용하는것은 별로 추천되는 방법이 아닌걸로 알고 있습니다. C언어 사용할때에는 속도면에서 제한도 없고 파이썬보다 속도도 월등하다보니 재귀를 자주 사용했었는데 파이썬에서 재귀함수로 풀어야 하는 경우가 있을까요?
age_bin_list = np.arange(10, 80, 10) df['age_bin'] = pd.cut(df['age'], bins = age_bin_list) pivot_df = df.pivot_table( index = 'age_bin', columns = 'region', values = 'charges', aggfunc = 'median' # 각 구간에 해당하는 값을 중간값을 사용하겠다. ) pivot_df # 각각의 값들에 대해 크기를 가늠할 수 있게끔 시각화(주로 색상)하는 방법 # 2D 형식으로 준비된 데이터를 Seaborn heatmap으로 시각화 # annot 인자를 통해 각 셀의 값 표현 가능 fig, ax = plt.subplots() sns.heatmap(pivot_df, ax = ax, annot = True) 코드 똑같이 따라했는데 왜 저는 표에 수치가 다 표현이 안되는 건가요?
안녕하세요 강사님 ㅎㅎ 현재 챕터도 이전과 같은 증상인데 어떻게 확인하면 좋을까요? Github snapshot: https://github.com/dimz119/learn-python-django/tree/form_view 에서 다운받아서 실행시켜도 제가 작성한 코드랑 똑같은 문제가 발생하는데 확인할수있는 방법이있을까요??
groupby를 사용하면 에러는 아니고 경고가 뜹니다. FutureWarning: The default of observed=False is deprecated and will be changed to True in a future version of pandas. Pass observed=False to retain current behavior or observed=True to adopt the future default and silence this warning. chatGPT: 이 경고는 Pandas의 value_counts() 메서드를 사용할 때 발생하는 것으로 보입니다. 이 경고는 현재 버전의 Pandas에서는 observed 매개변수의 기본값이 False 이지만, 향후 버전에서는 True 로 변경될 것이라는 것을 알려주는 것입니다. 즉, 향후에는 observed=False 를 명시적으로 지정하지 않으면 경고가 표시될 것입니다. 이러한 경고를 피하려면 value_counts() 를 호출할 때 observed=False 를 명시적으로 전달하면 됩니다. 예를 들어: import pandas as pd # 예제 데이터프레임 생성 df = pd.DataFrame({'Category': ['A', 'B', 'A', 'C', 'B', 'A']}) # value_counts() 호출 시 observed 매개변수 명시 counts = df['Category'].value_counts(observed=False) print(counts) 이렇게 하면 경고가 발생하지 않습니다. 하지만 향후 Pandas 버전에서는 이러한 변경이 기본 동작이 되므로 observed 매개변수를 사용하여 코드를 업데이트하는 것이 좋습니다. -> 근데 이게 무슨 말인지 모르겠습니다! 뭐... 대충 업데이트 할 건데, 오류가 생길 수 있으니 미리 대비를 해라~ 이런 거 같은데 정확히 무슨 뜻인지 모르겠습니다!
기존 질문이 삭제되어 헷갈리실 다른 분들을 위해 자문자답 형태로 남겨둡니다. Python의 경우 어느 곳에서 다운로드 받느냐에 따라 다양한 경로에 다양한 버전이 생길 수 있습니다. 첨부해주신 사진을 봤을 때, /usr/bin/python3 를 통해 boto3를 import 하시려면, /usr/bin/pip3 를 통해 boto3를 다운로드 해주셔야 될 것 같습니다.( /usr/bin/python3 를 입력해서 실행했을 때와 python3 를 입력했을 때 버전을 비교해보시면 좋습니다.) 간단한 해결 방법으로는 /usr/bin/python3 가 아닌 그냥 python3 로 실행해주시면 될 것 같습니다. 만약 해결되지 않는다면, 현재 boto3가 설치된 경로에 있는 Python 실행 파일을 통해 파일을 실행해주시면 됩니다. 이런 번거로운 절차가 귀찮으시면, 1.3. Python 실행 단축키 설정 을 참고하셔서 실행 설정을 해주시고, vscode에서 cmd + shift + p 입력 후, Python: Select Interpreter 를 입력해주신 후에 실행하고 싶은 Python3 경로를 선택해주시면 됩니다. 또는, 우측 하단에 아래 그림과 같이 나오는 부분에서 버전을 클릭하시면 위 그림이 나오게 됩니다. 이후에는 cmd + enter 를 통해 쉽게 실행 가능합니다! 해보시고 안되시면 다시 말씀 부탁드리겠습니다.
@WebMvcTest(CompanyController::class) @ActiveProfiles("test") @WithMockUser class CompanyControllerTest { @Autowired lateinit var mockMvc: MockMvc @MockBean lateinit var getCompanyService: GetCompanyService @MockBean lateinit var adminAuthorizationFilter: AdminAuthorizationFilter private val cookie = Cookie(ADMIN_AUTH_TOKEN, "admin-auth-token") @DisplayName("회사 목록 조회") @Test fun findAll() { // given val companies = listOf( companyEntity(1, "A"), companyEntity(2, "B"), companyEntity(3, "C"), ) `when`(getCompanyService.findAll()).thenReturn(companies) // when val request = MockMvcRequestBuilders.get("/admin/api/v1/companies") .cookie(cookie).accept(MediaType.APPLICATION_JSON) // then mockMvc.perform(request) .andExpect(MockMvcResultMatchers.status().isOk) .andDo(MockMvcResultHandlers.print()) } } 위 코드를 가지고 질문드리겠습니다. val request = MockMvcRequestBuilders.get("/admin/api/v1/companies") 이 부분에서 companies가 아니라 존재하지 않는 url(ex. /admin/api/v1/cfasfsdfcompanies )라고 한 후 위 코드를 돌리면 200나옵니다. 존재하지 않는 url도 호출이 가능한건가요? 그리고 body가 항상 빈 값입니다. MockHttpServletResponse: Status = 200 Error message = null Headers = [Vary:"Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers", X-Content-Type-Options:"nosniff", X-XSS-Protection:"0", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"] Content type = null Body = Forwarded URL = null Redirected URL = null Cookies = [] 목킹이 잘못되었는지 점검해보려고 getCompanyService.findAll() 를 호출해보았는데 3개가 정상적으로 나옵니다. 혹시 몰라 소스 공유드립니다. // controller @RestController @RequestMapping("/admin/api/v1/companies") class CompanyController( private val getCompanyService: GetCompanyService ) { @GetMapping fun findAll(): List<CompanyResponse> { return getCompanyService.findAll().map { CompanyResponse.of(it) } } } // service @Service @Transactional(readOnly = true) class GetCompanyService( private val companyFindService: CompanyFindService ) { fun findAll(): List<CompanyEntity> { return companyFindService.findAll() } }