자바풀스택 과정/자바 풀 스택 : 수업내용정리

자바 풀 스택 3/14 오후 기록 074-2

파티피플지선 2025. 3. 14. 17:43

<14:30 5교시>

 

drag & drop하는 기능을 새롭게 배울 것이다.

1. 드롭존 만들기

 

이 드롭존에 파일이 들어오면 dragover event가 발생하고, 마우스를 때면 drop event가 발생하게 된다.

근데 웹브라우저의 기본 드래그드롭 이벤트 처리는 새탭에서 해당 파일을 여는 것으로 실행된다.

그래서 우리는 이 디폴트 동작부터 막고 시작해야 한다.

 

 

얻어낸 files는 배열을 담고 있지만 배열로서 참조할 수는 없다. 그래서 map 함수를 쓰거나 할 수 없다.

그래서 file 안에 있는 아이템을 펼쳐놓은 실제 배열을 만든 다음 해당 배열에서 이미지 파일만 골라 놓은 새로운 배열을 만들어야 한다.  는 여러개의 이미지를 다룰려고 해서 이렇게 했엇는데 이건 나중에 gallery 만들때 하자신다.

 

 

 

 

이미지 파일만 드롭할 수 있게 해주기.

 

 

 

 

상태값 관리하기

<15:30 6교시>

이미지가 없을 때는 drag&drop 하기 전에 기본 이미지로 svg를 디코딩한 것을 띄워준다.

 

 

 

쌤이 보내준 코드

더보기
// src/pages/UserUpdateForm.jsx

import axios from 'axios';
import React, { useEffect, useRef, useState } from 'react';
import { Button, Form } from 'react-bootstrap';

function UserUpdateForm(props) {
    const [user, setUser]=useState({});
    const [imageSrc, setImageSrc]=useState(null);

    useEffect(()=>{
        axios.get("/user")
        .then(res=>{
            setUser(res.data);
            //만일 등록된 프로필 이미지가 있다면
            if(res.data.profileImage){
                setImageSrc(`/upload/${res.data.profileImage}`);
            }else{//없으면 기본 svg 이미지 출력 
                // person svg 이미지를 읽어들여서 data url 로 만든다음 imageSrc 에 반영하기 
                // svg 이미지를 2 진 데이터 문자열로 읽어들여서 
                const svgString=new XMLSerializer().serializeToString(personSvg.current)
                // 2진데이터 문자열을 btoa (binary to ascii) 함수를 이용해서 ascii 코드로 변경
                const encodedData = btoa(svgString)
                // 변경된 ascii 코드를 이용해서 dataUrl 을 구성한다 
                const dataUrl = "data:image/svg+xml;base64," + encodedData;
                setImageSrc(dataUrl);
            }
        })
        .catch(error=>{

        });
    }, []);
    // dropZone 의 스타일 
    const dropZoneStyle={
        minHeight:"300px",
        border:"3px solid #cecece",
        borderRadius:"10px",
        display:"flex",
        justifyContent:"center",
        alignItems:"center",
        cursor:"pointer"
    }
    const profileStyle={
        width: "200px",
        height: "200px",
        border: "1px solid #cecece",
        borderRadius: "50%"
    }
    //사각형 영역에 파일이 drop 되었을때 호출되는 함수 
    const handleDrop = (e)=>{
        e.preventDefault(); //웹브라우저의 기본 동작 막기
        //drop 된 파일 객체 얻어내기
        const file=e.dataTransfer.files[0];
        //파일의 type을 조사해서 이미지가 아니면 함수를 종료한다.
        const reg=/image/;
        if(!reg.test(file.type)){
            alert("이미지 파일을 drop 하세요");
            return ;
        }
        //파일로 부터 데이터를 읽어들일 객체 생성
        const reader=new FileReader()
        //파일을 DataURL 형식의 문자열로 읽어들이기
        reader.readAsDataURL(file)
        //로딩이 완료(파일데이터를 모드 읽었을때) 되었을때 실행할 함수 등록
        reader.onload=(event)=>{
            //읽은 파일 데이터 얻어내기 
            const data=event.target.result;
            //읽은 data url 을 상태값에 넣어주기 
            setImageSrc(data);
        }
        // input type="file" 요소에 drop 된 파일의 정보 넣어주기 (form 전송할때 전송이 될수 있도록)
        imageInput.current.files = e.dataTransfer.files;
    };

    const personSvg = useRef();
    const profileStyle2={
        width: "200px",
        height: "200px",
        border: "1px solid #cecece",
        borderRadius: "50%",
        display: "none"
    }

    const imageInput = useRef();

    // input type="file" 요소에 change 이벤트가 일어 났을때 호출되는 함수 
    const handleChange = (e)=>{
        //선택한 파일 객체
        const file=e.target.files[0]
        //파일로 부터 데이터를 읽어들일 객체 생성
        const reader=new FileReader()
        //파일을 DataURL 형식의 문자열로 읽어들이기
        reader.readAsDataURL(file)
        //로딩이 완료(파일데이터를 모드 읽었을때) 되었을때 실행할 함수 등록
        reader.onload=(event)=>{
            //읽은 파일 데이터 얻어내기 
            const data=event.target.result
            setImageSrc(data)
        }
    }

    return (
        <>
            <svg ref={personSvg} style={profileStyle2}  xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
                <path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
                <path fillRule="evenodd" d="M0 8a8 8 0 1 1 16 0A8 8 0 0 1 0 8zm8-7a7 7 0 0 0-5.468 11.37C3.242 11.226 4.805 10 8 10s4.757 1.225 5.468 2.37A7 7 0 0 0 8 1z"/>
            </svg>
            <h1>개인 정보 수정 양식</h1>
            <Form>
                <Form.Group className="mb-3">
                    <Form.Label>사용자명</Form.Label>
                    <Form.Control name="userName" defaultValue={user.userName} readOnly/>
                </Form.Group>
                <Form.Group className="mb-3" controlId="email">
                    <Form.Label>이메일</Form.Label>
                    <Form.Control name="email" defaultValue={user.email}/>
                </Form.Group>
                <Form.Group>
                    <Form.Label>프로필 이미지 ( click or drag-drop to Edit ) </Form.Label>
                    <Form.Control ref={imageInput} onChange={handleChange} style={{display:"none"}} type="file" name="image" accept="image/*"/>
                </Form.Group>
                <div className="mb-3">
                    <a href="about:blank" onClick={(e)=>{
                        e.preventDefault()
                        // input  type="file" 요소를 강제 클릭 
                        imageInput.current.click();
                    }}>
                        <div style={dropZoneStyle} onDragOver={(e)=>e.preventDefault()} onDrop={handleDrop}>
                            { imageSrc && <img style={profileStyle} src={imageSrc} alt="프로필 이미지"/>}
                        </div>
                    </a>
                </div>
                <Button type="submit" variant="success" size="sm">수정확인</Button>
                <Button className="ms-1" type="reset" variant="danger" size="sm">Reset</Button>
            </Form>
        </>
    );
}

export default UserUpdateForm;

 

 

처음에 받아온 프로필 이미지 정보를 저장해놨다가 리셋 버튼을 누르면 원래의 이미지로 돌아갈 수 있게 해주기.

 

인풋 속성의 name과 Dto의 필드명이 같아야 한다.

 

와 진짜 피곤해 ㄷㄷ

<16:30 7교시>

 

 

 

<17:30 8교시>

에러 핸들링

 

react에서 사용한 비밀번호 유효성 검사도 했다.

일단 저장하고... 내일 공부해보자... 오늘은 더 못하겠다.