본문 바로가기
Spring

[웹프로젝트] 10. 마이페이지(3) 프로필이미지 변경 요청

by moca7 2024. 10. 29.

 

 

 


ㅁ myinfo.jsp

 

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
   
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<style>
    #profileImg{
        width:250px;
        height:250px;
        border:1px solid lightgray;
        border-radius: 50%;
    }
</style>


    <script src="${contextPath}/resources/js/fileValidate.js"></script>

   
</head>
<body>

    <div class="container p-3">

        <!-- Header, Nav start -->
        <jsp:include page="/WEB-INF/views/common/header.jsp"/>
        <!-- Header, Nav end -->
   
        <!-- Section start -->
        <section class="row m-3" style="min-height: 500px">
   
          <div class="container border p-5 m-4 rounded">
            <h2 class="m-4">마이페이지</h2>
            <br>

            <div align="center">
                <img id="profileImg" src="${contextPath}<c:out value='${loginUser.profileURL}' default='/resources/images/defaultProfile.png' />" onclick="$('#profileImgFile').click();">
                <input type="file" class="file" id="profileImgFile" style="display:none;" accept="image/*">
            </div>

            <form action="${contextPath}/member/update.do" method="post" id="myinfo_form">
                <div class="form-group">
                    <label for="userId">* ID :</label>
                    <input type="text" class="form-control" id="userId" name="userId" value="${ loginUser.userId }" readonly><br>
                   
                    <label for="userName">* Name :</label>
                    <input type="text" class="form-control" id="userName" name="userName" value="${ loginUser.userName }"><br>
                   
                    <label for="email"> &nbsp; Email :</label>
                    <input type="email" class="form-control" id="email" name="email" value="${ loginUser.email }"><br>
                   
                    <label for="phone"> &nbsp; Phone :</label>
                    <input type="tel" class="form-control" id="phone" name="phone" value="${ loginUser.phone}"><br>
                   
                    <label for="address"> &nbsp; Address :</label>
                    <input type="text" class="form-control" id="address" name="address" value="${ loginUser.address }"><br>
                   
                    <label for=""> &nbsp; Gender : </label> &nbsp;&nbsp;
                    <input type="radio" name="gender" id="Male" value="M">
                    <label for="Male">남자</label> &nbsp;&nbsp;
                    <input type="radio" name="gender" id="Female" value="F">
                    <label for="Female">여자</label><br>
                   
                    <script>
                        $(function(){
                                $("#myinfo_form :radio").filter("[value=${loginUser.gender}]").attr("checked", true);
                        })
                    </script>
                   
                   
                </div>
                <br>
                <div class="btns" align="center">
                    <button type="submit" class="btn btn-primary">수정하기</button>
                    <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteForm">회원탈퇴</button>
                </div>
            </form>
         
          </div>
   
        </section>
        <!-- Section end -->
   
        <!-- Footer start -->
        <jsp:include page="/WEB-INF/views/common/footer.jsp"/>
        <!-- Footer end -->
   
    </div>
   

    <!-- 회원탈퇴 버튼 클릭시 보여질 Modal -->
    <div class="modal" id="deleteForm">
        <div class="modal-dialog">
            <div class="modal-content">
           
                <!-- Modal Header -->
                <div class="modal-header">
                <h4 class="modal-title">회원탈퇴</h4>
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                </div>
               
                <!-- Modal body -->
                <div class="modal-body" align="center">
               
                    <b>
                                    탈퇴 후 복구가 불가능합니다. <br>  
                                    정말로 탈퇴 하시겠습니까?
                    </b>

                    <form action="" method="post">
                        비밀번호 :
                        <input type="password" name="" required>

                        <button type="submit" class="btn btn-danger">탈퇴하기</button>
                    </form>

                </div>
               
            </div>
        </div>
    </div>



    <script src="${contextPath}/resources/js/fileValidate.js"></script>

   
</body>
</html>
 

 

