묻고 답해요
160만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
- 
      
        
    미해결카카오,구글 SNS 로그인(springboot3, vue3)카카오 인가코드 요청카카오 인가 코드 요청 url이 변경 된 것 같습니다! 
- 
      
        
    해결됨카카오,구글 SNS 로그인(springboot3, vue3)구글 로그인 프론트 화면안녕하세요 구글 로그인 구현 중 질문있어서 질문드립니다! googleUrl, googleClientId, googleRedirectUrl, googleScope, googleResponseType 을 const auth_url = `${this.googleUrl}?client_id=${this.googleClientId}&redirect_url=${this.googleRedirectUrl}&response_type=code&scope=${this.googlescope}`; window.location.href = auth_url; 구글로그인 화면을 누르면 리다이렉트 url에 오류가 있다고 하는데 동일한 리다이렉트 url로 해도 잘 안됩니다 이럴 경우 또 어떤 것을 확인해보는게 좋을까요?? 
- 
      
        
    미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지12.7 socket.js코드 그대로 뱃겨서 했는데, socket.request.session.color가안나오네요socket.request.session은 서버쪽으로 잘 전달되는데, socket.request.session.color가 전달이안되네요 cors에러도 잡았는데 그래도 안잡히네요 
- 
      
        
    미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지12.7 코드 그대로 뱃겨서 햇는데 스샷같이 오류가뜹니다.완전히 똑같이 복붙하고 실행했는데 계속 이메시지가 프론트엔트에 뜨네요 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버소셜 로그인 질문 있습니다social 유저는 기존 회원보다 위험한 유저이므로 회원 정보 수정 페이지로 이동시켜야 한다 라고 하셨는데 이유가 뭔가요?? 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버JWT 설정 후 JSON 데이터가 문자열로 옵니다...📤 before requestjwtUtil.ts:30 ✅ Response ReceivedjwtUtil.ts:34 📦 Content-Type: application/jsonjwtUtil.ts:35 🧾 typeof res.data: stringcontent-type은 json 형식으로 맞춰 주었는데 정작 데이터가 String으로 와서 list에 뿌려주지를 못하고 있습니다.Postman으로 확인했을 때는 정상적으로 JSON 데이터를 반환받는데 리액트에서 확인할려면 res.data가 "{\"dtoList\":[{\"tno\":115,\"title\":\"123zzzㅋㅋㅋㅋ\",\"content\":null,\"complete\":false,\"dueDate\":\"2025-08-07\",\"writer\":\"123\"}위와 같이 스트링 형식으로 변환되어서 들어와서 오류가 생깁니다.어디가 문제일까요..ㅠㅠ 
