관리 메뉴

거니의 velog

231206_SPRING 2 (11-2) 본문

대덕인재개발원_웹기반 애플리케이션

231206_SPRING 2 (11-2)

Unlimited00 2023. 12. 6. 08:25

            <p class="mb-1">
                <a href="/notice/forget.do">아이디&비밀번호 찾기</a>
            </p>
            <p class="mb-0">
                <a href="/notice/signup.do" class="text-center">회원가입</a>
            </p>
package kr.or.ddit.controller.crud.notice;

import java.util.HashMap;
import java.util.Map;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.service.INoticeService;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/notice")
public class NoticeLoginController {

	.......

	@RequestMapping(value = "/forget.do", method = RequestMethod.GET)
	public String loginForgetIdAndPw(Model model) {
		model.addAttribute("bodyText", "login-page");
		return "conn/forget";
	}
	
}

[header.jsp]

    <ul class="navbar-nav ml-auto">
        <li class="nav-item dropdown">
            <a class="nav-link" data-toggle="dropdown" href="#">
                <i class="far fa-user"></i>
            </a>
            <d iv class="dropdown-menu dropdown-menu-sm dropdown-menu-right">
                <a href="/notice/profile.do" class="dropdown-item dropdown-footer">마이페이지</a>
                <div class="dropdown-divider"></div>
                <a href="/notice/logout.do" class="dropdown-item dropdown-footer">로그아웃</a>
        </li>
    </ul>
package kr.or.ddit.controller.crud.notice;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/notice")
public class NoticeProfileController {

	@RequestMapping(value = "/profile.do", method = RequestMethod.GET)
	public String noticeProfile() {
		return "notice/profile";
	}
	
}

- http://localhost/notice/forget.do

- http://localhost/notice/profile.do


package kr.or.ddit.controller.crud.notice;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import kr.or.ddit.service.INoticeService;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/notice")
public class NoticeProfileController {
	
	@Inject
	private INoticeService noticeService;
	
	@RequestMapping(value = "/profile.do", method = RequestMethod.GET)
	public String noticeProfile(
			HttpServletRequest req,
			RedirectAttributes ra,
			Model model
			) {
		
		String goPage = "";
		
		HttpSession session = req.getSession();
		NoticeMemberVO sessionMember = (NoticeMemberVO) session.getAttribute("SessionInfo");
		
		if(sessionMember == null) {
			ra.addFlashAttribute("message", "로그인 후 이용가능합니다!");
			return "redirect:/notice/login.do";
		}
		
		NoticeMemberVO member = noticeService.selectMember(sessionMember.getMemId());
		
		if(member != null) {
			model.addAttribute("member", member);
			goPage = "notice/profile";
		}else {
			ra.addFlashAttribute("message", "로그인 후 이용가능합니다!");
			goPage = "redirect:/notice/login.do";
		}
		
		return goPage;
		
	}
	
}
package kr.or.ddit.service;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.vo.crud.NoticeFileVO;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import kr.or.ddit.vo.crud.NoticeVO;
import kr.or.ddit.vo.crud.PaginationInfoVO;

public interface INoticeService {

	public int selectNoticeCount(PaginationInfoVO<NoticeVO> pagingVO);
	public List<NoticeVO> selectNoticeList(PaginationInfoVO<NoticeVO> pagingVO);
	public ServiceResult insertNotice(HttpServletRequest req, NoticeVO noticeVO);
	public NoticeVO selectNotice(int boNo);
	public ServiceResult updateNotice(HttpServletRequest req, NoticeVO noticeVO);
	public ServiceResult deleteNotice(HttpServletRequest req, int boNo);
	
	public NoticeMemberVO loginCheck(NoticeMemberVO member);
	public ServiceResult idCheck(String memId);
	public ServiceResult signup(HttpServletRequest req, NoticeMemberVO memberVO);
	
	public NoticeFileVO noticeDownload(int fileNo);
	
	public NoticeMemberVO selectMember(String memId);

}
package kr.or.ddit.service.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.controller.crud.notice.TelegramSendController;
import kr.or.ddit.mapper.ILoginMapper;
import kr.or.ddit.mapper.INoticeMapper;
import kr.or.ddit.mapper.IProfileMapper;
import kr.or.ddit.service.INoticeService;
import kr.or.ddit.vo.crud.NoticeFileVO;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import kr.or.ddit.vo.crud.NoticeVO;
import kr.or.ddit.vo.crud.PaginationInfoVO;

@Service
public class NoticeServiceImpl implements INoticeService {

	@Inject
	private INoticeMapper noticeMapper;
	
	@Inject
	private ILoginMapper loginMapper;
	
	@Inject
	private IProfileMapper profileMapper;
	
	private TelegramSendController tst = new TelegramSendController();

	@Override
	public int selectNoticeCount(PaginationInfoVO<NoticeVO> pagingVO) {
		return noticeMapper.selectNoticeCount(pagingVO);
	}