- 이미지 태그 하단에 type이 file인 input 요소가 있는데 현재 display:none으로 숨겨져 있다.

여기에 accept 속성을 추가한다.

이미지 파일만 선택할 수 있는 창이 뜨게끔 한다.

여기에 class속성을 추가한다.

- 이미지 파일만 들어와야 하고, 용량 제한도 있다. 유효성 검사를 해야 한다는 것이다.

 

- 프로필 이미지 요소를 클릭 (onclick 이벤트 발생시) 하면 

id가 profileImgFile인 input type file 요소가 클릭되게끔 걸어놨다.

 

 

- script를 head에 뒀다.(뒤에서 나옴)

 

 

- 비동기식으로 파일을 업로드한다.

 

 

 

 

 

 

- 프로필 이미지를 클릭하면 파일 업로드 차잉 뜬다. 이미지 파일이 유형으로 되어있다. 전체선택도 가능. 

 

 

 

 

 

ㅁ src/main/webapp/resources에 js 폴더 생성

- 그 폴더에 fileValidate.js 파일 생성

create new file에서 

- js확장자으 ㅣ파일이고 여기에 곧바로 스크립트 구문을 작성하면 된다.

 

 

 

 

 

- 문서 내으 ㅣ모든 요소들이 로드된 후에 이 functionㅇ ㅣ실행된다.

 

 

 
$(document).ready(function(){

  $('.file').on('change', function(evt){
   
    const files = evt.target.files; // FileList {0: File, 1: File, ...}
   
    let totalSize = 0;
    for(let i=0; i<files.length; i++){
   
      if(files[i].size > 10*1024*1024){
        alert('첨부파일의 최대 크기는 10MB입니다');
        evt.target.value = '';
        return;
      }
     
      totalSize += files[i].size;
   
      if(totalSize > 100*1024*1024){
        alert('전체 첨부파일의 최대 크기는 100MB입니다');
        evt.target.value = '';
        return;
      }
     
    }
   
  })
 
})  
 

 

 

 

 

- 어차피 지금 multiple이없어서 다중 파일 선택이 안된다.

그런데 이걸 다른데서도 쓸건데 거기서는 여러개의 파일이 선택될 수 있다.

- evt.target으로 현재 이벤특 ㅏ발생한 요소.

 

- 자바에서 메서드를 return으로 종료하는 것처럼 JavaScript에서도 return은 함수를 종료하는 역할을 한다.

- return 뒤에 값을 넣으면 그 값을 함수의 결과로 반환한다.

 

- js파일로 둔 이유는 다른데서도 쓸거여서. 근데 여기에 제이쿼리쓰고있어서 먼저 제이쿼리 라이브러리가 등록되어 있어야 한다.

 

- evt.target.files하면 현재 선택된 파일 리스트 객체.

 

 

 

 

 


 

- 마이페이지를 새로고침하면 콘솔에 오류가 뜬다. 

- $ is not defined는 제이쿼리 라이브러리를 못찾는거.

지금 제이쿼리 라이브러릴르 못찾고 있다.

 

 

 

 

 

 

- 그래서 script 그거를 바디태그 제일 하단에 몰아서 작성한다. 

head 태그 내에 두면 ~

- 젤 아래에 두고 새로고침하면 저 오륙 ㅏ사라진다.

 

 

 

 

=======================================================================

 

 

 

 

- 파일 업로드 하고, 그 후에 파일 업로드 정보를 db에도 기록한다.

- input 요소에 change 이벤트가 발생하는 순간 비동기식으로 파일을 전송할 수 있게 코드를 작성한다.

 

 

 

 

 

 

 

 


ㅁ MemberService

 

package com.br.spring.service;

import com.br.spring.dto.MemberDto;

public interface MemberService {

  // 로그인
  MemberDto selectMember(MemberDto m);
 
  // 회원가입
  int insertMember(MemberDto m);
 
  // 아이디중복체크
  int selectUserIdCount(String checkId);
 
  // 회원정보변경
  int updateMember(MemberDto m);
 
