
zmember와 zmember_detial을 outer join 할 때 누락된 데이터가 보여져야 id 중복 체크가 가능하다.
// ID 중복 체크 및 로그인 처리
public MemberVO checkMember(String id) throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
String sql = null;
ResultSet rs = null;
MemberVO member = null;
try {
conn = DBUtil.getConnection();
sql="SELECT * FROM zmember LEFT OUTER JOIN zmember_detail USING(mem_num) WHERE id=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, id);
rs = pstmt.executeQuery();
if(rs.next()) {
member = new MemberVO();
member.setMem_num(rs.getInt("mem_num"));
member.setId(rs.getString("id"));
member.setAuth(rs.getInt("auth"));
member.setPasswd(rs.getString("passwd"));
member.setPhoto(rs.getString("photo"));
member.setEmail(rs.getString("email")); // 회원 탈퇴시에 필요한 정보
}
} catch (Exception e) {
throw new Exception(e);
} finally {
DBUtil.executeClose(rs, pstmt, conn);
}
return member;
}
lib > jackson-core-asl-1.9.11.jar/jackson-mapper-asl-1.9.11.jar Copy 시켜놓기
JSON 형식으로 변환하기를 원하는 문자열을 HashMap에 key와 value의 쌍으로 지정한 후 ObjectMapper의 writeValueAsString에 Map 객체를 전달해서 일반 문자열 데이터를 JSON 형식의 문자열 데이터로 변환 후 반환한다
package kr.main.action;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.codehaus.jackson.map.ObjectMapper;
import kr.controller.Action;
import kr.member.dao.MemberDAO;
import kr.member.vo.MemberVO;
public class CheckDuplicatedIdAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 전송된 데이터 인코딩 타입 지정
request.setCharacterEncoding("utf-8");
// 전송된 데이터 반환
String id = request.getParameter("id");
MemberDAO dao = MemberDAO.getInstance();
MemberVO member = dao.checkMember(id);
Map<String, String> mapAjax = new HashMap<String, String>();
if(member == null) { // 아이디 미중복
mapAjax.put("result","idNotFound");
} else { // 아이디 중복
mapAjax.put("result", "idDuplicated");
}
ObjectMapper mapper = new ObjectMapper();
// JSON 문자열 반환
String ajaxData = mapper.writeValueAsString(mapAjax);
request.setAttribute("ajaxData", ajaxData);
return "/WEB-INF/views/common/ajax_view.jsp";
}
}
<%@ page language="java" contentType="text/plain; charset=UTF-8"
pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>
${ajaxData}
/member/checkDuplicatedId.do=kr.member.action.CheckDuplicatedIdAction
$(function(){
let idChecked = 0; // 0: 중복, id 중복 체크 미실시, 1: 미중복
// 아이디 중복 체크
$('#id_check').click(function(){
if(!/^[A-Za-z0-9]{4,12}$/.test($('#id').val())){
alert('영문 또는 숫자 사용, 최소 4자 ~ 최대 12자 사용');
$('#id').val('').focus();
return;
}
// 서버와 통신
$.ajax({
url:'checkDuplicatedId.do',
type:'post',
data:{id:$('#id').val()},
dataType: 'json',
success: function(param){
if(param.result=='idNotFound'){
idChecked = 1;
$('#message_id').css('color','black').text('등록 가능 ID');
}else if(param.result=='idDuplicated'){
idChecked = 0;
$('#message_id').css('color','red').text('중복된 ID');
$('#id').val('').focus();
} else{
idChecked=0;
alert('ID 중복 체크 오류 발생');
}
},
error:function(){
idChecked = 0;
alert('Network Error Occurred');
}
})
});// end of Click
// 아이디 중복 안내 메시지 초기화 및 아이디 중복 값 초기화
$('#register_form #id').keydown(function(){
idChecked = 0;
$('#message_id').text('');
});// end of Keydown
// 회원 정보 등록 유효성 체크
$('#register_form').submit(function(){
const items = document.querySelectorAll('.input-check');
for(let i=0; i<items.length; i++){
if(items[i].value.trim()==''){
const label = document.querySelector('label[for="'+items[i].id+'"]');
alert(label.textContent+' 필수 입력');
items[i].value = '';
items[i].focus();
return false;
} // if 4
if(items[i].id == 'id' && !/^[A-Za-z0-9]{4,12}$/.test($('#id').val())){
alert('영문 또는 숫자 사용, 최소 4자 ~ 최대 12자 사용');
$('#id').val('').focus();
return false;
} // if 3
if(items[i].id == 'id' && idChecked == 0){
alert('ID 중복 체크는 필수입니다.');
return false;
} // if 2
if(items[i].id == 'zipcode' && !/^[0-9]{5}$/.test($('#zipcode').val())){
alert('우편 번호를 입력하세요(숫자 5자리)');
$('#zipcode').val('').focus();
return false;
} // if 1
}
}); // end of submit
});
package kr.member.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.controller.Action;
public class LoginFormAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
return "/WEB-INF/views/member/loginForm.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Login</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap" rel="stylesheet">
<script type="text/javascript" src="<%= request.getContextPath() %>/js/jquery-3.7.1.min.js"></script>
<script type="text/javascript">
$(function(){
$('#login_form').submit(function(){
if($('#id').val().trim()==''){
alert('아이디를 입력하세요');
$('#id').val('').focus();
return false;
}
if($('#passwd').val().trim()==''){
alert('비밀번호를 입력하세요');
$('#passwd').val('').focus();
return false;
}
})
});
</script>
</head>
<body>
<div class="page-main">
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<div class="content-main">
<h2>Login</h2>
</div>
<form action="login.do" id="login_form" method="post">
<ul>
<li class="floating-label">
<input type="text" class="form-input" placeholder="ID" name="id" id="id" maxlength="12" autocomplete="off">
<label for="id">ID</label>
</li>
<li class="floating-label">
<input type="password" class="form-input" placeholder="PW" name="passwd" id="passwd" maxlength="12">
<label for="passwd">PW</label>
</li>
</ul>
<div class="align-center">
<input type="submit" value="Login">
<input type="button" value="Home" onclick="location.href='${pageContext.request.contextPath}/main/main.do'">
</div>
</form>
</div>
</body>
</html>
package kr.member.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import kr.controller.Action;
import kr.member.dao.MemberDAO;
import kr.member.vo.MemberVO;
public class LoginAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("UTF-8");
String id = request.getParameter("id");
String passwd= request.getParameter("passwd");
MemberDAO dao = MemberDAO.getInstance();
MemberVO member= dao.checkMember(id);
boolean check = false;
if (member != null) {
// 동일한 id 존재
// 비밀번호 일치 여부 체크
check = member.isCheckedPassword(passwd);
// 정지 회원의 경우 상태 표시
request.setAttribute("auth", member.getAuth());
}
if(check) {
// 인증 성공, 로그인 처리
HttpSession session = request.getSession();
session.setAttribute("user_num", member.getMem_num());
session.setAttribute("user_id", member.getId());
session.setAttribute("user_auth", member.getAuth());
session.setAttribute("user_photo", member.getPhoto());
// 메인으로 리다이렉트
return "redirect:/main/main.do";
}
// 인증 실패
return "/WEB-INF/views/member/login.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:choose>
<c:when test="${auth == 1}">
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 정보</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap" rel="stylesheet">
</head>
<body>
<div class="page-main">
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<div class="content-main">
<h2>회원 정보</h2>
<div class="result-display">
<div class="align-center">
정지된 회원 ID입니다.<br><br>
<input type="button" value="홈으로" onclick="location.href='${pageContext.request.contextPath}/main/main.do'">
</div>
</div>
</div>
</div>
</body>
</html>
</c:when>
<%-- auth가 1이 아닌 경우 --%>
<c:otherwise>
<script type="text/javascript">
alert('ID 또는 PW가 불일치합니다.');
history.go(-1);
</script>
</c:otherwise>
</c:choose>
package kr.member.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import kr.controller.Action;
public class LogoutAction implements Action {
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpSession session = request.getSession();
session.invalidate();
// 메인으로 redirect
return "redirect:/main/main.do";
}
}