- 
      
        
    미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지12.7.1스스로 해보기 질문되나요//채팅창에 현재 참여자 수나 목록표시하기구현한chat.html코드와 socket.j코드입니다. 그런데 chat: ${socket.request.session.color} 이부분이 undefined으로 계속 나옵니다. console.log에 찍어보면 socket.request.session에 color만 빼고 나오네요.{% extends 'layout.html' %} {% block content %} <h1>{{title}}</h1> <a href="/" id="exit-btn">방 나가기</a> <fieldset> <legend>채팅 내용</legend> <div style="display: flex; gap: 20px;"> <!-- 채팅 목록 --> <div id="chat-list" style="flex: 3;"> {% for chat in chats %} {% if chat.user === user %} <div class="mine" style="color: {{chat.user}}"> <div>{{chat.user}}</div> {% if chat.gif %} <img src="/gif/{{chat.gif}}"> {% else %} <div>{{chat.chat}}</div> {% endif %} </div> {% elif chat.user === 'system' %} <div class="system"> <div>{{chat.chat}}</div> </div> {% else %} <div class="other" style="color: {{chat.user}}"> <div>{{chat.user}}</div> {% if chat.gif %} <img src="/gif/{{chat.gif}}"> {% else %} <div>{{chat.chat}}</div> {% endif %} </div> {% endif %} {% endfor %} </div> <!-- 참여자 목록 --> <div style="flex: 1;"> <h3>참여자</h3> <ul id="user-list"></ul> </div> </div> </fieldset> <form action="/chat" id="chat-form" method="post" enctype="multipart/form-data"> <label for="gif">GIF 올리기</label> <input type="file" id="gif" name="gif" accept="image/gif"> <input type="text" id="chat" name="chat"> <button type="submit">전송</button> </form> <script src="https://unpkg.com/axios/dist/axios.min.js"></script> <script src="/socket.io/socket.io.js"></script> <script> const socket = io.connect('http://localhost:8005/chat', { path: '/socket.io', transports: ['websocket'] }); socket.emit('join', new URL(location).pathname.split('/').at(-1)); socket.on('join', function (data) { const div = document.createElement('div'); div.classList.add('system'); const chat = document.createElement('div'); chat.textContent = data.chat; div.appendChild(chat); document.querySelector('#chat-list').appendChild(div); if (data.userList) { const ul = document.querySelector('#user-list'); // 참여자 목록이 들어갈 ul ul.innerHTML = ''; // 기존 목록 초기화 data.userList.forEach(function (user) { const li = document.createElement('li'); li.textContent = user; ul.appendChild(li); }); } }); socket.on('exit', function (data) { const div = document.createElement('div'); div.classList.add('system'); const chat = document.createElement('div'); chat.textContent = data.chat; div.appendChild(chat); document.querySelector('#chat-list').appendChild(div); }); socket.on('chat', function (data) { const div = document.createElement('div'); if (data.user === '{{user}}') { div.classList.add('mine'); } else { div.classList.add('other'); } const name = document.createElement('div'); name.textContent = data.user; div.appendChild(name); if (data.chat) { const chat = document.createElement('div'); chat.textContent = data.chat; div.appendChild(chat); } else { const gif = document.createElement('img'); gif.src = '/gif/' + data.gif; div.appendChild(gif); } div.style.color = data.user; document.querySelector('#chat-list').appendChild(div); }); document.querySelector('#chat-form').addEventListener('submit', function (e) { e.preventDefault(); if (e.target.chat.value) { axios.post('/room/{{room._id}}/chat', { chat: this.chat.value, }) .then(() => { e.target.chat.value = ''; }) .catch((err) => { console.error(err); }); } }); document.querySelector('#gif').addEventListener('change', function (e) { console.log(e.target.files); const formData = new FormData(); formData.append('gif', e.target.files[0]); axios.post('/room/{{room._id}}/gif', formData) .then(() => { e.target.file = null; }) .catch((err) => { console.error(err); }); }); </script> {% endblock %} const SocketIO = require('socket.io');const { removeRoom } = require('./services'); module.exports = (server, app, sessionMiddleware) => { const io = SocketIO(server, { path: '/socket.io',transports: ['websocket'] }); app.set('io', io); const room = io.of('/room'); const chat = io.of('/chat'); const wrap = middleware => (socket, next) => middleware(socket.request, {}, next); chat.use(wrap(sessionMiddleware)); room.on('connection', (socket) => { console.log('room 네임스페이스에 접속'); socket.on('disconnect', () => { console.log('room 네임스페이스 접속 해제'); }); }); chat.on('connection', (socket) => { console.log('chat 네임스페이스에 접속'); console.log(socket.request.session); socket.on('join', (roomId) => { socket.join(roomId); const room = socket.adapter.rooms.get(roomId); // Set const userList = room ? Array.from(room) : []; // 시스템 메시지 + 사용자 목록 전송 socket.to(roomId).emit('join', { user: 'system', chat: `${socket.request.session.color}님이 입장하셨습니다.`, userList, }); }); socket.on('disconnect', async () => { console.log('chat 네임스페이스 접속 해제'); const { referer } = socket.request.headers; // 브라우저 주소가 들어있음 const roomId = new URL(referer).pathname.split('/').at(-1); const currentRoom = chat.adapter.rooms.get(roomId); const userCount = currentRoom?.size || 0; if (userCount === 0) { // 유저가 0명이면 방 삭제 await removeRoom(roomId); // 컨트롤러 대신 서비스를 사용 room.emit('removeRoom', roomId); console.log('방 제거 요청 성공'); } else { socket.to(roomId).emit('exit', { user: 'system', chat: `${socket.request.session.color}님이 퇴장하셨습니다.`, }); } }); });} 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버loginSlice에서 reject가 반환되지 않습니다.로그인시에 잘못된 아이디 비밀번호를 넣게 되면 콘솔 로그 창에 reject가 반환되어야 하는데 전부 fulfilled로 반환됩니다. 혹시 코드 필요하시면 첨부하도록 하겠습니다. 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버강사님 질문 있습니다.이미지를 저장할 때 이미지 파일을 저장할 때가 있고 이미지 이름을 저장할 때가 있다고 하셨는데그러면 이미지를 파일 시스템이나 DB상에 저장을 하므로 그 파일에 접근하기 위해서 DB상에 이미지 이름을 저장한다고 생각하면 될까요?제가 생각한게 맞는지 궁금합니다. 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버delete에 대한 테스트를 진행하지 않는 이유가 뭔가요??테스트 코드 상에 있는 테스트 데이터를 지우는 것이므로 딱히 별 영향이 없지 않나요? 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버17강 강의중 문의드립니다.안녕하세요 강의 실습중 문의드립니다. 강의랑 똑같이 하던중에 저에게만 에러가 나는부분이 있어 문의드립니다.@Override public Long register(TodoDTO todoDTO) { Todo todo = dtoToEntity(todoDTO);dtoToEntity에서 에러가 발생합니다.Cannot invoke "java.lang.Long.longValue()" because the return value of "com.project.reactserver.dto.TodoDTO.getTno()" is null에러가 발생하는데 당연히 tno값을 안넣었으니 null인데 강사님 강의에서는 잘 진행이 되는데뭐가 문제인지.. 물론 TodoDTO에는 @Data 어노테이션도 작성했고 Setting에서 어노테이션 활성도 확인했습니다. 