  // 회원탈퇴
  int deleteMember(String userId);
 
  // 회원프로필변경
  int updateProfileImg(MemberDto m);
}

 

ㅁ MemberServiceImpl

package com.br.spring.service;

import org.springframework.stereotype.Service;

import com.br.spring.dao.MemberDao;
import com.br.spring.dto.MemberDto;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service
public class MemberServiceImpl implements MemberService {
    private final MemberDao memberDao;

  @Override
  public MemberDto selectMember(MemberDto m) {
    return memberDao.selectMember(m);
  }

  @Override
  public int insertMember(MemberDto m) {
    return memberDao.insertMember(m);
  }

  @Override
  public int selectUserIdCount(String checkId) {
    return memberDao.selectUserIdCount(checkId);
  }

  @Override
  public int updateMember(MemberDto m) {
    return memberDao.updateMember(m);
  }

  @Override
  public int deleteMember(String userId) {
    return memberDao.deleteMember(userId);
  }

  @Override
  public int updateProfileImg(MemberDto m) {
    return memberDao.updateProfileImg(m);
  }
}

 

ㅁ MemberDao

 

package com.br.spring.dao;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Repository;

import com.br.spring.dto.MemberDto;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Repository
public class MemberDao {

    private final SqlSessionTemplate sqlSession;
   
    public MemberDto selectMember(MemberDto m) {
      return sqlSession.selectOne("memberMapper.selectMember", m);
    }
   
    public int insertMember(MemberDto m) {
      return sqlSession.insert("memberMapper.insertMember", m);
    }
   
    public int selectUserIdCount(String checkId) {
      return sqlSession.selectOne("memberMapper.selectUserIdCount", checkId);
    }
   
    public int updateMember(MemberDto m) {
      return sqlSession.update("memberMapper.updateMember", m);
    }
   
    public int deleteMember(String userId) {
      return sqlSession.update("memberMapper.deleteMember", userId);
    }
   
    public int updateProfileImg(MemberDto m) {
      return sqlSession.update("memberMapper.updateProfileImg", m);
    }
   
}

 

 