public MemberVO getMember(int mem_num) throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String sql = null;
MemberVO member = null;
try {
conn = DBUtil.getConnection();
sql = "SELECT * FROM zmember_detail JOIN zmember USING(mem_num) WHERE mem_num=?";
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, mem_num);
rs = pstmt.executeQuery();
if(rs.next()) {
member = new MemberVO();
member.setId(rs.getString("id"));
member.setName(rs.getString("name"));
member.setPhone(rs.getString("phone"));
member.setEmail(rs.getString("email"));
member.setZipcode(rs.getString("zipcode"));
member.setAddress1(rs.getString("address1"));
member.setAddress2(rs.getString("address2"));
member.setPhoto(rs.getString("photo"));
member.setReg_date(rs.getDate("reg_date"));
member.setModify_date(rs.getDate("modify_date"));
}
} catch (Exception e) {
throw new Exception(e);
} finally {
DBUtil.executeClose(rs, pstmt, conn);
}
return member;
}
package kr.member.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import kr.controller.Action;
import kr.member.dao.MemberDAO;
import kr.member.vo.MemberVO;
public class MyPageAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
request.setCharacterEncoding("utf-8");
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num == null) { // 로그인 되지 않은 경우
return "redirect:/member/loginForm.do";
}
// 로그인 완료 후
MemberDAO dao = MemberDAO.getInstance();
MemberVO member = dao.getMember(user_num);
request.setAttribute("member", member);
return "/WEB-INF/views/member/myPage.jsp";
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Page</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap" rel="stylesheet">
<script type="text/javascript" src="<%= request.getContextPath() %>/js/jquery-3.7.1.min.js"></script>
</head>
<body>
<div class="page-main">
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<div class="content-main">
<h2>My Page</h2>
<div class="mypage-div">
<h3>Profile Photo</h3>
<ul>
<li>
<c:if test="${empty member.photo}">
<img alt="profile photo" src="${pageContext.request.contextPath}/images/face.png"
width="200" height="200" class="my-photo">
</c:if>
<c:if test="${!empty member.photo}">
<img alt="profile photo" src="${pageContext.request.contextPath}/upload/${member.photo}"
width="200" height="200" class="my-photo">
</c:if>
</li>
<li>
<div class="align-center">
<input type="button" value="수정" id="photo_btn">
</div>
<div id="photo_choice" style="display: none;">
<input type="file" id="photo" accept="image/gif,image/png,image/jpeg">
<input type="button" value="전송" id="photo_submit">
<input type="button" value="취소" id="photo_reset">
</div>
</li>
</ul>
<h3>연락처 <input type="button" id="tel_btn" value="연락처 수정" onclick="location.href='modifyUserForm.do'"> </h3>
<ul>
<li>ID : ${member.id }</li>
<li>이름 : ${member.name }</li>
<li>전화번호 : ${member.phone }</li>
<li>E-mail : ${member.email }</li>
<li>우편번호 : ${member.zipcode }</li>
<li>주소 : ${member.address1} ${member.address2}</li>
<li>가입일 : ${member.reg_date }</li>
<c:if test="${!empty member.modify_date }">
<li>최근 정보 수정일 : ${member.modify_date }</li>
</c:if>
</ul>
<h3>비밀번호 수정</h3>
<h3>회원 탈퇴</h3>
</div>
<div class="mypage-div">
<h3>관심 게시물 목록</h3>
</div>
<div class="mypage-end">
</div>
</div>
</div>
</body>
</html>
public void updateMyPhoto(String photo, int mem_num) throws Exception{
Connection conn = null;
PreparedStatement pstmt = null;
String sql = null;
try {
conn= DBUtil.getConnection();
sql="UPDATE zmember_detail SET photo=? WHERE mem_num=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, photo);
pstmt.setInt(2, mem_num);
pstmt.executeUpdate();
} catch (Exception e) {
throw new Exception(e);
} finally {
DBUtil.executeClose(null, pstmt, conn);
}
}
package kr.member.action;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.codehaus.jackson.map.ObjectMapper;
import kr.controller.Action;
import kr.member.dao.MemberDAO;
import kr.util.FileUtil;
public class UpdateMyPhotoAction implements Action{
@Override
public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception {
Map<String, String> mapAjax = new HashMap<String, String>();
HttpSession session = request.getSession();
Integer user_num = (Integer)session.getAttribute("user_num");
if(user_num==null) { // 로그인 되지 않은 경우
mapAjax.put("result", "Logout");
return "redirect:/member/loginForm.do";
} else { // 로그인 된 경우
// 전송된 데이터 인코딩 타입 지정
request.setCharacterEncoding("UTF-8");
// 파일 업로드 처리
String photo = FileUtil.createFile(request, "photo");
MemberDAO dao = MemberDAO.getInstance();
// 프로필 사진 수정
dao.updateMyPhoto(photo, user_num);
// 이전 파일 삭제 처리
String user_photo = (String) session.getAttribute("user_photo");
FileUtil.removeFile(request, user_photo);
session.setAttribute("user_photo", photo);
mapAjax.put("result", "success");
}
ObjectMapper mapper = new ObjectMapper();
String ajaxData = mapper.writeValueAsString(mapAjax);
request.setAttribute("ajaxData", ajaxData);
return "/WEB-INF/views/common/ajax_view.jsp";
}
}
Script 추가
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>My Page</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100..900&display=swap" rel="stylesheet">
<script type="text/javascript" src="<%= request.getContextPath() %>/js/jquery-3.7.1.min.js"></script>
<script type="text/javascript">
$(function(){
$('#photo_btn').click(function(){
$('#photo_choice').show();
$(this).hide();
}); // end of Click
// 이미지 미리보기
let photo_path = $('.my-photo').attr('src'); // 처음 화면에 보여지는 이미지 읽기
$('#photo').change(function(){
let my_photo = this.files[0];
if(!my_photo){
// 선택을 취소하면 원래 처음 화면으로 되돌림
$('.my-photo').attr('src',photo_path);
return;
}
if(my_photo.size > 1024*1024){
alert(Math.round(my_photo.size/1024) + 'kbytes(1024kbytes까지만 업로드 가능)');
$('.my-photo').attr('src',photo_path);
$(this).val(''); // 선택한 파일 정보 지우기
return;
}
// 화면에 이미지 미리보기
const reader = new FileReader();
reader.readAsDataURL(my_photo);
reader.onload=function(){
$('.my-photo').attr('src',reader.result);
};
}); // end of Change
// 이미지 미리보기 취소
$('#photo_reset').click(function(){
// 초기 이미지 표시
$('.my-photo').attr('src',photo_path); // 이미지 미리보기 전 이미지로 되돌리기
$('#photo').val('');
$('#photo_choice').hide();
$('#photo_btn').show(); // 수정 버튼 표시
})
});
</script>
</head>
<body>
<div class="page-main">
<jsp:include page="/WEB-INF/views/common/header.jsp"/>
<div class="content-main">
<h2>My Page</h2>
<div class="mypage-div">
<h3>Profile Photo</h3>
<ul>
<li>
<c:if test="${empty member.photo}">
<img alt="profile photo" src="${pageContext.request.contextPath}/images/face.png"
width="200" height="200" class="my-photo">
</c:if>
<c:if test="${!empty member.photo}">
<img alt="profile photo" src="${pageContext.request.contextPath}/upload/${member.photo}"
width="200" height="200" class="my-photo">
</c:if>
</li>
<li>
<div class="align-center">
<input type="button" value="수정" id="photo_btn">
</div>
<div id="photo_choice" style="display: none;">
<input type="file" id="photo" accept="image/gif,image/png,image/jpeg">
<input type="button" value="전송" id="photo_submit">
<input type="button" value="취소" id="photo_reset">
</div>
</li>
</ul>
<h3>연락처 <input type="button" id="tel_btn" value="연락처 수정" onclick="location.href='modifyUserForm.do'"> </h3>
<ul>
<li>ID : ${member.id }</li>
<li>이름 : ${member.name }</li>
<li>전화번호 : ${member.phone }</li>
<li>E-mail : ${member.email }</li>
<li>우편번호 : ${member.zipcode }</li>
<li>주소 : ${member.address1} ${member.address2}</li>
<li>가입일 : ${member.reg_date }</li>
<c:if test="${!empty member.modify_date }">
<li>최근 정보 수정일 : ${member.modify_date }</li>
</c:if>
</ul>
<h3>비밀번호 수정</h3>
<h3>회원 탈퇴</h3>
</div>
<div class="mypage-div">
<h3>관심 게시물 목록</h3>
</div>
<div class="mypage-end">
</div>
</div>
</div>
</body>
</html>
MY PAGE 화면

profile photo의 수정 버튼 클릭시, 사진 수정 가능한 input[type="file"] 보여짐

다양한 의견들 제시하면서 어떤 프로젝트를 진행하면 좋을지 의논하다가 내가 낸 아이디어인
개발자들을 위한 팀 프로젝트 팀원 구하는 웹사이트를 만들기로 결정함
그래서 참고할만한 사이트들이 있을지 찾아보았음!
https://holaworld.io/
=> 프로젝트 인원 구하기, 스터디 구하기, 내가 생각한 사이트와 가장 유사함
https://bside.best/careercard
=> 조금 더 커리어 쪽에 집중되어 있는 느낌
https://www.beginmate.com/
=> IT 분야 외에도 많은 분야의 프로젝트도 진행함
https://letspl.me/people
=> 분야가 다양하고, 본인의 소개 개인과 채팅으로 소통 가능함
요구사항 정의서를 작성 시작함!