- 
      
        
    미해결지금 당장 NodeJS 백엔드 개발 [사주 만세력]깃허브 소스는 어떻게 받을 수 있나요?깃허브 소스는 어떻게 받을 수 있을까요? 
- 
      
        
    해결됨[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지시퀄라이즈 실습하기 질문드립니다.실습 중에 댓글 작성하려고 하는데 오류가 발생해서 오류 로그를 보다가 sqlMessage 로 "Unknown column 'commenter' in 'field list'", 라는 문구를 봤습니다. 따로 commenter 라는 필드를 만드신건 못본거같은데 제가 강의를 흘려 들은건지 잘 모르겠습니다. 근데 이상한건, 맨 처음에 실행하고 댓글을 작성할땐 댓글이 작성이 되고, MySQL 에 들어가서 comment 테이블을 확인해보면 댓글이 들어가긴 했습니다.근데 두번째 댓글 작성시도부터 오류가 발생했습니다. 
- 
      
        
    미해결[개정3판] Node.js 교과서 - 기본부터 프로젝트 실습까지<7-5. 시퀄라이즈 사용하기>수업 질문 드립니다.안녕하세요. 수업 중 막히는 것이 있어서 질문 글 올립니다.수업을 다 따라가고 연결테스트를 하려고 했는데,이렇게 에러가 생겼습니다.분명히 config폴더가 있고 그안에 config.json 파일이 존재하는데 없다고 하길래, 일단 npx sequelize init 을 했더니 이번에는 config 파일이 이미 존재한다는 소리를 하길래 --force 를 하긴했습니다.그런 다음에 다시 실행하니까,이렇게 오류메시지가 생겼어요.강의에는 models 폴더에 user라는 파일을 만들라는 건 듣도보도 못했는데, 뭐가 잘못된건지 잘 모르겠습니다. 
- 
      
        
    미해결스프링부트 시큐리티 & JWT 강의JWT를 구현한 다음 이 API를 호출해서 사용하는 것은 프론트엔드 쪽에서 하는 역할인가요?안녕하세요. 현재 강의를 통해 JWT를 구현하여 전체적인 개념을 익힌 백엔드 개발 취준생입니다. 배운것을 저의 웹 프로젝트에 적용하려고 했지만 이 api를 호출해서 하는 것은 자바스크립트를 사용해서 하는 것이 있길래 백엔드 개발자라면 어디까지 구현해야할지가 참 어려운 것 같습니다. RestController로 API 개발까지는 수업을 통해 구현할 수 있지만 나머지를 웹에 적용하는 것은 어려운 것 같습니다. 
- 
      
        
    미해결따라하며 배우는 NestJS파일을 찾지 못하는 오류가 계속 뜹니다Cannot find module './app.controller' or its corresponding type declarations.Cannot find module './app.service' or its corresponding type declarations.저런 내용이 아예 없는데 코드에서 저게 잘못됐다고 뜨네요....파일구조도 다 맞는것 같은데왜 계속 저런 오류가 뜨는걸까요ㅜㅜ 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버로그인 관련 커스텀 훅 만들기 -> 부분 질문입니다.현재 loginSlice.tsx에서 오류가 나고 있습니다..아래와 같은 메세지를 접했습니다.useCustomLogin.tsx:2 Uncaught SyntaxError: The requested module '/src/store.tsx' does not provide an export named 'AppDispatch' (at useCustomLogin.tsx:2:10) 어느부분을 손 봐야할까요?vite 6.3버전으로 이용하고 있습니다. loginSlice.tsximport { createAsyncThunk, createSlice } from "@reduxjs/toolkit" import { loginPost } from "../api/memberApi" import { removeCookie, setCookie } from "../util/cookieUtil" export interface LoginInfo { email:string, nickname:string, accessToken: string, refreshToken: string, roleNames: string[], status: string } const initState:LoginInfo = { email: '', nickname: '', accessToken:'', refreshToken: '', roleNames: [], status: '' } export const loginPostAsync = createAsyncThunk('loginPostAsync', ({email, pw}: {email:string, pw:string}) => { console.log("---------------loginPostAsync---------------------") console.log(email, pw) return loginPost(email, pw) }) const loginSlice = createSlice({ name: 'loginSlice', initialState: initState, reducers: { save: (state, action) => { console.log("save...........") return action.payload }, logout: (state, action) => { console.log("logout..........") removeCookie("member") } }, extraReducers :(builder) => { builder.addCase(loginPostAsync.fulfilled , (state, action) => { console.log("loginPostAsync.fulfilled") const newState:LoginInfo = action.payload newState.status = 'fulfilled' setCookie("member", JSON.stringify(newState), 1) return newState }) .addCase(loginPostAsync.pending, (state, action) => { console.log("loginPostAsync.pending") state.status = 'pending' }) .addCase(loginPostAsync.rejected, (state, action) => { console.log("loginPostAsync.rejected") state.status = 'rejected' }) } }) export const { save, logout} = loginSlice.actions export default loginSlice.reducer useCustoLogin.tsximport { useDispatch, useSelector } from "react-redux" import { AppDispatch, RootState } from "../store" import { Navigate, useNavigate } from "react-router" import { loginPostAsync, logout, save } from "../slices/loginSlice" import { useEffect } from "react" import { getCookie } from "../util/cookieUtil" const useCustomLogin = () => { const dispatch = useDispatch<AppDispatch>() //로그인 상태 객체 const loginState = useSelector((state: RootState) => state.loginSlice) //로그인 여부 const loginStatus = loginState.status //fulfilled, pending, rejected useEffect(()=> { if(! loginStatus ) { const cookieData = getCookie("member") if(cookieData){ dispatch(save(cookieData)) } } }, []) const navigate = useNavigate() const doLogin = async (email:string, pw:string) => { dispatch(loginPostAsync({ email, pw })) } const doLogout = () => { dispatch(logout(null)) } const moveToLogin = () => { navigate("/member/login") } const moveToLoginReturn = () => { //--------로그인 페이지로 이동 컴포넌트 return <Navigate replace to="/member/login"/> } const moveToPath = (path:string) => { //----------------페이지 이동 navigate({pathname: path}, {replace:true}) } return {loginState, loginStatus, doLogin, doLogout,moveToLogin,moveToLoginReturn,moveToPath} } export default useCustomLogin store.tsximport { configureStore } from "@reduxjs/toolkit"; import loginSlice from "./slices/loginSlice"; const store = configureStore({ reducer: { "loginSlice": loginSlice, } }) export type AppDispatch = typeof store.dispatch export type RootState = ReturnType<typeof store.getState> export default store 
- 
      
        
    미해결카카오,구글 SNS 로그인(springboot3, vue3)github 주소 어디서 확인가능한가요?소스코드 올라온 github 주소 어디서 확인이 가능할까요? 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버mallapimallapi에서 malldb를 연결 했고,apiserver에서 apidb를 연결했습니다.4강 조회기능에서test를 위해 malldb에 테이블 확인을 하시는데 왜 갑자기 테이블이 생긴걸까요?저희는 mallapi는 연결만 하고 구현은 안된거 아닌가요?apiserver에서 구현한 todo는 apidb 안에서 생성되는 걸로 구현이 되어있는데뭘 잘못 한건가요? 
- 
      
        
    미해결코드로 배우는 React 19 with 스프링부트 API서버수업에사용되는 ppt강의중에서 설명하시는 ppt는 어디서 확인할 수 있을까요? 