ㅁ member-mapper.xml

 

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="memberMapper">

  <resultMap id="memberResultMap" type="MemberDto">
    <result column="user_no" property="userNo" />
    <result column="user_id" property="userId" />
    <result column="user_pwd" property="userPwd" />
    <result column="user_name" property="userName" />
    <result column="email" property="email" />
    <result column="gender" property="gender" />
   
    <result column="phone" property="phone" />
    <result column="address" property="address" />    
    <result column="profile_url" property="profileURL" />
    <result column="signup_date" property="signupDt" />
    <result column="modify_date" property="modifyDt" />
    <result column="status" property="status" />                                        
  </resultMap>


  <!-- 로그인(암호화 적용 전)
  <select id="selectMember" resultMap="memberResultMap">
      select
             user_no
           , user_id
           , user_pwd
           , user_name
           , email
           , gender
           , phone
           , address
           , profile_url
           , signup_date
           , modify_date
           , status
        from member  
       where status in ('Y', 'A')
         and user_id = #{userId}
         and user_pwd = #{userPwd}
  </select> -->

  <select id="selectMember" resultMap="memberResultMap">
      select
             user_no
           , user_id
           , user_pwd
           , user_name
           , email
           , gender
           , phone
           , address
           , profile_url
           , signup_date
           , modify_date
           , status
        from member  
       where status in ('Y', 'A')
         and user_id = #{userId}
  </select>
 
 

  <!-- 회원가입 -->
  <insert id="insertMember">
      insert
        into member
        (
          user_no
        , user_id
        , user_pwd
        , user_name
        , email
        , gender
        , phone
        , address
        )
        values
        (
          seq_uno.nextval
        , #{userId}
        , #{userPwd}
        , #{userName}
        , #{email}
        , #{gender}
        , #{phone}
        , #{address}
        )
  </insert>
 
 

  <!-- 아이디중복체크(아이디 수 조회) -->
  <select id="selectUserIdCount" resultType="_int">
      select
             count(*)
        from member
       where user_id = #{checkId}      
  </select>
  <!-- 한 개의 컬럼, 한 개의 숫자만 조회된다. 자바에서의 int로 반환되게끔 한다. -->



  <!-- 회원정보수정 -->
  <update id="updateMember">
      update
             member
             
         set user_name = #{userName}
           , email = #{email}
           , phone = #{phone}
           , address = #{address}
           , gender = #{gender}
           , modify_date = sysdate
       where user_id = #{userId}        
  </update>
 
 

  <!-- 회원탈퇴 (행을 삭제하진 않고 개인정보만 일부 지운다. 이름 첫글자만 남기고 마스킹처리. -->
  <update id="deleteMember">
      update
             member
         set email = null
           , gender = null
           , phone = null
           , address = null
           , profile_url = null
<!--       , user_name = rpad( substr(user_name, 1, 1), 최종반환글자수, 덧붙일문자열 ) -->
           , user_name = rpad( substr(user_name, 1, 1), length(user_name), '*' )
           , status = 'N'
           , modify_date = sysdate
       where user_id = #{userId}
             
  </update>

  <!-- 회원프로필이미지 수정 -->
  <update id="updateProfileImg">
    update
           member
       set profile_url = #{profileURL}
         , modify_date = sysdate
     where user_no = #{userNo}    
  </update>


</mapper>

 

- 매퍼파일에 프로필 이미지를 변경하는 쿼리가 없다. 서비스도 dao도 없다.

- pk컬럼이 기본적으로 index로 지정되어 있다.

이왕 ~찾고자 한다면 pk로 하는게 제일 좋다. user_no

 

 

 

 

 

 

 

 

 

 

 

ㅁ FileUtil

 

 
package com.br.spring.util;

import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

@Component
public class FileUtil {
 

  public Map<String, String> fileupload(MultipartFile uploadFile, String folderName) {
   
   
    // (1) 업로드할 폴더 (/upload/yyyyMMdd)
    String filePath = "/upload/" + folderName + new SimpleDateFormat("/yyyyMMdd").format(new Date());
   
    File filePathDir = new File(filePath);
    if(!filePathDir.exists()) {   // 해당 경로의 폴더가 존재하지 않을 경우
      filePathDir.mkdirs();   // 해당 폴더 만들기
    }
   
   
    // (2) 파일명 수정 작업
    String originalFilename = uploadFile.getOriginalFilename(); // "xxxxx.jpg" | "xxxx.tar.gz" (파일 확장자가 2단계로 된 확장자도 있다)
   
    // 원본명으로부터 확장자 추출하기
    String originalExt = originalFilename.endsWith(".tar.gz") ? ".tar.gz"
                                  : originalFilename.substring(originalFilename.lastIndexOf("."));
   
    String filesystemName = UUID.randomUUID().toString().replace("-", "") + originalExt;
   
   
    // (3) 업로드 (폴더에 파일 저장)
    try {
      uploadFile.transferTo(new File(filePathDir, filesystemName));
    } catch (IllegalStateException e) {
      e.printStackTrace();
    } catch (IOException e) {
      e.printStackTrace();
    }
     
   
   
    // db에 기록할 데이터 다시 반환
    Map<String, String> map = new HashMap<>();
    map.put("filePath", filePath);
    map.put("originalFilename", originalFilename);
    map.put("filesystemName", filesystemName);
   
    return map;
   
   
  }
 
}

 

- 매개변수를 추가. 폴더명을 전달.

- filePath에 folderName과 뒤에 yyyy를 /yyyy로 수정했다.

슬래시가 있어야 한다.

/를 저기 말고 앞쪽에 + "/" + 로 둬도 된다.

 

 

 

 

 

 



ㅁ myinfo.jsp

 

 
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
   
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    
<c:set var="contextPath" value="${pageContext.request.contextPath}" />
   
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<style>
    #profileImg{
        width:250px;
        height:250px;
        border:1px solid lightgray;
        border-radius: 50%;
    }
