묻고 답해요
164만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결프로그래밍 시작하기 : 파이썬 입문 (Inflearn Original)
안녕하세요! 강의자료 부탁드립니다!
kyungy00@naver.com
-
미해결이미지 관리 풀스택(feat. Node.js, React, MongoDB, AWS)
node js를 이용하고 mysql에 이미지 경로 저장
nodejs, multer를 통해서 이미지를 업로드했습니다db에 해당 파일명uuid()를 통해서 저장을 했는데 이미지 주소복사 해서 검색해서 들어가면 이미지가 나오는데 검색해도 못들어가게 하려면 어떻게해야하나요? 또는 관리자만 들어갈수있게하려는데 방법이 있을까요
-
미해결홍정모의 게임 만들기 연습 문제 패키지
따배C++ 몇 강까지 학습한 후 수강가능 할까요?
현재 따배c++을 수강중입니다. 뭔가를 빨리 만들어 보며 실전 위주로 공부하고 싶어서 게임 페키지도 구매하였습니다. 게임 패키지 강의 소개에 12강 기준이라는 글을 봤는데 따배c++ 강의 12강까지 수강하면 게임 페키지 강의를 듣는데 문제가 없을까요?
-
해결됨Vue.js 끝장내기 - 실무에 필요한 모든 것
npm i 에러
안녕하세요. 맥북 m2으로 수업 듣고있는 수강생입니다.이전까지 수업은 잘 진행 하였는데, 이번 수업에서는 시작부터 에러가 발생해서 진행을 할 수 가 없네요..ㅠㅠ 도움 부탁드립니다.nvm 버전: 0.39.3node 버전: v18.16.1 (LTS)npm 버전: 9.5.1다른 질문들 및 에러에 대해 구글에서 살펴보고 프로젝트 폴더에서 node_modules와 package-lock.json 삭제 이후 npm i bcryptnpm i 둘 다 비슷한 에러 메세지가 발생하고 있습니다. 에러 로그는 아래와 같습니다.$ npm i bcrypt npm WARN deprecated source-map-url@0.4.1: See https://github.com/lydell/source-map-url#deprecated npm WARN deprecated swagger-methods@2.0.2: This package is no longer being maintained. npm WARN deprecated urix@0.1.0: Please see https://github.com/lydell/urix#deprecated npm WARN deprecated resolve-url@0.2.1: https://github.com/lydell/resolve-url#deprecated npm WARN deprecated source-map-resolve@0.5.3: See https://github.com/lydell/source-map-resolve#deprecated npm WARN deprecated fsevents@1.2.13: The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2 npm WARN deprecated chokidar@2.1.8: Chokidar 2 does not receive security updates since 2019. Upgrade to chokidar 3 with 15x fewer dependencies npm WARN deprecated babel-eslint@8.2.6: babel-eslint is now @babel/eslint-parser. This package will no longer receive updates. npm WARN deprecated bcrypt@3.0.8: versions < v5.0.0 do not handle NUL in passwords properly npm WARN deprecated json-schema-ref-parser@7.1.4: Please switch to @apidevtools/json-schema-ref-parser npm WARN deprecated node-pre-gyp@0.14.0: Please upgrade to @mapbox/node-pre-gyp: the non-scoped node-pre-gyp package is deprecated and only the @mapbox scoped package will recieve updates in the future npm WARN deprecated core-js@2.6.12: core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js. npm ERR! code 1 npm ERR! path /Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt npm ERR! command failed npm ERR! command sh -c node-pre-gyp install --fallback-to-build npm ERR! CXX(target) Release/obj.target/bcrypt_lib/src/blowfish.o npm ERR! CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt.o npm ERR! CXX(target) Release/obj.target/bcrypt_lib/src/bcrypt_node.o npm ERR! Failed to execute '/Users/paris/.nvm/versions/node/v18.16.1/bin/node /Users/paris/.nvm/versions/node/v18.16.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/lib/binding/bcrypt_lib.node --module_name=bcrypt_lib --module_path=/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/lib/binding --napi_version=8 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v108' (1) npm ERR! node-pre-gyp info it worked if it ends with ok npm ERR! node-pre-gyp info using node-pre-gyp@0.14.0 npm ERR! node-pre-gyp info using node@18.16.1 | darwin | arm64 npm ERR! node-pre-gyp WARN Using needle for node-pre-gyp https download npm ERR! node-pre-gyp info check checked for "/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/lib/binding/bcrypt_lib.node" (not found) npm ERR! node-pre-gyp http GET https://github.com/kelektiv/node.bcrypt.js/releases/download/v3.0.8/bcrypt_lib-v3.0.8-node-v108-darwin-arm64-unknown.tar.gz npm ERR! node-pre-gyp http 404 https://github.com/kelektiv/node.bcrypt.js/releases/download/v3.0.8/bcrypt_lib-v3.0.8-node-v108-darwin-arm64-unknown.tar.gz npm ERR! node-pre-gyp WARN Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v3.0.8/bcrypt_lib-v3.0.8-node-v108-darwin-arm64-unknown.tar.gz npm ERR! node-pre-gyp WARN Pre-built binaries not found for bcrypt@3.0.8 and node@18.16.1 (node-v108 ABI, unknown) (falling back to source compile with node-gyp) npm ERR! node-pre-gyp http 404 status code downloading tarball https://github.com/kelektiv/node.bcrypt.js/releases/download/v3.0.8/bcrypt_lib-v3.0.8-node-v108-darwin-arm64-unknown.tar.gz npm ERR! gyp info it worked if it ends with ok npm ERR! gyp info using node-gyp@9.3.1 npm ERR! gyp info using node@18.16.1 | darwin | arm64 npm ERR! gyp info ok npm ERR! gyp info it worked if it ends with ok npm ERR! gyp info using node-gyp@9.3.1 npm ERR! gyp info using node@18.16.1 | darwin | arm64 npm ERR! gyp info find Python using Python version 3.11.4 found at "/Library/Frameworks/Python.framework/Versions/3.11/bin/python3" npm ERR! gyp info spawn /Library/Frameworks/Python.framework/Versions/3.11/bin/python3 npm ERR! gyp info spawn args [ npm ERR! gyp info spawn args '/Users/paris/.nvm/versions/node/v18.16.1/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py', npm ERR! gyp info spawn args 'binding.gyp', npm ERR! gyp info spawn args '-f', npm ERR! gyp info spawn args 'make', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/build/config.gypi', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/Users/paris/.nvm/versions/node/v18.16.1/lib/node_modules/npm/node_modules/node-gyp/addon.gypi', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/Users/paris/Library/Caches/node-gyp/18.16.1/include/node/common.gypi', npm ERR! gyp info spawn args '-Dlibrary=shared_library', npm ERR! gyp info spawn args '-Dvisibility=default', npm ERR! gyp info spawn args '-Dnode_root_dir=/Users/paris/Library/Caches/node-gyp/18.16.1', npm ERR! gyp info spawn args '-Dnode_gyp_dir=/Users/paris/.nvm/versions/node/v18.16.1/lib/node_modules/npm/node_modules/node-gyp', npm ERR! gyp info spawn args '-Dnode_lib_file=/Users/paris/Library/Caches/node-gyp/18.16.1/<(target_arch)/node.lib', npm ERR! gyp info spawn args '-Dmodule_root_dir=/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt', npm ERR! gyp info spawn args '-Dnode_engine=v8', npm ERR! gyp info spawn args '--depth=.', npm ERR! gyp info spawn args '--no-parallel', npm ERR! gyp info spawn args '--generator-output', npm ERR! gyp info spawn args 'build', npm ERR! gyp info spawn args '-Goutput_dir=.' npm ERR! gyp info spawn args ] npm ERR! gyp info ok npm ERR! gyp info it worked if it ends with ok npm ERR! gyp info using node-gyp@9.3.1 npm ERR! gyp info using node@18.16.1 | darwin | arm64 npm ERR! gyp info spawn make npm ERR! gyp info spawn args [ 'BUILDTYPE=Release', '-C', 'build' ] npm ERR! In file included from ../src/bcrypt_node.cc:1: npm ERR! ../../nan/nan.h:2536:8: warning: 'SetAccessor' is deprecated: Do signature check in accessor [-Wdeprecated-declarations] npm ERR! tpl->SetAccessor( npm ERR! ^ npm ERR! /Users/paris/Library/Caches/node-gyp/18.16.1/include/node/v8-template.h:837:3: note: 'SetAccessor' has been explicitly marked deprecated here npm ERR! V8_DEPRECATED("Do signature check in accessor") npm ERR! ^ npm ERR! /Users/paris/Library/Caches/node-gyp/18.16.1/include/node/v8config.h:460:35: note: expanded from macro 'V8_DEPRECATED' npm ERR! # define V8_DEPRECATED(message) [[deprecated(message)]] npm ERR! ^ npm ERR! In file included from ../src/bcrypt_node.cc:1: npm ERR! In file included from ../../nan/nan.h:2884: npm ERR! ../../nan/nan_typedarray_contents.h:34:43: error: no member named 'GetContents' in 'v8::ArrayBuffer' npm ERR! data = static_cast<char*>(buffer->GetContents().Data()) + byte_offset; npm ERR! ~~~~~~~~^ npm ERR! 1 warning and 1 error generated. npm ERR! make: *** [Release/obj.target/bcrypt_lib/src/bcrypt_node.o] Error 1 npm ERR! gyp ERR! build error npm ERR! gyp ERR! stack Error: `make` failed with exit code: 2 npm ERR! gyp ERR! stack at ChildProcess.onExit (/Users/paris/.nvm/versions/node/v18.16.1/lib/node_modules/npm/node_modules/node-gyp/lib/build.js:203:23) npm ERR! gyp ERR! stack at ChildProcess.emit (node:events:513:28) npm ERR! gyp ERR! stack at ChildProcess._handle.onexit (node:internal/child_process:291:12) npm ERR! gyp ERR! System Darwin 22.3.0 npm ERR! gyp ERR! command "/Users/paris/.nvm/versions/node/v18.16.1/bin/node" "/Users/paris/.nvm/versions/node/v18.16.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "build" "--fallback-to-build" "--module=/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/lib/binding/bcrypt_lib.node" "--module_name=bcrypt_lib" "--module_path=/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/lib/binding" "--napi_version=8" "--node_abi_napi=napi" "--napi_build_version=0" "--node_napi_label=node-v108" npm ERR! gyp ERR! cwd /Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt npm ERR! gyp ERR! node -v v18.16.1 npm ERR! gyp ERR! node-gyp -v v9.3.1 npm ERR! gyp ERR! not ok npm ERR! node-pre-gyp ERR! build error npm ERR! node-pre-gyp ERR! stack Error: Failed to execute '/Users/paris/.nvm/versions/node/v18.16.1/bin/node /Users/paris/.nvm/versions/node/v18.16.1/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js build --fallback-to-build --module=/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/lib/binding/bcrypt_lib.node --module_name=bcrypt_lib --module_path=/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt/lib/binding --napi_version=8 --node_abi_napi=napi --napi_build_version=0 --node_napi_label=node-v108' (1) npm ERR! node-pre-gyp ERR! stack at ChildProcess.<anonymous> (/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/node-pre-gyp/lib/util/compile.js:83:29) npm ERR! node-pre-gyp ERR! stack at ChildProcess.emit (node:events:513:28) npm ERR! node-pre-gyp ERR! stack at maybeClose (node:internal/child_process:1091:16) npm ERR! node-pre-gyp ERR! stack at ChildProcess._handle.onexit (node:internal/child_process:302:5) npm ERR! node-pre-gyp ERR! System Darwin 22.3.0 npm ERR! node-pre-gyp ERR! command "/Users/paris/.nvm/versions/node/v18.16.1/bin/node" "/Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/.bin/node-pre-gyp" "install" "--fallback-to-build" npm ERR! node-pre-gyp ERR! cwd /Users/paris/Documents/Dev/vue/inflearn/vue-til-server/node_modules/bcrypt npm ERR! node-pre-gyp ERR! node -v v18.16.1 npm ERR! node-pre-gyp ERR! node-pre-gyp -v v0.14.0 npm ERR! node-pre-gyp ERR! not ok npm ERR! A complete log of this run can be found in: npm ERR! /Users/paris/.npm/_logs/2023-07-13T05_21_26_110Z-debug-0.log
-
미해결스프링 MVC 2편 - 백엔드 웹 개발 활용 기술
@ModelAttribute 와 생성자의 관계
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]강의 예제를 따라하다가 @ModelAttribute 에 매핑하는 Item 클래스에 @AllArgsConstructor 와 @NoArgsConstructor 만 붙이고, 진행을 하니 @AllArgsConstructor가 있음에도 불구하고 form 데이터의 값을 매핑하지 못했습니다. 이 경우 기본 생성자를 지우거나, @Setter 를 달면 정상작동하는데, 왜 이렇게 동작하는 것인지 질문드리고 싶습니다 !
-
미해결스프링 입문 - 코드로 배우는 스프링 부트, 웹 MVC, DB 접근 기술
JdbcMemberRepository.java 코드
안녕하세요! 순수 JDBC 강의에서 JdbcMemberRepository.java 전체 코드 혹시 어디서 확인할 수 있을까요....?!
-
미해결설계독학맛비's 실전 Verilog HDL Season 1 (Clock부터 Internal Memory까지)
다운로드 완료 후에도 VIVADO 폴더가 생성되지 않았습니다.
안녕하세요 :) 알려주신 D드라이브 PATH에 다운로드 경로를 설정하여 다운로드 완료하였습니다. 후에 SOURE과정으로 넘어가려고 하니 VIVADO폴더 파일 자체가 없길래 재설치도 해보았습니다. 재설치하는 중에는 VIVADO폴더 및 다른 여러 폴더도 설치 되길래 이번에는 성공적일것이라 생각했는데 마무리 단계에서 다 삭제되는 것 같습니다. 다음과 같은 터미널창이 출력되고 다운로드가 완료되었는데 정상적인 다운로드 과정이 아닌가요?어떤 부분이 문제점일까요? 감사합니다 :)
-
해결됨자바 ORM 표준 JPA 프로그래밍 - 기본편
값타입에서 엠비디드를 사용할 때 질문
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]Address를 만들 때 값 타입은 불변으로 만들어야 해서 setter을 빼라고 말씀하셨고 생성할 때 new Address로 해서 만들던데 혹시 @builder도 사용하면 안되나요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
id 관련 질문
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요.1. 강의 내용과 관련된 질문을 남겨주세요.2. 인프런의 질문 게시판과 자주 하는 질문(링크)을 먼저 확인해주세요.(자주 하는 질문 링크: https://bit.ly/3fX6ygx)3. 질문 잘하기 메뉴얼(링크)을 먼저 읽어주세요.(질문 잘하기 메뉴얼 링크: https://bit.ly/2UfeqCG)질문 시에는 위 내용은 삭제하고 다음 내용을 남겨주세요.=========================================[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예/아니오)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예/아니오)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예/아니오)[질문 내용]여기에 질문 내용을 남겨주세요.안녕하세요.코드를 똑같이 따라 썼는데 글 수정시 submit을 누르면 글이 수정되는 것이 아니라 수정된 내용의 상품이 하나 더 등록됩니다. 그래서 상품 한개가 있을 때 그 상품을 수정하면 수정된 상품까지해서 상품이 총 두개가 됩니다. 엔티티 설계할 때 @ID의 생성전략을 GenerationType.IDENTITY로 하였는데 이게 문제가 될까요? 디버깅 해보니 상품 저장시에 ItemRepository에서 merge가 아닌 persist를 하고있습니다.
-
미해결프로그래밍 시작하기 : 파이썬 입문 (Inflearn Original)
vs code 대신 atom으로 강의되네요.
vs code 대신 atom으로 강의되네요.
-
해결됨파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트
two form on a page 관련 질문
안녕하세요!한 페이지당 2개의 form을 사용해서 페이지를 만들려고 합니다.2개의 form을 만든 사례가 구글링을 해도 많이 보이지 않아서 직접 View class를 상속받아서만 만들어봤습니다.그래서 view를 다음과 같이 만들었지만 에러가 발생되어 구글링을 하거나 print문으로 찍어봐도 어디서 해결할지를 몰라서 여쭤봅니다.Traceback (most recent call last): File "/Users/jehakim/.pyenv/versions/assignment/lib/python3.10/site-packages/django/core/handlers/exception.py", line 55, in inner response = get_response(request) File "/Users/jehakim/.pyenv/versions/assignment/lib/python3.10/site-packages/django/utils/deprecation.py", line 136, in call response = self.process_response(request, response) File "/Users/jehakim/.pyenv/versions/assignment/lib/python3.10/site-packages/django/middleware/clickjacking.py", line 34, in process_response response.headers["X-Frame-Options"] = self.get_xframe_options_value(AttributeError: 'dict' object has no attribute 'headers'위 에러는 django middleware 단에서 발생했습니다. views.py한 화면에 버튼이 2개가 있고, 이 버튼에 따라 전송되는 form이 다른 상황입니다. 이런 상황일 때 버튼을 구분하는 방법을 구글링해보니 button tag에 name 속성으로 구분하면 된다고 하여"refusal-btn" 과 "approval-btn" 으로 구분했습니다.FBV로 먼저 만든 후 코드가 너무 지저분해 보여서 CBV로 바꿨습니다.views.py from django.shortcuts import render, redirect, get_object_or_404 from django.contrib.auth.decorators import login_required from django.utils.decorators import method_decorator from django.views.generic import FormView, ListView, View from django.views.generic.base import ContextMixin from django.contrib.auth import login, logout from django.urls import reverse_lazy from django.utils import timezone from django.db.models import Q from config.settings.base import COUNTS_PER_PAGE from accounts.utils import ( authorization_filter_on_employee_list, authorization_filter_on_signup_list, ) from accounts.forms import ( ResignationForm, EmployeeForm, SignUpForm, LoginForm, UserForm, ) from accounts.models import User, Employee @method_decorator(login_required(login_url=reverse_lazy("login")), name="get") class SignupUserDetailView(View, ContextMixin): user_object = None user_form = None employee_form = None context = dict() def post(self, request, **kwargs): self.user_form = UserForm(request.POST, instance=self.user_object) if self.user_form.is_valid(): state = self.user_form.cleaned_data.get("state") self.user_object.state = state if "refusal-btn" in request.POST: reason_for_refusal = self.user_form.cleaned_data.get( "reason_for_refusal" ) rejected_at = timezone.now() self.user_object.reason_for_refusal = reason_for_refusal self.user_object.rejected_at = rejected_at self.user_object.save() else: # approval-btn 일 때 self.employee_form = EmployeeForm(request.POST) if self.employee_form.is_valid(): cleaned_data = self.employee_form.cleaned_data grade = self.employee_form.data.get("grade") authorizations = { "authorization_grade": grade, "signup_approval_authorization": cleaned_data.get( "signup_approval_authorization" ), "list_read_authorization": cleaned_data.get( "list_read_authorization" ), "update_authorization": cleaned_data.get( "update_authorization" ), "resign_authorization": cleaned_data.get( "resign_authorization" ), } employee = Employee.objects.create( user_id=self.user_object.id, **authorizations ) employee.save() self.user_object.save() return render(request, "detail.html", self.get_context_data()) return render(request, "detail.html", self.get_context_data()) def get(self, request, user_id): self.user_object = get_object_or_404(User, pk=user_id) self.user_form = UserForm(instance=self.user_object) self.employee_form = EmployeeForm() return render(request, "detail.html", self.get_context_data()) def get_context_data(self, **kwargs): self.context["user_form"] = self.user_form self.context["employee_form"] = self.employee_form self.context["signup_list"] = True return self.context제일 하단에 있는 signup_list 는 하나의 템플릿 .html을 사용하는데 두 개의 view에서 이를 공유하기 때문에 이를 구분하고자 만든 flag 변수입니다.제가 알기로는 render 함수는 HttpResponse를 반환하는데 그러면 header가 당연히 있지 않나? 라는 생각이라서 부딪혔습니다.제 생각에는 기존에 다른 View 종류들을 상속받으면 해결해주는 거를 순수히 View만 상속받아서 어느 부분을 놓친 것 같은데, 이러면 어느 클래스를 상속받으면 될지, 아니면 직접 뭔가를 해야할지 모르겠습니다.읽어주셔서 감사합니다.advice 해주시면 감사하겠습니다 ㅠㅠ
-
미해결생산성을 향상시키는 스프링부트 기반의 API 템플릿 프로젝트 구현
yml 설정에 오류가 발생합니다.
저 부분에 오류가 발생합니다.모두 똑같이 작성하고 부트 버전도 같은데어떤것 때문에 문제가 발생하는건가요?
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
post에 게시글 추가시 오류
로그인 후 post를 추가하면 아래와 같이 오류가 납니다 ㅠㅠ!화면에러내용Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading '0') Source components\PostCard.js (47:27) @ PostCard 45 | <Card 46 | // post안에 Images가 있는 경우 > 47 | cover={post.Images[0] && <PostImages images={post.Images} />} | ^ 48 | actions={[ 49 | <RetweetOutlined key="retweet" />, 50 | liked ? (콘솔 추가 에러내용react-dom.development.js:19527 The above error occurred in the <PostCard> component: in PostCard (at pages/index.js:24) in div (created by Context.Consumer) in Col (at AppLayout.js:57) in div (created by Context.Consumer) in Row (at AppLayout.js:53) in div (at AppLayout.js:35) in AppLayout (at pages/index.js:21) in Home (at _app.js:13) in NodeBird (created by withRedux(NodeBird)) in Provider (created by withRedux(NodeBird)) in withRedux(NodeBird) in ErrorBoundary (created by ReactDevOverlay) in ReactDevOverlay (created by Container) in Container (created by AppContainer) in AppContainer in Root page/index.jsimport { all, fork } from "redux-saga/effects"; import postSaga from "./post"; import userSaga from "./user"; export default function* rootSaga() { yield all([fork(postSaga), fork(userSaga)]); } reducer/post.jsimport shortId from "shortid"; import produce from "immer"; import immer from "immer"; export const initailState = { mainPosts: [ { id: 1, User: { id: 1, nickname: "행복", }, content: "첫 번째 게시글 #해시태그 #해시태그2", Images: [ { src: "https://bookthumb-phinf.pstatic.net/cover/137/995/13799585.jpg?udate=20180726", }, { src: "https://gimg.gilbut.co.kr/book/BN001958/rn_view_BN001958.jpg", }, { src: "https://gimg.gilbut.co.kr/book/BN001998/rn_view_BN001998.jpg", }, ], Comments: [ { User: { nickname: "nero", }, content: "우와 개정판이 나왔군요~", }, { User: { nickname: "hero", }, content: "얼른 사고싶어요~", }, ], }, ], imagePaths: [], addPostLoading: false, addPostDone: false, addPostError: null, removePostLoading: false, removePostDone: false, removePostError: null, addCommentLoading: false, addCommentDone: false, addCommentError: null, }; export const ADD_POST_REQUEST = "ADD_POST_REQUEST"; export const ADD_POST_SUCCESS = "ADD_POST_SUCCESS"; export const ADD_POST_FAILURE = "ADD_POST_FAILURE"; export const REMOVE_POST_REQUEST = "REMOVE_POST_REQUEST"; export const REMOVE_POST_SUCCESS = "REMOVE_POST_SUCCESS"; export const REMOVE_POST_FAILURE = "REMOVE_POST_FAILURE"; export const ADD_COMMENT_REQUEST = "ADD_COMMENT_REQUEST"; export const ADD_COMMENT_SUCCESS = "ADD_COMMENT_SUCCESS"; export const ADD_COMMENT_FAILURE = "ADD_COMMENT_FAILURE"; export const addPost = (data) => { return { type: ADD_POST_REQUEST, data, }; }; export const addComment = (data) => { return { type: ADD_COMMENT_REQUEST, data, }; }; const dummyPost = (data) => ({ id: data.id, content: data.content, User: { id: 1, nickname: "행복", }, }); const dummyComment = (data) => ({ id: shortId.generate(), content: data, User: { id: 1, nickname: "행복", }, Images: [], Comments: [], }); const reducer = (state = initailState, action) => { return produce(state, (draft) => { switch (action.type) { case ADD_POST_REQUEST: draft.addPostLoading = true; draft.addPostDone = false; draft.addPostError = null; break; case ADD_POST_SUCCESS: draft.mainPosts.unshift(dummyPost(action.data)); draft.addPostLoading = false; draft.addPostDone = true; break; case ADD_POST_FAILURE: draft.addPostLoading = false; draft.addPostError = action.error; break; case REMOVE_POST_REQUEST: draft.removePostLoading = true; draft.removePostDone = false; draft.removePostError = null; draft.mainPosts = state.main; break; case REMOVE_POST_SUCCESS: // draft.mainPosts = state.mainPosts.filter((v) => v.id !== action.data); draft.mainPosts = draft.mainPosts.filter((v) => v.id !== action.data); draft.removePostLoading = false; draft.removePostDone = true; break; case REMOVE_POST_FAILURE: draft.removePostLoading = false; draft.removePostError = action.error; break; case ADD_COMMENT_REQUEST: draft.addCommentLoading = true; draft.addCommentDone = false; draft.addCommentError = null; break; case ADD_COMMENT_SUCCESS: { // 게시글을 찾음 const post = draft.mainPosts.find((v) => v.id === action.data.postId); // 그 게시글 댓글에다가 새로운 댓글 추가 post.Comments.unshift(dummyComment(action.data.content)); draft.addCommentLoading = false; draft.addCommentDone = true; break; // const postIndex = state.mainPosts.findIndex( // (v) => v.id === action.data.postId // ); // const post = { ...state.mainPosts[postIndex] }; // post.Comments = [dummyComment(action.data.content), ...post.Comments]; // Comments 얕은 복사 후 dummyComment 추가 // const mainPosts = [...state.mainPosts]; // mainPosts 새로운객체 생성 // mainPosts[postIndex] = post; // return { // ...state, // mainPosts, // addCommentLoading: false, // addCommentDone: true, // }; } case ADD_COMMENT_FAILURE: draft.addCommentLoading = false; draft.addCommentError = action.error; break; default: break; } }); }; export default reducer; //기본 구조 // const initailState = {}; // const reducer = (state = initailState, action) => { // switch (action.type) { // default: // return state; // } // }; // export default reducer; // 데이터를 구성하고 그에따라 액션구성후 reducer작성 그 후 화면 구성 sagas/post.jsimport { all, fork, delay, put, takeLatest } from "redux-saga/effects"; // import axios from "axios"; import { ADD_POST_REQUEST, ADD_POST_SUCCESS, ADD_POST_FAILURE, ADD_COMMENT_REQUEST, ADD_COMMENT_SUCCESS, ADD_COMMENT_FAILURE, REMOVE_POST_REQUEST, REMOVE_POST_SUCCESS, REMOVE_POST_FAILURE, } from "../reducers/post"; import { REMOVE_POST_OF_ME } from "../reducers/user"; import { ADD_POST_TO_ME } from "../reducers/user"; import shortId from "shortid"; function addPostAPI(data) { return axios.post("/api/post", data); // 서버에 요청 } function* addPost(action) { try { // const result = yield call(addPostAPI, action.data); yield delay(1000); const id = shortId.generate(); yield put({ type: ADD_POST_SUCCESS, data: { id, content: action.data, }, }); yield put({ type: ADD_POST_TO_ME, data: id, }); } catch (err) { yield put({ type: ADD_POST_FAILURE, error: err.response.data, }); } } function removePostAPI(data) { return axios.delete("/api/post", data); // 서버에 요청 } function* removePost(action) { try { yield delay(1000); yield put({ type: REMOVE_POST_SUCCESS, data: action.data, }); yield put({ type: REMOVE_POST_OF_ME, data: action.data, }); } catch (err) { yield put({ type: REMOVE_POST_FAILURE, error: err.response.data, }); } } function addcommentAPI(data) { return axios.post(`/api/post/${data.postId}/comment`, data); // 서버에 요청 } function* addComment(action) { try { // const result = yield call(addCommentAPI, action.data); yield delay(1000); yield put({ type: ADD_COMMENT_SUCCESS, data: action.data, }); } catch (err) { yield put({ type: ADD_COMMENT_FAILURE, error: err.response.data, }); } } function* watchAddPost() { yield takeLatest(ADD_POST_REQUEST, addPost); } function* watchRemovePost() { yield takeLatest(REMOVE_POST_REQUEST, removePost); } function* watchAddComment() { yield takeLatest(ADD_COMMENT_REQUEST, addComment); } export default function* postSaga() { yield all([fork(watchAddPost), fork(watchRemovePost), fork(watchAddComment)]); } components/PosdCard.jsimport React, { useState, useCallback } from "react"; import { Card, Popover, Button, Avatar, Comment, List } from "antd"; import PropTypes from "prop-types"; import CommentForm from "./CommentForm"; import { RetweetOutlined, HeartOutlined, MessageOutlined, EllipsisOutlined, HeartTwoTone, } from "@ant-design/icons"; import { useDispatch, useSelector } from "react-redux"; import PostImages from "./PostImages"; import PostCardContent from "./PostCardContent"; import { REMOVE_POST_REQUEST } from "../reducers/post"; const PostCard = ({ post }) => { const dispatch = useDispatch(); const { removePostLoading } = useSelector((state) => state.post); const [liked, setLiked] = useState(false); const [commentFormOpened, setCommentFormOpened] = useState(false); const onToggleLike = useCallback(() => { setLiked((prev) => !prev); }, []); const onToggleComment = useCallback(() => { setCommentFormOpened((prev) => !prev); }, []); const id = useSelector((state) => state.user.me?.id); // = const id = useSelector((state) => state.user.me && state.user.me.id); //const { me } = useSelector((state) => state.user); //const id = me?.id; // 로그인을 한 상태이고 아이디가 있으면 으로 해석해서 설계해보자 // const id = me && me.id; const onRemovePost = useCallback(() => { dispatch({ type: REMOVE_POST_REQUEST, data: post.id, }); }, []); return ( <div style={{ marginBottom: 20 }}> <Card // post안에 Images가 있는 경우 cover={post.Images[0] && <PostImages images={post.Images} />} actions={[ <RetweetOutlined key="retweet" />, liked ? ( <HeartTwoTone twoToneColor="#eb2f96" key="heart" onClick={onToggleLike} /> ) : ( <HeartOutlined key="heart" onClick={onToggleLike} /> ), <MessageOutlined key="comment" onClick={onToggleComment} />, <Popover key="more" content={ <Button.Group> {/* 내아이디랑 게시글작성아디가 나랑 같으면 */} {id && post.User.id === id ? ( <> <Button>수정</Button> <Button type="danger" onClick={onRemovePost} loading={removePostLoading} > 삭제 </Button> </> ) : ( <Button>신고</Button> )} </Button.Group> } > <EllipsisOutlined /> </Popover>, ]} > <Card.Meta avatar={<Avatar>{post.User.nickname[0]}</Avatar>} title={post.User.nickname} description={<PostCardContent postData={post.content} />} /> </Card> {commentFormOpened && ( <div> {/* post를 넘겨주는 이유는? 어떤 게시글에 댓글을 달건지 게시글의 id가 필요하기 때문에 */} <CommentForm post={post} /> <List header={`${post.Comments.length}개의 댓글`} itemLayout="horizontal" dataSource={post.Comments} //post.Comments가 각각 item으로 들어감 renderItem={(item) => ( <li> <Comment author={item.User.nickname} avatar={<Avatar>{item.User.nickname[0]}</Avatar>} content={item.content} /> </li> )} /> </div> )} </div> ); }; PostCard.propTypes = { post: PropTypes.shape({ id: PropTypes.number, User: PropTypes.object, content: PropTypes.string, createdAt: PropTypes.object, Comments: PropTypes.arrayOf(PropTypes.object), Images: PropTypes.arrayOf(PropTypes.object), }).isRequired, }; export default PostCard; componets/PostForm.jsimport React, { useCallback, useRef, useEffect } from "react"; import { Form, Input, Button } from "antd"; import { useDispatch, useSelector } from "react-redux"; import { addPost } from "../reducers/post"; import useInput from "../hooks/useInput"; const PostForm = () => { const { imagePaths, addPostDone } = useSelector((state) => state.post); const dispath = useDispatch(); const [text, onChangeText, setText] = useInput(""); useEffect(() => { if (addPostDone) { setText(""); } }, [addPostDone]); const onSubmit = useCallback(() => { dispath(addPost(text)); }, [text]); const imageInput = useRef(); const onClickImageUpload = useCallback(() => { imageInput.current.click(); }, [imageInput.current]); return ( <Form onFinish={onSubmit} style={{ margin: "10px 0 20px" }} encType="multipart/form-data" > <Input.TextArea value={text} onChange={onChangeText} maxLength={140} placeholder="어떤 신기한 일이?" /> <div> <input type="file" multiple hidden ref={imageInput} /> <Button onClick={onClickImageUpload}>이미지 업로드</Button> <Button type="primary" style={{ float: "right" }} htmlType="submit"> 등록 </Button> </div> <div> {imagePaths.map((v) => ( <div key={v} style={{ display: "inline-block" }}> <img src={v} style={{ width: "200px" }} alt={v} /> <div> <Button>제거</Button> </div> </div> ))} </div> </Form> ); }; export default PostForm;
-
미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지
POST처리후 페이지 이동
강의에서 설명하신 코드로 이것저것 해보다가 궁금한점이 생겼습니다!form태그에 사용자명 입력후 submit하면, POST요청이기 때문에 위의 코드가 실행되는데, 모든 작업처리 후에 어째서 다시 'localhost:8080/' 의 경로로 이동한 것인지 궁금합니다!!! 위처럼 작성하신 restFront.js 파일에도 따로 이동명령을 내린 것이 없는데, 어디서 설정할 수 있는 건가요?? POST요청 처리 후에 다른 경로로 이동하려면 어떻게 해야하는 것인지 알려주시면 감사하겠습니다!!
-
해결됨Data Engineering Course (1) : 빅데이터 하둡 직접 설치하기
노트북 램이 8GB 인데 괜찮나요?
서버를 계속 켜두고 싶어서 사용하지 않는 노트북에 2gb ubuntu desktop을 설치했는데, 강의를 진행하는데 문제 없을까요? 해당 노트북은 다른 용도로는 전혀 사용하지 않고, 강의내용은 다른 pc에서 Xshell과 크롬 데스크톱 화면 공유를 활용하면서 실행하려고 해요.
-
미해결공공데이터로 파이썬 데이터 분석 시작하기
강의
코렙에서 해도 괜찮나요?
-
미해결자바와 스프링 부트로 생애 최초 서버 만들기, 누구나 쉽게 개발부터 배포까지! [서버 개발 올인원 패키지]
findByname 질문있습니다
인터페이스에 findByName(String name) 메소드를 선언만하고 구현체에 무슨 역할을 하는지 상세한 메소드를 오버라이딩 하지 않았는데 쓸 수 있는 이유가 뭔가요?아 강의를 더 들으니 설명을해주시네요 ㅎㅎ..그리고 제가 자바에 아직 잘 모르기 때문일까요? 자바 문법을 처음 공부하고 현재 이 강의를 듣고 있는데 위와 같은 질문들을 잘 모르겠다면 자바를 더 공부해야 하는걸까요?자바 문법만 공부했고 자바에 익숙해지려는 연습으로 자바 코딩테스트를 해보면 자바에 더 익숙해질까요? 아니면 다른 추천 해주실 만한 공부가 있을까요?
-
미해결실전! 스프링 부트와 JPA 활용1 - 웹 애플리케이션 개발
ddl-auto: create
강의에서spring.jpa.hibernate.ddl-auto: create 이 옵션은 애플리케이션 실행 시점에 테이블을 drop 하고, 다시 생성한다. 라고 되있는데테스트에서는 @Transaction에 의해 자동으로 메소드가 끝나면 rollback되니까 영향을 끼치지 못한다. 라고 이해하면 될까요??정리하면rollback이 테이블자체를 삭제하는 것은 아니니까 ddl-auto: create와 다르지만 결과에는 영향을 끼치지 않는다. 라고 이해하면 될까요?답변주시면 정말 감사하겠습니다.
-
해결됨[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문
강의 11:48 질문
강의 11:48에서 설명하신 내용에 관한 질문입니다.Knight(const Knight& knight) : Player(knight), _pet(knight._pet)Knight클래스의 복사 생성자를 정의하시면서 부모 클래스와 멤버 클래스의 기본 생성자가 아닌 복사 생성자를 호출하기 위해 초기화 리스트에 작성한 내용입니다. 여기서 Player(knight)가 성립하는 이유는Player(const Player& player) 복사 생성자: 자식->부모는 참조형에 대한 암시적 형 변환이 지원되기 때문에 가능한건가요?
-
미해결자바 ORM 표준 JPA 프로그래밍 - 기본편
엔티티매니저의 flush(), clear() 호출 빈도가 궁금합니다.
[질문 템플릿]1. 강의 내용과 관련된 질문인가요? (예)2. 인프런의 질문 게시판과 자주 하는 질문에 없는 내용인가요? (예)3. 질문 잘하기 메뉴얼을 읽어보셨나요? (예)[질문 내용]>> 개발환경hibernate-core:5.6.15.Final자바 17>> 질문안녕하세요. Team team = new Team(); team.setName("teamA"); manager.persist(team); Member member1 = new Member(); member1.setName("hello1"); member1.setTeam(team); manager.persist(member1); manager.flush(); manager.clear(); Member m = manager.find(Member.class, member1.getId()); System.out.println("m = " + m.getTeam().getClass()); // Proxy System.out.println("=============="); m.getTeam().getName(); System.out.println("=============="); System.out.println("m = " + m.getTeam().getName());프록시 설명해주실 때 엔티티 매니저의 flush(), clear()를 호출해서 1차 캐시를 비웁니다. 실무에서 이렇게 코드 중간에 1차 캐시를 비우는 일이 잦은가요? 프록시 객체의 존재를 확인시켜주기 위해서 호출하신 건지, 실제로 실무에서 프록시 객체를 사용하기 위해(?) 중간에 flush(), clear()을 사용하는 일이 있는지 궁금합니다 1차 캐시를 강제로 비우지 않는 한은 Query 문 나갈 일 없이 영속성 컨텍스트에서 데이터를 가져오는 일이 대부분일 것 같아서요! 복잡한 쿼리를 JPQL로 작성할 때는 Lazy loading을 적용하고 필요한 객체들이 그때그때 프록시를 통해 초기화되는 일이 자주 있겠지만, 강제로 1차 캐시를 비우는 일은 거의 없지 않나 하는 생각이 들어 질문드립니다.감사합니다.