	@Override
	public List<NoticeVO> selectNoticeList(PaginationInfoVO<NoticeVO> pagingVO) {
		return noticeMapper.selectNoticeList(pagingVO);
	}

	@Override
	public ServiceResult insertNotice(HttpServletRequest req, NoticeVO noticeVO) {
		ServiceResult result = null;

		int status = noticeMapper.insertNotice(noticeVO);
		if (status > 0) {	// 게시글 등록이 성공했을 때
			List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
			try {
				// 공지사항 파일 업로드 처리
				noticeFileUpload(noticeFileList, noticeVO.getBoNo(), req);
			}catch(IOException e) {
				e.printStackTrace();
			}
			
			// Telegram Bot API를 이용한 실시간 메세지 처리
			try {
				tst.sendGet("홍길동", noticeVO.getBoTitle());
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			result = ServiceResult.OK;
		} else {
			result = ServiceResult.FAILED;
		}

		return result;
	}

	@Override
	public NoticeVO selectNotice(int boNo) {
		noticeMapper.incrementHit(boNo); // 게시글 조회수 증가
		return noticeMapper.selectNotice(boNo); // 게시글 번호에 해당하는 게시글 정보 가져오기
	}

	@Override
	public ServiceResult updateNotice(HttpServletRequest req, NoticeVO noticeVO) {
		ServiceResult result = null;

		int status = noticeMapper.updateNotice(noticeVO); // 게시글 수정
		if (status > 0) { // 게시글 수정 완료
			// 게시글 정보에서 파일 목록을 가져오기
			List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
			try {
				// 공지사항 업로드 진행
				noticeFileUpload(noticeFileList, noticeVO.getBoNo(), req);
				
				// 기존에 등록되어 있는 파일 목록들 중, 수정하기 위해서 X버튼을 눌러 삭제 처리로 넘겨준 파일 번호들
				Integer[] delNoticeNo = noticeVO.getDelNoticeNo();
				if(delNoticeNo != null) {
					for(int i = 0; i < delNoticeNo.length; i++) {
						// 삭제할 파일 번호 목록들 중, 파일 번호에 해당하는 공지사항 파일 정보를 가져온다.
						NoticeFileVO noticeFileVO = noticeMapper.selectNoticeFile(delNoticeNo[i]);
						noticeMapper.deleteNoticeFile(delNoticeNo[i]); // 파일번호에 해당하는 파일 데이터를 삭제
						File file = new File(noticeFileVO.getFileSavepath());
						file.delete(); // 기존 파일이 업로드 되어 있던 경로에 파일 삭제
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			result = ServiceResult.OK;
		} else { // 게시글 수정 실패
			result = ServiceResult.FAILED;
		}

		return result;
	}

	@Override
	public ServiceResult deleteNotice(HttpServletRequest req, int boNo) {
		ServiceResult result = null;

		// 공지사항 파일 데이터를 삭제하기 위한 준비(파일 적용시)
		NoticeVO noticeVO = noticeMapper.selectNotice(boNo); // 게시글 번호에 해당하는 공지사항 게시글 정보 가져오기
		noticeMapper.deleteNoticeFileByBoNo(boNo); // 게시글 번호에 해당하는 파일 데이터 삭제
		
		int status = noticeMapper.deleteNotice(boNo); // 일반적인 게시글 삭제
		if (status > 0) {
			List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
			if(noticeFileList != null && noticeFileList.size() > 0) {
				// D:\99_Class...\workspace\.metadate\.plugins.....\Project명\resources\notice\boNo
				// 12d3uiy21euy1e2d.jpg
				// '/' 기준으로 잘라준다.
				String[] filePath = noticeFileList.get(0).getFileSavepath().split("/");
				
				String path = filePath[0];
				deleteFolder(req, path);
			}
			
			result = ServiceResult.OK;
		} else {
			result = ServiceResult.FAILED;
		}

		return result;
	}

	private void deleteFolder(HttpServletRequest req, String path) {
		// UUID + 원본파일명 전 폴더 경로를 folder 파일 객체로 잡는다.
		File folder = new File(path);
		
		if(folder.exists()) { // 경로가 존재한다면
			File[] folderList = folder.listFiles(); // 폴더 안에 있는 파일들의 목록을 가져온다.
			
			for(int i = 0; i < folderList.length; i++) {
				if(folderList[i].isFile()) { // 폴더 안에 있는 파일이 파일일 때
					// 폴더 안에 파일을 차례대로 삭제
					folderList[i].delete();
				}else {
					// 폴더 안에 있는 파일이 폴더일 때 재귀함수 호출(폴더 안으로 들어가서 재 처리할 수 있도록)
					deleteFolder(req, folderList[i].getPath());
				}
			}
			
			folder.delete(); // 폴더 삭제
		}
	}

	@Override
	public NoticeMemberVO loginCheck(NoticeMemberVO member) {
		return loginMapper.loginCheck(member);
	}

	@Override
	public ServiceResult idCheck(String memId) {
		ServiceResult result = null;

		NoticeMemberVO member = loginMapper.idCheck(memId);
		if (member != null) {
			result = ServiceResult.EXIST;
		} else {
			result = ServiceResult.NOTEXIST;
		}

		return result;
	}

	@Override
	public ServiceResult signup(HttpServletRequest req, NoticeMemberVO memberVO) {
		ServiceResult result = null;

		// 회원가입 시, 프로필 이미지로 파일을 업로드 하는데 이때 업로드 할 서버 경로
		String uploadPath = req.getServletContext().getRealPath("/resources/profile");
		File file = new File(uploadPath);
		if (!file.exists()) {
			file.mkdirs();
		}

		String proFileImg = ""; // 회원정보에 추가될 프로필 이미지 경로
		try {
			// 넘겨받은 회원정보에서 파일 데이터 가져오기
			MultipartFile proFileImgFile = memberVO.getImgFile();

			// 넘겨받은 파일 데이터가 존재할 때
			if (proFileImgFile.getOriginalFilename() != null && !proFileImgFile.getOriginalFilename().equals("")) {
				String fileName = UUID.randomUUID().toString(); // UUID 파일명 생성
				fileName += "_" + proFileImgFile.getOriginalFilename(); // UUID_원본파일명으로 파일명 생성
				uploadPath += "/" + fileName; // /resources/profile/uuid_원본파일명

				proFileImgFile.transferTo(new File(uploadPath)); // 해당 위치에 파일 복사
				proFileImg = "/resources/profile/" + fileName; // 파일 복사가 일어난 파일의 위치로 접근하기 위한 URI 설정
			}

			memberVO.setMemProfileImg(proFileImg);
		} catch (Exception e) {
			e.printStackTrace();
		}

		int status = loginMapper.signup(memberVO);

		if (status > 0) { // 등록 성공
			result = ServiceResult.OK;
		} else {
			result = ServiceResult.FAILED;
		}

		return result;
	}
	
	private void noticeFileUpload(
			List<NoticeFileVO> noticeFileList, 
			int boNo, 
			HttpServletRequest req
			) throws IOException {
		
		String savePath = "/resources/notice/";
		
		if(noticeFileList != null) { // 넘겨받은 파일 데이터가 존재할 때
			if(noticeFileList.size() > 0) {
				for(NoticeFileVO noticeFileVO : noticeFileList) {
					String saveName = UUID.randomUUID().toString(); // UUID의 랜덤 파일명 생성
					
					// 파일명을 설장할 때, 원본 파일명의 공백을 '_'로 변경한다.
					saveName = saveName + "_" + noticeFileVO.getFileName().replaceAll(" ", "_");
					// 디버깅 및 확장자 추출 참고
					String endFileName = noticeFileVO.getFileName().split("\\.")[1];
					
					String saveLocate = req.getServletContext().getRealPath(savePath + boNo);
					File file = new File(saveLocate);
					if(!file.exists()) {
						file.mkdirs();
					}
					saveLocate += "/" + saveName;
					
					noticeFileVO.setBoNo(boNo);						// 게시글 번호 설정
					noticeFileVO.setFileSavepath(saveLocate); 		// 파일 업로드 경로 설정
					noticeMapper.insertNoticeFile(noticeFileVO);	// 게시글 파일 데이터 추가
					
					File saveFile = new File(saveLocate);
					
					// 방법 1
//					InputStream is = noticeFileVO.getItem().getInputStream();
//					FileUtils.copyInputStreamToFile(is, saveFile);
					
					// 방법 2
					noticeFileVO.getItem().transferTo(saveFile); // 파일 복사
				}
			}
		}
		
	}

	@Override
	public NoticeFileVO noticeDownload(int fileNo) {
		NoticeFileVO noticeFileVO = noticeMapper.noticeDownload(fileNo);
		if(noticeFileVO == null) {
			throw new RuntimeException();
		}
		noticeMapper.incrementNoticeDowncount(fileNo); // 다운로드 횟수 증가
		return noticeFileVO;
	}

	@Override
	public NoticeMemberVO selectMember(String memId) {
		return profileMapper.selectMember(memId);
	}

}
package kr.or.ddit.mapper;

import kr.or.ddit.vo.crud.NoticeMemberVO;

public interface IProfileMapper {

	public NoticeMemberVO selectMember(String memId);

}

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IProfileMapper">
	
	<select id="selectMember" parameterType="string" resultType="noticeMemberVO">
		select 
			mem_no,
			mem_id,
			mem_pw,
			mem_name,
			mem_gender,
			mem_email,
			mem_phone,
			mem_postcode,
			mem_address1,
			mem_address2,
			mem_agree,
			mem_profileimg,
			mem_regdate
		from noticemember 
		where mem_id = #{memId}
	</select>
	
</mapper>

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<section class="content-header">
    <div class="container-fluid">
        <div class="row mb-2">
            <div class="col-sm-6">
                <h1>마이페이지</h1>
            </div>
            <div class="col-sm-6">
                <ol class="breadcrumb float-sm-right">
                    <li class="breadcrumb-item"><a href="#">Home</a></li>
                    <li class="breadcrumb-item active">User Profile</li>
                </ol>
            </div>
        </div>
    </div>
</section>

<section class="content">
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-3">

                <!-- Profile Image -->
                <div class="card card-dark card-outline">
                    <div class="card-header">
                        <div class="card-title">
                            <h4>내정보</h4>
                        </div>
                    </div>
                    <div class="card-body">
                        <div class="position-relative">
                            <img src="${member.memProfileImg }" alt="Photo 1" class="img-fluid">
                            <div class="ribbon-wrapper ribbon-lg">
                                <div class="ribbon bg-success text-lg">
                                    Profile
                                </div>
                            </div>
                        </div>
                        <div class="row mt-4">
                            <div class="col-md-4 text-bold">아이디</div>
                            <div class="col-md-8">${member.memId }</div>
                        </div>
                        <div class="row mt-2">
                            <div class="col-md-4 text-bold">비밀번호</div>
                            <div class="col-md-8">${member.memPw }</div>
                        </div>
                        <div class="row mt-2">
                            <div class="col-md-4 text-bold">이름</div>
                            <div class="col-md-8">${member.memName }</div>
                        </div>
                        <div class="row mt-2">
                            <div class="col-md-4 text-bold">성별</div>
                            <div class="col-md-8">
                            	<c:if test="${member.memGender eq 'M' }">남자</c:if>
                            	<c:if test="${member.memGender eq 'F' }">여자</c:if>
                            </div>
                        </div>
                        <div class="row mt-2">
                            <div class="col-md-4 text-bold">이메일</div>
                            <div class="col-md-8">${member.memEmail }</div>
                        </div>
                        <div class="row mt-2">
                            <div class="col-md-4 text-bold">전화번호</div>
                            <div class="col-md-8">${member.memPhone }</div>
                        </div>
                        <div class="row mt-2">
                            <div class="col-md-4 text-bold">주소</div>
                            <div class="col-md-8">${member.memAddress1 } ${member.memAddress2 }</div>
                        </div>
                        <div class="row mt-2">
                            <div class="col-md-4 text-bold">가입일</div>
                            <div class="col-md-8">${member.memRegDate }</div>
                        </div>
                    </div>
                </div>
            </div>
            <div class="col-md-9">
                <div class="card card-dark card-outline">
                	<form class="form-horizontal" action="/notice/profileUpdate.do" method="post" id="profileUpdateForm" enctype="multipart/form-data">
	                    <div class="card-header">
	                        <div class="row">
	                            <div class="col-md-10">
	                                <h4>내정보 수정</h4>
	                            </div>
	                            <div class="col-md-2" align="right">
	                                <button type="submit" class="btn btn-info">수정하기</button>
	                            </div>
	                        </div>
	                    </div>
	                    <div class="card-body">
	                        <div class="tab-content">
	                            <div class="tab-pane active">
	                            	<input type="hidden" name="memNo" id="memNo" value="${member.memNo }" />
                                    <div class="form-group row">
                                        <label class="col-sm-2 col-form-label">프로필이미지</label>
                                        <div class="col-md-10">
                                            <div class="custom-file">
                                                <input type="file" class="custom-file-input" id="imgFile" name="imgFile">
                                                <label class="custom-file-label" for="imgFile">프로필 이미지를 선택해주세요</label>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="form-group row">
                                        <label for="memId" class="col-sm-2 col-form-label">아이디</label>
                                        <div class="col-sm-10">
                                            <input type="text" class="form-control" id="memId" name="memId" placeholder="아이디를 입력해주세요." value="${member.memId }" readonly="readonly">
                                        </div>
                                    </div>
                                    <div class="form-group row">
                                        <label for="memPw" class="col-sm-2 col-form-label">비밀번호</label>
                                        <div class="col-sm-10">
                                            <input type="password" class="form-control" id="memPw" name="memPw" placeholder="비밀번호를 입력해주세요." value="${member.memPw }">
                                        </div>
                                    </div>
                                    <div class="form-group row">
                                        <label for="memName" class="col-sm-2 col-form-label">이름</label>
                                        <div class="col-sm-10">
                                            <input type="text" class="form-control" id="memName" name="memName" placeholder="이름을 입력해주세요."  value="${member.memName }">
                                        </div>
                                    </div>
                                    <div class="form-group row">
                                        <label for="" class="col-sm-2 col-form-label">성별</label>
                                        <div class="col-sm-10">
                                            <div class="icheck-primary d-inline">
                                                <input type="radio" id="memGenderM" name="memGender" value="M" <c:if test="${member.memGender eq 'M' }">checked</c:if>>
                                                <label for="memGenderM">남자</label>
                                            </div>
                                            <div class="icheck-primary d-inline">
                                                <input type="radio" id="memGenderF" name="memGender" value="F" <c:if test="${member.memGender eq 'F' }">checked</c:if>>
                                                <label for="memGenderF">여자</label>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="form-group row">
                                        <label for="memEmail" class="col-sm-2 col-form-label">이메일</label>
                                        <div class="col-sm-10">
                                            <input type="text" class="form-control" id="memEmail" name="memEmail" placeholder="이메일을 입력해주세요." value="${member.memEmail }">
                                        </div>
                                    </div>
                                    <div class="form-group row">
                                        <label for="memPhone" class="col-sm-2 col-form-label">전화번호</label>
                                        <div class="col-sm-10">
                                            <input type="text" class="form-control" id="memPhone" name="memPhone" placeholder="전화번호를 입력해주세요." value="${member.memPhone }">
                                        </div>
                                    </div>
                                    <div class="input-group mb-3">
                                        <label for="inputSkills" class="col-sm-2 col-form-label">주소</label>
                                        <div class="col-sm-10">
                                            <div class="input-group mb-3">
                                                <input type="text" class="form-control" id="memPostCode" name="memPostCode" placeholder="우편번호를 입력해주세요" value="${member.memPostCode }">
                                                <span class="input-group-append">
                                                    <button type="button" onclick="DaumPostcode()" class="btn btn-secondary btn-flat">우편번호 찾기</button>
                                                </span>
                                            </div>
                                            <div class="input-group mb-3">
                                                <input type="text" class="form-control" id="memAddress1" name="memAddress1" placeholder="주소를 입력해주세요" value="${member.memAddress1 }">
                                            </div>
                                            <div class="input-group mb-3">
                                                <input type="text" class="form-control" id="memAddress2" name="memAddress2" placeholder="상세주소를 입력해주세요" value="${member.memAddress2 }">
                                            </div>
                                        </div>
                                    </div>
	                            </div>
	                        </div>
	                    </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</section>
<script src="//t1.daumcdn.net/mapjsapi/bundle/postcode/prod/postcode.v2.js"></script>
<script>
	//daum 주소 API(주소 찾기)
	function DaumPostcode() {
	    new daum.Postcode({
	        oncomplete: function(data) {
	            // 팝업에서 검색결과 항목을 클릭했을때 실행할 코드를 작성하는 부분.
	
	            // 각 주소의 노출 규칙에 따라 주소를 조합한다.
	            // 내려오는 변수가 값이 없는 경우엔 공백('')값을 가지므로, 이를 참고하여 분기 한다.
	            var addr = ''; // 주소 변수
	            var extraAddr = ''; // 참고항목 변수
	
	            //사용자가 선택한 주소 타입에 따라 해당 주소 값을 가져온다.
	            if (data.userSelectedType === 'R') { // 사용자가 도로명 주소를 선택했을 경우
	                addr = data.roadAddress;
	            } else { // 사용자가 지번 주소를 선택했을 경우(J)
	                addr = data.jibunAddress;
	            }
	
	            // 사용자가 선택한 주소가 도로명 타입일때 참고항목을 조합한다.
	            if(data.userSelectedType === 'R'){
	                // 법정동명이 있을 경우 추가한다. (법정리는 제외)
	                // 법정동의 경우 마지막 문자가 "동/로/가"로 끝난다.
	                if(data.bname !== '' && /[동|로|가]$/g.test(data.bname)){
	                    extraAddr += data.bname;
	                }
	                // 건물명이 있고, 공동주택일 경우 추가한다.
	                if(data.buildingName !== '' && data.apartment === 'Y'){
	                    extraAddr += (extraAddr !== '' ? ', ' + data.buildingName : data.buildingName);
	                }
	            }
	
	            // 우편번호와 주소 정보를 해당 필드에 넣는다.
	            document.getElementById('memPostCode').value = data.zonecode;
	            document.getElementById("memAddress1").value = addr;
	            // 커서를 상세주소 필드로 이동한다.
	            document.getElementById("memAddress2").focus();
	        }
	    }).open();
	}
</script>

- http://localhost/notice/profile.do


package kr.or.ddit.controller.crud.notice;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.service.INoticeService;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
@RequestMapping("/notice")
public class NoticeProfileController {
	
	@Inject
	private INoticeService noticeService;
	
	@RequestMapping(value = "/profile.do", method = RequestMethod.GET)
	public String noticeProfile(
			HttpServletRequest req,
			RedirectAttributes ra,
			Model model
			) {
		
		String goPage = "";
		
		HttpSession session = req.getSession();
		NoticeMemberVO sessionMember = (NoticeMemberVO) session.getAttribute("SessionInfo");
		
		if(sessionMember == null) {
			ra.addFlashAttribute("message", "로그인 후 이용가능합니다!");
			return "redirect:/notice/login.do";
		}
		
		NoticeMemberVO member = noticeService.selectMember(sessionMember.getMemId());
		
		if(member != null) {
			model.addAttribute("member", member);
			goPage = "notice/profile";
		}else {
			ra.addFlashAttribute("message", "로그인 후 이용가능합니다!");
			goPage = "redirect:/notice/login.do";
		}
		
		return goPage;
		
	}
	
	@RequestMapping(value = "/profileUpdate.do", method = RequestMethod.POST)
	public String noticeProfileUpdate(
			HttpServletRequest req,
			NoticeMemberVO memberVO,
			RedirectAttributes ra,
			Model model
			) {
		
		String goPage = "";
		
		ServiceResult result = noticeService.profileUpdate(req, memberVO);
		if(result.equals(ServiceResult.OK)) {
			ra.addFlashAttribute("message", "회원정보 수정이 완료되었습니다!");
			goPage = "redirect:/notice/profile.do";
		}else {
			model.addAttribute("message", "서버에러, 수정이 실패했습니다!");
			model.addAttribute("member", memberVO);
			goPage = "notice/profile";
		}
		
		return goPage;
		
	}
	
}
package kr.or.ddit.service;

import java.util.List;

import javax.servlet.http.HttpServletRequest;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.vo.crud.NoticeFileVO;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import kr.or.ddit.vo.crud.NoticeVO;
import kr.or.ddit.vo.crud.PaginationInfoVO;

public interface INoticeService {

	public int selectNoticeCount(PaginationInfoVO<NoticeVO> pagingVO);
	public List<NoticeVO> selectNoticeList(PaginationInfoVO<NoticeVO> pagingVO);
	public ServiceResult insertNotice(HttpServletRequest req, NoticeVO noticeVO);
	public NoticeVO selectNotice(int boNo);
	public ServiceResult updateNotice(HttpServletRequest req, NoticeVO noticeVO);
	public ServiceResult deleteNotice(HttpServletRequest req, int boNo);
	
	public NoticeMemberVO loginCheck(NoticeMemberVO member);
	public ServiceResult idCheck(String memId);
	public ServiceResult signup(HttpServletRequest req, NoticeMemberVO memberVO);
	
	public NoticeFileVO noticeDownload(int fileNo);
	
	public NoticeMemberVO selectMember(String memId);
	public ServiceResult profileUpdate(HttpServletRequest req, NoticeMemberVO memberVO);

}
package kr.or.ddit.service.impl;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;

import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.io.FileUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import kr.or.ddit.ServiceResult;
import kr.or.ddit.controller.crud.notice.TelegramSendController;
import kr.or.ddit.mapper.ILoginMapper;
import kr.or.ddit.mapper.INoticeMapper;
import kr.or.ddit.mapper.IProfileMapper;
import kr.or.ddit.service.INoticeService;
import kr.or.ddit.vo.crud.NoticeFileVO;
import kr.or.ddit.vo.crud.NoticeMemberVO;
import kr.or.ddit.vo.crud.NoticeVO;
import kr.or.ddit.vo.crud.PaginationInfoVO;

@Service
public class NoticeServiceImpl implements INoticeService {

	@Inject
	private INoticeMapper noticeMapper;
	
	@Inject
	private ILoginMapper loginMapper;
	
	@Inject
	private IProfileMapper profileMapper;
	
	private TelegramSendController tst = new TelegramSendController();

	@Override
	public int selectNoticeCount(PaginationInfoVO<NoticeVO> pagingVO) {
		return noticeMapper.selectNoticeCount(pagingVO);
	}

	@Override
	public List<NoticeVO> selectNoticeList(PaginationInfoVO<NoticeVO> pagingVO) {
		return noticeMapper.selectNoticeList(pagingVO);
	}

	@Override
	public ServiceResult insertNotice(HttpServletRequest req, NoticeVO noticeVO) {
		ServiceResult result = null;

		int status = noticeMapper.insertNotice(noticeVO);
		if (status > 0) {	// 게시글 등록이 성공했을 때
			List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
			try {
				// 공지사항 파일 업로드 처리
				noticeFileUpload(noticeFileList, noticeVO.getBoNo(), req);
			}catch(IOException e) {
				e.printStackTrace();
			}
			
			// Telegram Bot API를 이용한 실시간 메세지 처리
			try {
				tst.sendGet("홍길동", noticeVO.getBoTitle());
			} catch (Exception e) {
				e.printStackTrace();
			}
			
			result = ServiceResult.OK;
		} else {
			result = ServiceResult.FAILED;
		}

		return result;
	}

	@Override
	public NoticeVO selectNotice(int boNo) {
		noticeMapper.incrementHit(boNo); // 게시글 조회수 증가
		return noticeMapper.selectNotice(boNo); // 게시글 번호에 해당하는 게시글 정보 가져오기
	}

	@Override
	public ServiceResult updateNotice(HttpServletRequest req, NoticeVO noticeVO) {
		ServiceResult result = null;

		int status = noticeMapper.updateNotice(noticeVO); // 게시글 수정
		if (status > 0) { // 게시글 수정 완료
			// 게시글 정보에서 파일 목록을 가져오기
			List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
			try {
				// 공지사항 업로드 진행
				noticeFileUpload(noticeFileList, noticeVO.getBoNo(), req);
				
				// 기존에 등록되어 있는 파일 목록들 중, 수정하기 위해서 X버튼을 눌러 삭제 처리로 넘겨준 파일 번호들
				Integer[] delNoticeNo = noticeVO.getDelNoticeNo();
				if(delNoticeNo != null) {
					for(int i = 0; i < delNoticeNo.length; i++) {
						// 삭제할 파일 번호 목록들 중, 파일 번호에 해당하는 공지사항 파일 정보를 가져온다.
						NoticeFileVO noticeFileVO = noticeMapper.selectNoticeFile(delNoticeNo[i]);
						noticeMapper.deleteNoticeFile(delNoticeNo[i]); // 파일번호에 해당하는 파일 데이터를 삭제
						File file = new File(noticeFileVO.getFileSavepath());
						file.delete(); // 기존 파일이 업로드 되어 있던 경로에 파일 삭제
					}
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			result = ServiceResult.OK;
		} else { // 게시글 수정 실패
			result = ServiceResult.FAILED;
		}

		return result;
	}

	@Override
	public ServiceResult deleteNotice(HttpServletRequest req, int boNo) {
		ServiceResult result = null;

		// 공지사항 파일 데이터를 삭제하기 위한 준비(파일 적용시)
		NoticeVO noticeVO = noticeMapper.selectNotice(boNo); // 게시글 번호에 해당하는 공지사항 게시글 정보 가져오기
		noticeMapper.deleteNoticeFileByBoNo(boNo); // 게시글 번호에 해당하는 파일 데이터 삭제
		
		int status = noticeMapper.deleteNotice(boNo); // 일반적인 게시글 삭제
		if (status > 0) {
			List<NoticeFileVO> noticeFileList = noticeVO.getNoticeFileList();
			if(noticeFileList != null && noticeFileList.size() > 0) {
				// D:\99_Class...\workspace\.metadate\.plugins.....\Project명\resources\notice\boNo
				// 12d3uiy21euy1e2d.jpg
				// '/' 기준으로 잘라준다.
				String[] filePath = noticeFileList.get(0).getFileSavepath().split("/");
				
				String path = filePath[0];
				deleteFolder(req, path);
			}
			
			result = ServiceResult.OK;
		} else {
			result = ServiceResult.FAILED;
		}

		return result;
	}

	private void deleteFolder(HttpServletRequest req, String path) {
		// UUID + 원본파일명 전 폴더 경로를 folder 파일 객체로 잡는다.
		File folder = new File(path);
		
		if(folder.exists()) { // 경로가 존재한다면
			File[] folderList = folder.listFiles(); // 폴더 안에 있는 파일들의 목록을 가져온다.
			
			for(int i = 0; i < folderList.length; i++) {
				if(folderList[i].isFile()) { // 폴더 안에 있는 파일이 파일일 때
					// 폴더 안에 파일을 차례대로 삭제
					folderList[i].delete();
				}else {
					// 폴더 안에 있는 파일이 폴더일 때 재귀함수 호출(폴더 안으로 들어가서 재 처리할 수 있도록)
					deleteFolder(req, folderList[i].getPath());
				}
			}
			
			folder.delete(); // 폴더 삭제
		}
	}

	@Override
	public NoticeMemberVO loginCheck(NoticeMemberVO member) {
		return loginMapper.loginCheck(member);
	}

	@Override
	public ServiceResult idCheck(String memId) {
		ServiceResult result = null;

		NoticeMemberVO member = loginMapper.idCheck(memId);
		if (member != null) {
			result = ServiceResult.EXIST;
		} else {
			result = ServiceResult.NOTEXIST;
		}

		return result;
	}

	@Override
	public ServiceResult signup(HttpServletRequest req, NoticeMemberVO memberVO) {
		ServiceResult result = null;

		// 회원가입 시, 프로필 이미지로 파일을 업로드 하는데 이때 업로드 할 서버 경로
		String uploadPath = req.getServletContext().getRealPath("/resources/profile");
		File file = new File(uploadPath);
		if (!file.exists()) {
			file.mkdirs();
		}

		String proFileImg = ""; // 회원정보에 추가될 프로필 이미지 경로
		try {
			// 넘겨받은 회원정보에서 파일 데이터 가져오기
			MultipartFile proFileImgFile = memberVO.getImgFile();

			// 넘겨받은 파일 데이터가 존재할 때
			if (proFileImgFile.getOriginalFilename() != null && !proFileImgFile.getOriginalFilename().equals("")) {
				String fileName = UUID.randomUUID().toString(); // UUID 파일명 생성
				fileName += "_" + proFileImgFile.getOriginalFilename(); // UUID_원본파일명으로 파일명 생성
				uploadPath += "/" + fileName; // /resources/profile/uuid_원본파일명

				proFileImgFile.transferTo(new File(uploadPath)); // 해당 위치에 파일 복사
				proFileImg = "/resources/profile/" + fileName; // 파일 복사가 일어난 파일의 위치로 접근하기 위한 URI 설정
			}

			memberVO.setMemProfileImg(proFileImg);
		} catch (Exception e) {
			e.printStackTrace();
		}

		int status = loginMapper.signup(memberVO);

		if (status > 0) { // 등록 성공
			result = ServiceResult.OK;
		} else {
			result = ServiceResult.FAILED;
		}

		return result;
	}
	
	private void noticeFileUpload(
			List<NoticeFileVO> noticeFileList, 
			int boNo, 
			HttpServletRequest req
			) throws IOException {
		
		String savePath = "/resources/notice/";
		
		if(noticeFileList != null) { // 넘겨받은 파일 데이터가 존재할 때
			if(noticeFileList.size() > 0) {
				for(NoticeFileVO noticeFileVO : noticeFileList) {
					String saveName = UUID.randomUUID().toString(); // UUID의 랜덤 파일명 생성
					
					// 파일명을 설장할 때, 원본 파일명의 공백을 '_'로 변경한다.
					saveName = saveName + "_" + noticeFileVO.getFileName().replaceAll(" ", "_");
					// 디버깅 및 확장자 추출 참고
					String endFileName = noticeFileVO.getFileName().split("\\.")[1];
					
					String saveLocate = req.getServletContext().getRealPath(savePath + boNo);
					File file = new File(saveLocate);
					if(!file.exists()) {
						file.mkdirs();
					}
					saveLocate += "/" + saveName;
					
					noticeFileVO.setBoNo(boNo);						// 게시글 번호 설정
					noticeFileVO.setFileSavepath(saveLocate); 		// 파일 업로드 경로 설정
					noticeMapper.insertNoticeFile(noticeFileVO);	// 게시글 파일 데이터 추가
					
					File saveFile = new File(saveLocate);
					
					// 방법 1
//					InputStream is = noticeFileVO.getItem().getInputStream();
//					FileUtils.copyInputStreamToFile(is, saveFile);
					
					// 방법 2
					noticeFileVO.getItem().transferTo(saveFile); // 파일 복사
				}
			}
		}
		
	}

	@Override
	public NoticeFileVO noticeDownload(int fileNo) {
		NoticeFileVO noticeFileVO = noticeMapper.noticeDownload(fileNo);
		if(noticeFileVO == null) {
			throw new RuntimeException();
		}
		noticeMapper.incrementNoticeDowncount(fileNo); // 다운로드 횟수 증가
		return noticeFileVO;
	}

	@Override
	public NoticeMemberVO selectMember(String memId) {
		return profileMapper.selectMember(memId);
	}

	@Override
	public ServiceResult profileUpdate(HttpServletRequest req, NoticeMemberVO memberVO) {
		ServiceResult result = null;
		
		// 프로필 이미지를 업로드 하기 위한 서버 경로(/resources/profile)
		String uploadPath = req.getServletContext().getRealPath("/resources/profile");
		File file = new File(uploadPath);
		if(!file.exists()) {
			file.mkdirs();
		}
		
		String profileImg = "";
		try {
			
			MultipartFile profileImgFile = memberVO.getImgFile();
			if(profileImgFile.getOriginalFilename() != null && !profileImgFile.getOriginalFilename().equals("")) {
				String fileName = UUID.randomUUID().toString();
				fileName += "_" + profileImgFile.getOriginalFilename();
				uploadPath += "/" + fileName;
				profileImgFile.transferTo(new File(uploadPath));
				profileImg = "/resources/profile/" + fileName;
			}
			
			memberVO.setMemProfileImg(profileImg);
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		int status = profileMapper.profileUpdate(memberVO);
		if(status > 0) { // 수정 성공
			result = ServiceResult.OK;
		}else { // 수정 실패
			result = ServiceResult.FAILED;
		}
		
		return result;
	}

}
package kr.or.ddit.mapper;

import kr.or.ddit.vo.crud.NoticeMemberVO;

public interface IProfileMapper {

	public NoticeMemberVO selectMember(String memId);
	public int profileUpdate(NoticeMemberVO memberVO);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="kr.or.ddit.mapper.IProfileMapper">
	
	<select id="selectMember" parameterType="string" resultType="noticeMemberVO">
		select 
			mem_no,
			mem_id,
			mem_pw,
			mem_name,
			mem_gender,
			mem_email,
			mem_phone,
			mem_postcode,
			mem_address1,
			mem_address2,
			mem_agree,
			mem_profileimg,
			mem_regdate
		from noticemember 
		where mem_id = #{memId}
	</select>
	
	<update id="profileUpdate" parameterType="noticeMemberVO">
		update noticemember 
		set 
			mem_pw = #{memPw},
			mem_name = #{memName},
			mem_gender = #{memGender},
			mem_email = #{memEmail},
			mem_phone = #{memPhone},
			mem_postcode = #{memPostCode},
			mem_address1 = #{memAddress1},
			mem_address2 = #{memAddress2} 
			<if test="memProfileImg != null and memProfileImg != ''">
				, mem_profileimg = #{memProfileImg}
			</if>
		where mem_no = #{memNo}
	</update>
	
</mapper>

- http://localhost/notice/profile.do