</style>

</head>
<body>

    <div class="container p-3">

        <!-- Header, Nav start -->
        <jsp:include page="/WEB-INF/views/common/header.jsp"/>
        <!-- Header, Nav end -->
   
        <!-- Section start -->
        <section class="row m-3" style="min-height: 500px">
   
          <div class="container border p-5 m-4 rounded">
            <h2 class="m-4">마이페이지</h2>
            <br>

            <div align="center">
                <img id="profileImg" src="${contextPath}<c:out value='${loginUser.profileURL}' default='/resources/images/defaultProfile.png' />" onclick="$('#profileImgFile').click();">
                <input type="file" class="file" id="profileImgFile" style="display:none;" accept="image/*">
            </div>
           
            <script>
                $(document).ready(function(){
                    $('#profileImgFile').on("change", function(evt){
                        const files = evt.target.files; // FileList {File, File}
                       
                        if(files.length != 0){ // 선택된 파일이 있으면 비동기식으로 파일 전송 업로드 처리하고, db에 기록한다.
                            let formData = new FormData();
                            formData.append("uploadFile", files[0]);
                           
                            $.ajax({
                                url: '${contextPath}/member/updateProfile.do',
                                type: 'post',
                                data: formData,
                                processData: false,
                                contentType: false,
                               
                                success: function(resData){
                                    if(resData == "SUCCESS"){
                                        location.reload();
                                    }else{
                                        alert("프로필 이미지 변경 실패");
                                    }
                                }
                               
                               
                            })
                        }
                           
                    })
                })
            </script>
           

            <form action="${contextPath}/member/update.do" method="post" id="myinfo_form">
                <div class="form-group">
                    <label for="userId">* ID :</label>
                    <input type="text" class="form-control" id="userId" name="userId" value="${ loginUser.userId }" readonly><br>
                   
                    <label for="userName">* Name :</label>
                    <input type="text" class="form-control" id="userName" name="userName" value="${ loginUser.userName }"><br>
                   
                    <label for="email"> &nbsp; Email :</label>
                    <input type="email" class="form-control" id="email" name="email" value="${ loginUser.email }"><br>
                   
                    <label for="phone"> &nbsp; Phone :</label>
                    <input type="tel" class="form-control" id="phone" name="phone" value="${ loginUser.phone}"><br>
                   
                    <label for="address"> &nbsp; Address :</label>
                    <input type="text" class="form-control" id="address" name="address" value="${ loginUser.address }"><br>
                   
                    <label for=""> &nbsp; Gender : </label> &nbsp;&nbsp;
                    <input type="radio" name="gender" id="Male" value="M">
                    <label for="Male">남자</label> &nbsp;&nbsp;
                    <input type="radio" name="gender" id="Female" value="F">
                    <label for="Female">여자</label><br>
                   
                    <script>
                        $(function(){
                                $("#myinfo_form :radio").filter("[value=${loginUser.gender}]").attr("checked", true);
                        })
                    </script>
                   
                   
                </div>
                <br>
                <div class="btns" align="center">
                    <button type="submit" class="btn btn-primary">수정하기</button>
                    <button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteForm">회원탈퇴</button>
                </div>
            </form>
         
          </div>
   
        </section>
        <!-- Section end -->
   
        <!-- Footer start -->
        <jsp:include page="/WEB-INF/views/common/footer.jsp"/>
        <!-- Footer end -->
   
    </div>
   

    <!-- 회원탈퇴 버튼 클릭시 보여질 Modal -->
    <div class="modal" id="deleteForm">
        <div class="modal-dialog">
            <div class="modal-content">
           
                <!-- Modal Header -->
                <div class="modal-header">
                <h4 class="modal-title">회원탈퇴</h4>
                <button type="button" class="close" data-dismiss="modal">&times;</button>
                </div>
               
                <!-- Modal body -->
                <div class="modal-body" align="center">
               
                    <b>
                                    탈퇴 후 복구가 불가능합니다. <br>  
                                    정말로 탈퇴 하시겠습니까?
                    </b>

                    <form action="" method="post">
                        비밀번호 :
                        <input type="password" name="" required>

                        <button type="submit" class="btn btn-danger">탈퇴하기</button>
                    </form>

                </div>
               
            </div>
        </div>
    </div>



    <script src="${contextPath}/resources/js/fileValidate.js"></script>

   
</body>
</html>
 

 

- script 구문 작성.

- 파일 전송은 무조건 post 방식이다.

- 또 ajax로 파일을 전송할 때는 2개의 속성을 꼭 설정해야 한다.

 

- style border radius로 이미지가 원래는 네모인데 동그랗게 보인다.

 

 

 

ㅁ MemberController

 

 
package com.br.spring.controller;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.br.spring.dto.MemberDto;
import com.br.spring.service.MemberService;
import com.br.spring.util.FileUtil;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@RequestMapping("/member")
@RequiredArgsConstructor
@Controller
public class MemberController {

      private final MemberService memberService;
      private final BCryptPasswordEncoder bcryptPwdEncoder;
      private final FileUtil fileUtil;
   
     
    @PostMapping("/signin.do")
    public void signin(MemberDto m, HttpServletResponse response, HttpSession session, HttpServletRequest request) throws IOException {
        MemberDto loginUser = memberService.selectMember(m);

        // 로그인 성공시 => 세션에 회원정보를 담고, alert와 함께 메인 페이지로 이동
        // 로그인 실패시 => alert와 함께 기존에 보던 페이지 유지(아이디, 비번 입력하는 로그인 폼 유지. 작성하던 입력데이터도 그대로.)

        // script문을 응답데이터로 돌려줘서 흐름제어
        response.setContentType("text/html; charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("<script>");

        if(loginUser != null && bcryptPwdEncoder.matches(m.getUserPwd(), loginUser.getUserPwd())) { // 로그인 성공
            session.setAttribute("loginUser", loginUser);
            out.println("alert('" + loginUser.getUserName() + "님 환영합니다~');");
            out.println("location.href = '" + request.getHeader("referer") + "';"); // 메인페이지가 아닌 이전에 보던 페이지로 이동
        }else { // 로그인 실패
            out.println("alert('로그인에 실패하였습니다. 아이디 및 비밀번호를 다시 확인해주세요.');");
            out.println("history.back();"); // modal이 띄워진 상태였으면 modal도 유지된다.
        }

        out.println("</script>");
    }
   
   
    @GetMapping("/signout.do")
    public String signout(HttpSession session) {
        session.invalidate();
        return "redirect:/";
    }
   
   
    @GetMapping("/signup.do")
    public void signupPage() { } //WEB-INF/views/member/signup.jsp
       
    @ResponseBody
    @GetMapping("/idcheck.do")
    public String idCheck(String checkId) {
        return memberService.selectUserIdCount(checkId) == 0 ? "YYYY" : "NNNN";
    }
   
   
    @PostMapping("/insert.do")
    public String signup(MemberDto m, RedirectAttributes rdAttributes) {
       
        log.debug("암호화 전 member: {}", m);
       
        m.setUserPwd( bcryptPwdEncoder.encode(m.getUserPwd()) );
       
        log.debug("암호화 후 member: {}", m);
       
       
        int result = memberService.insertMember(m);
       
        // 성공시 alert와 함께 메인페이지 이동
        // 실패시 alert와 함께 기존에 작업중이던 페이지 유지
        if(result > 0) {
            rdAttributes.addFlashAttribute("alertMsg", "성공적으로 회원가입 되었습니다.");
        }else {
            rdAttributes.addFlashAttribute("alertMsg", "회원가입에 실패하였습니다.");
            rdAttributes.addFlashAttribute("historyBackYN", "Y");
        }
       
        return "redirect:/";
    }
   
   
   
    @GetMapping("/myinfo.do")
    public void myinfoPage() {}
   
   
    @PostMapping("/update.do")
    public String modify(MemberDto m
                       , RedirectAttributes rdAttributes
                       , HttpSession session) {
       
        int result = memberService.updateMember(m);
       
        if(result > 0) {
            session.setAttribute("loginUser", memberService.selectMember(m));// 동일한 키값으로 담으면 덮어씌워진다.
            rdAttributes.addFlashAttribute("alertMsg", "성공적으로 정보수정 되었습니다.");
        }else {
            rdAttributes.addFlashAttribute("alertMsg", "정보수정에 실패하였습니다.");          
        }
       
        return "redirect:/member/myinfo.do";
    }
   
   
    @ResponseBody
    @PostMapping("/updateProfile.do")
    public String modifyProfile(MultipartFile uploadFile, HttpSession session) {
       
        // 현재 로그인한 회원정보
        MemberDto loginUser = (MemberDto)session.getAttribute("loginUser");
       
        // 현재 로그인한 회원의 기존 프로필 url (불필요한 파일은 삭제처리하는 것이 좋다)
        String originalProfileURL = loginUser.getProfileURL();
       
        // 변경요청한 프로필 파일 업로드
        Map<String, String> map = fileUtil.fileupload(uploadFile, "profile");
       
        // 현재 로그인한 회원 객체의 profileURL 필드값을 새로운 프로필 이미지 경로로 수정
        String newURL = map.get("filePath") + "/" + map.get("filesystemName"); // 새로 저장된 프로필 이미지의 url 주소.
        loginUser.setProfileURL(newURL);
       
        // db에 기록하기 위해 service 호출
        int result = memberService.updateProfileImg(loginUser);
       
        if(result > 0) {
            // 성공시 기존 프로필이 존재했다면 파일을 삭제한다.
            if(originalProfileURL != null) {
                new File(originalProfileURL).delete();
            }
            return "SUCCESS";
           
        }else {
            // 실패시 변경요청시 전달된 파일을 삭제한다.
            new File(loginUser.getProfileURL()).delete();
            loginUser.setProfileURL(originalProfileURL); // 기존걸로 다시 변경
            return "FAIL";
           
        }
    }
}

 

- 매개변수명을 key값과 동일하게 uploadFile로 하면 곧바로 담긴다.

formData.append로 담았었다.

- FileUtil을 전역 변수로 선언했다.

FileUtil도 빈등록이 이미 되어있어야 한다. @Component를 붙였었다.

 

- File 객체는 java.io.File을 import 한다.

 

- 현재 ajax여서 성공 실패를 판별할 응답데이터르 ㄹ돌려줘야 한다.

- 응답 뷰아니므로 @ResponseBody

 

 

 

 

ㅁ 

 

- servlet-context.xml에 정적인 경로를 등록해야 한다. 그래서 404가 뜬다.

 

 

 

 

ㅁ servlet-context.xml

 

 
<?xml version="1.0" encoding="UTF-8"?>

  <!-- DispatcherServlet Context: defines this servlet's request-processing infrastructure -->
 
  <!-- Enables the Spring MVC @Controller programming model -->
  <annotation-driven />

  <!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory -->
  <resources mapping="/resources/**" location="/resources/" />
  <resources mapping="/upload/**" location="file:///upload/" />

  <!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
  <beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
  </beans:bean>
 
  <context:component-scan base-package="com.br.spring" />
 
 
 
</beans:beans>

 

- <resources mapping="/upload/**" location="file:///upload/" />를 작성했다.

 

- 다시해보면 잘 된다.

기존 파일은 사라지고 현재 프로필 이미지 파일 하나만 있다.

여러번 프로필 이미지를 바꿔도 하나의 이미지 파일만 있다.

 

 

 

 

ㅁ 프로필 이미지 변경은 마이페이지에서 수정하기 버튼 누르지 않아도 파일 선택하는 순간 update되게 했다.