9:20 경 학원 도착
<9:30 1교시>
자바스크립트에서는 변수를 만들고 아무것도 변수에 전달하지 않으면 undefined가 들어있다.
그리고 매개변수에 값을 지정해서 전달하면 디폴트값을 설정할 수 있다.
<10:30 2교시>
session 영역에 있는 정보는 페이지를 닫거나 일정시간이 지나거나 강제로 종료하지 않으면 페이지가 이동해도 사라지지 않고 있음.
<%@page import="java.net.URLEncoder"%>
<%@page import="test.user.dto.SessionDto"%>
<%@page import="test.user.dao.UserDao"%>
<%@page import="test.user.dto.UserDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
// 1. 폼 전송되는 userName, password 를 읽어와서
String userName=request.getParameter("userName");
String password=request.getParameter("password");
//2. 아이디에 해당하는 회원정보를 userdao 객체를 이용해서 얻어와서
UserDto dto = UserDao.getInstance().getData(userName);
//3. 실제로 존재하는 아이디이고, 존재한다면 비밀번호도 일치하는지 비교해서
boolean isLoginSuccess=false;
if(dto!=null){
//비밀 번호 확인 해서
if(dto.getPassword().equals(password)){//비밀번호까지 일치한다면
//로그인 처리를 한다(로그인된 user 정보를 session 영역에 담는다 * 이외에도 프라이머리키, userName, role 정도를 담아두는 편이다.)
SessionDto sessionDto=new SessionDto();
sessionDto.setNum(dto.getNum());
sessionDto.setUserName(dto.getUserName());
sessionDto.setRole(dto.getRole());
//로그인 처리 해주기
session.setAttribute("sessionDto", sessionDto);
isLoginSuccess=true;
}
}
//로그인 후 가야할 목적지 정보
String url=request.getParameter("url");
//로그인 실패를 대비해서 목적지 정보를 인코딩한 결과도 준비한다
String encodedUrl=URLEncoder.encode(url, "UTF-8");
//일치하면 로그인 처리 후 응답, 일치하지 않으면 일치하지 않는다고 응답
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div class="container">
<%if(isLoginSuccess){%>
<p><strong><%=dto.getUserName() %></strong>님 로그인 되었습니다.</p>
<a href="<%=url%>">확인</a>
<%}else{ %>
<p>아이디 또는 비밀번호가 일치하지 않습니다.</p>
<a href="${pageContext.request.contextPath}/user/login-form.jsp?url=<%=encodedUrl%>">다시 입력</a>
<%} %>
</div>
</body>
</html>
세션 기반의 인증 처리를 배우는 중임.
나중에는 토큰 기반으로 하는데 모바일 앱이 토큰 기반인 경우가 많음.
폰에서 로그인이 풀리는 경우는 토큰의 유효가 만료돼서임. 토큰의 만료 조건은 다양함(장기 미접, 접속 횟수 등)
필터가 동작하는 조건 : @WebFilter({"/member-only/*", "/staff/*", "/admin/*","/user/protected/*"})
package test.filter;
import java.io.IOException;
import java.net.URLEncoder;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import test.user.dto.SessionDto;
@WebFilter({"/member-only/*", "/staff/*", "/admin/*","/user/protected/*"})
public class LoginFilter implements Filter{
//@WebFilter()에 명시한 패턴의 요청을 하면 아래의 메소드가 호출된다
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//매개변수에 전달된 객체를 이용해서 부모타입을 자식타입으로 캐스팅하여 객체의 참조값을 얻어낸다.
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//session 영역에서 로그인된 정보를 얻어내기 위한 객체
HttpSession session = req.getSession();
//세션 영역에 sessionDto 라는 키값으로 저장된 세션 값이 있으면 얻어내서 원래 type으로 캐스팅
SessionDto dto = (SessionDto) session.getAttribute("sessionDto");
//만일 로그인하지 않았다면
if (dto == null) {
//로그인 페이지로 리다이렉트 시키는 메소드를 호출해서 리다이렉트 시킴
redirectToLogin(req, res);
//메소드를 여기서 끝내기
return;
}
// Role-based authorization : role을 확인해서 /admin/*, /staff/* 요청도 필터링 해주는 역할
String role = dto.getRole();
String requestURI = req.getRequestURI();
if (requestURI.startsWith(req.getContextPath() + "/admin") && !"ADMIN".equals(role)) {
//금지된 요청이라고 응답한다(관리자만 쓰는거니까 에러페이지를 굳이 쓸 필요는 없음)
res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
return;
}
if (requestURI.startsWith(req.getContextPath() + "/staff") && !"STAFF".equals(role) && !"ADMIN".equals(role)) {
//금지된 요청이라고 응답한다(직원이 쓸 수 있는거)
res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
return;
}
// 여기까지 실행의 흐름이 넘어오면 요청의 흐름을 계속 이어간다(필터를 하지 않겠다는 것)Allow access for USER, STAFF, ADMIN
chain.doFilter(request, response);
}
//리다이렉트로 응답하는 메소드(요청을 새로운 경로로 다시 하라는 응답)
private void redirectToLogin(HttpServletRequest req, HttpServletResponse res) throws IOException {
//원래 요청 url을 읽어온다
String url = req.getRequestURI();
//혹시 뒤에 query parameter가 있다면 걔 역시 읽어온다. ?num=xxx&count=ccc
String query = req.getQueryString();
String encodedUrl = query == null ? URLEncoder.encode(url, "UTF-8") : URLEncoder.encode(url + "?" + query, "UTF-8");
//로그인 페이지로 리다이렉트 이동하면서 원래 가려던 목적지 정보도 같이 넘겨줌.
res.sendRedirect(req.getContextPath() + "/user/login-form.jsp?url=" + encodedUrl);
}
}
리다이렉트 : 요청을 다시하라는 서버의 해석 -> 웹브라우저가 클라이언트에게 요청하러 감
회원정보 수정 기능 추가하기
<11:30 3교시>
동기처리(주로 java)와 비동기처리(주로 javascript)
동기처리: 시간이 걸려도 순서대로 진행(멀티스레드)
String result = reader.read(대상);
System.out.println(result);
System.out.println("*****");
비동기처리: 일단 코드를 읽어서 실행하고 시간 걸리는걸 기다리지 않고 다음 실행을 이어감. 실행에 시간이 걸리는걸 자동으로 읽은 다음 전달함.(단일스레드) ->순서가 정해진게 아님: 작업의 순서를 정하고 싶을 때는 함수의 안으로 집어넣게 됨(나중에 호출되는 함수는 콜백 함수라는 개념도 있음 -> 콜백 지옥->이걸 해결하는 방법은 나중에 배운다고 한다: 프로미스 ?->fetch 함수가 then then then 쓰는 프로미스로 우리도 썼긴함)
reader.read(대상)
reader.onload=(result)=}{
console.log(result);
}
console.log("*****");
<12:30 4교시>
오늘 한 것 중에서 변경된거랑 추가된 거 백업
UpdateForm
<%@page import="test.user.dto.UserDto"%>
<%@page import="test.user.dao.UserDao"%>
<%@page import="test.user.dto.SessionDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
//session에 저장된 정보를 이용해서
SessionDto sessionDto=(SessionDto)session.getAttribute("sessionDto");
//DB 에 저장된 회원 번호로 회원 정보(UserDto)를 얻어와서
UserDto dto=UserDao.getInstance().getData(sessionDto.getNum());
//회원정보 수정 폼을 응답한다.
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/user/protected/update-form.jsp</title>
<style>
#profileImage{
width: 100px;
height: 100px;
border: 1px solid #cecece;
border-radius: 50%;
}
#profileFile{
display: none;
}
</style>
</head>
<body>
<div class="container">
<h3>회원 정보 수정 양식</h3>
<form action="${pageContext.request.contextPath }/user/protected/update-profile"
method="post" id="myForm" enctype="multipart/form-data">
<input type="file" name="profileFile" id="profileFile" accept="image/*"/>
<div>
<label for="id">아이디</label>
<input type="text" id="id" value="<%=dto.getUserName() %>" readonly/>
</div>
<div>
<label for="email">이메일</label>
<input type="text" id="email" name="email" value="<%=dto.getEmail()%>"/>
</div>
<div>
<label>프로필 이미지</label>
<div>
<a href="javascript:" id="profileLink">
<%if(dto.getProfileImage()==null){ %>
<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" fill="currentColor" class="bi bi-person-circle" viewBox="0 0 16 16">
<path d="M11 6a3 3 0 1 1-6 0 3 3 0 0 1 6 0z"/>
<path fill-rule="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>
<%}else{ %>
<img id="profileImage" src="${pageContext.request.contextPath}/upload/<%=dto.getProfileImage() %>" alt="프로필 이미지" />
<%} %>
</a>
</div>
</div>
<button type="submit">수정확인</button>
<button type="reset">취소</button>
</form>
</div>
<script>
//프로필 이미지 출력란에 원래 있었던 html 을 변수에 담아 두었다가
const saved=document.querySelector("#profileLink").innerHTML;
//취소 버튼을 누르면
document.querySelector("#myForm").addEventListener("reset", ()=>{
//변수에 담아둔 내용을 이용해서 원상복구 시킨다.
document.querySelector("#profileLink").innerHTML=saved;
});
//링크를 클릭했을때
document.querySelector("#profileLink").addEventListener("click", ()=>{
// input type="file" 요소를 강제 클릭해서 파일 선택 창을 띄운다.
document.querySelector("#profileFile").click();
});
//새로운 이미지가 선택되었을때
document.querySelector("#profileFile").addEventListener("change", (e)=>{
console.log("hi")
//선택된 파일 배열 객체를 얻어낸다.
const files = e.target.files;
//만일 파일 데이터가 존재한다면
if(files.length > 0){
//파일로 부터 데이터를 읽어들일 객체 생성
const reader=new FileReader();
//로딩이 완료(파일데이터를 모en 읽었을때) 되었을때 실행할 함수 등록
reader.onload=(event)=>{
//읽은 파일 데이터 얻어내기
const data=event.target.result;
const img=`<img src="\${data}" id="profileImage" alt="프로필이미지">`;
document.querySelector("#profileLink").innerHTML=img;
};
//파일을 DataURL 형식의 문자열로 읽어들이기
reader.readAsDataURL(files[0]);
}
});
</script>
</body>
</html>
LoginFilter
package test.filter;
import java.io.IOException;
import java.net.URLEncoder;
import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;
import test.user.dto.SessionDto;
@WebFilter({"/member-only/*", "/staff/*", "/admin/*","/user/protected/*"})
public class LoginFilter implements Filter{
//@WebFilter()에 명시한 패턴의 요청을 하면 아래의 메소드가 호출된다
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
//매개변수에 전달된 객체를 이용해서 부모타입을 자식타입으로 캐스팅하여 객체의 참조값을 얻어낸다.
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
//session 영역에서 로그인된 정보를 얻어내기 위한 객체
HttpSession session = req.getSession();
//세션 영역에 sessionDto 라는 키값으로 저장된 세션 값이 있으면 얻어내서 원래 type으로 캐스팅
SessionDto dto = (SessionDto) session.getAttribute("sessionDto");
//만일 로그인하지 않았다면
if (dto == null) {
//로그인 페이지로 리다이렉트 시키는 메소드를 호출해서 리다이렉트 시킴
redirectToLogin(req, res);
//메소드를 여기서 끝내기
return;
}
// Role-based authorization : role을 확인해서 /admin/*, /staff/* 요청도 필터링 해주는 역할
String role = dto.getRole();
String requestURI = req.getRequestURI();
if (requestURI.startsWith(req.getContextPath() + "/admin") && !"ADMIN".equals(role)) {
//금지된 요청이라고 응답한다(관리자만 쓰는거니까 에러페이지를 굳이 쓸 필요는 없음)
res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
return;
}
if (requestURI.startsWith(req.getContextPath() + "/staff") && !"STAFF".equals(role) && !"ADMIN".equals(role)) {
//금지된 요청이라고 응답한다(직원이 쓸 수 있는거)
res.sendError(HttpServletResponse.SC_FORBIDDEN, "Access denied.");
return;
}
// 여기까지 실행의 흐름이 넘어오면 요청의 흐름을 계속 이어간다(필터를 하지 않겠다는 것)Allow access for USER, STAFF, ADMIN
chain.doFilter(request, response);
}
//리다이렉트로 응답하는 메소드(요청을 새로운 경로로 다시 하라는 응답)
private void redirectToLogin(HttpServletRequest req, HttpServletResponse res) throws IOException {
//원래 요청 url을 읽어온다
String url = req.getRequestURI();
//혹시 뒤에 query parameter가 있다면 걔 역시 읽어온다. ?num=xxx&count=ccc
String query = req.getQueryString();
String encodedUrl = query == null ? URLEncoder.encode(url, "UTF-8") : URLEncoder.encode(url + "?" + query, "UTF-8");
//로그인 페이지로 리다이렉트 이동하면서 원래 가려던 목적지 정보도 같이 넘겨줌.
res.sendRedirect(req.getContextPath() + "/user/login-form.jsp?url=" + encodedUrl);
}
}
UpdateProfileServlet
package test.servlet;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.UUID;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.MultipartConfig;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.Part;
import test.user.dao.UserDao;
import test.user.dto.SessionDto;
import test.user.dto.UserDto;
@WebServlet("/user/protected/update-profile")
@MultipartConfig(
fileSizeThreshold = 1024*1024*5, // 메모리 임계값
maxFileSize = 1024*1024*50, //최대 파일 사이즈
maxRequestSize = 1024*1024*60 //최대 요청 사이즈
)
public class UpdateProfileServlet extends HttpServlet{
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
SessionDto sessionDto=(SessionDto)req.getSession().getAttribute("sessionDto");
UserDto dto=UserDao.getInstance().getData(sessionDto.getNum());
//이미 저장된 프로필 이미지가 있는지 여부 -> 이미 저장된걸 삭제하기 위해서 알아놓는 정보
boolean hasProfileImage= dto.getProfileImage() == null ? false : true;
String email=req.getParameter("email");
dto.setEmail(email);
//업로드될 실제 경로 얻어내기
String uploadPath=this.getServletContext().getRealPath("/upload");
File uploadDir = new File(uploadPath);
//만일 upload 폴더가 존재 하지 않으면
if(!uploadDir.exists()) {
uploadDir.mkdir(); //실제로 폴더 만들기
}
String orgFileName=null;
String saveFileName=null;
//파일 데이터 처리
Part filePart = req.getPart("profileFile");
//만일 업로드된 프로필 이미지가 있다면
if(filePart != null && filePart.getSize() > 0) {
//원본 파일의 이름 얻어내기
orgFileName=filePart.getSubmittedFileName();
//파일명이 겹치지 않게 저장하기 위한 랜덤한 문자열 얻어내기
String uid = UUID.randomUUID().toString();
//저장될 파일의 이름 구성하기
saveFileName=uid+orgFileName;
//저장할 파일의 경로 구성하기
String filePath=uploadPath + File.separator + saveFileName;
/*
* 업로드된 파일은 임시 폴더에 임시 파일로 저장이 된다.
* 해당 파일에서 byte 알갱이를 읽어 들일수 있는 InputStream 객체를 얻어내서
*/
InputStream is=filePart.getInputStream();
// 원하는 목적지에 copy 를 해야 한다
Files.copy(is, Paths.get(filePath));
//기존에 업로드 파일이 있다면 기존 파일을 삭제한다.
if(hasProfileImage) {
String deleteFilePath=uploadPath + File.separator+dto.getProfileImage();
new File(deleteFilePath).delete();
}
//새롭게 업로드된 파일의 이름을 dto 에 담는다.
dto.setProfileImage(saveFileName);
//여기서는 프로필 이미지를 수정해야한다.
UserDao.getInstance().updateEmailProfile(dto);
}else {//선택한 프로필 이미지가 없는 경우
//여기서는 프로필 이미지가 수정되면 안된다.
UserDao.getInstance().updateEmail(dto);
}
String cPath=req.getContextPath();
resp.sendRedirect(cPath+"/user/protected/info.jsp");
}
}
UserDao
package test.user.dao;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import test.user.dto.UserDto;
import test.util.DbcpBean;
public class UserDao {
//자신의 참조값을 저장할 static 필드
private static UserDao dao;
//static 초기화 블럭 (이클래스가 최초로 사용될때 오직 한번만 수행된다)
static {
//객체를 생성해서 static 필드에 담는다.
dao=new UserDao();
}
//외부에서 객체 생성하지 못하도록 생성자의 접근 지정자를 private 로 설정
private UserDao() {}
//static 필드에 저장된 GuestDao 의 참조값을 리턴해주는 static 메소드
public static UserDao getInstance() {
return dao;
}
public boolean updateEmailProfile(UserDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 미완성의 sql 문
String sql = """
UPDATE users
SET email=?, profileImage=?, updatedAt=SYSDATE
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값을 여기서 바인딩한다.
pstmt.setString(1, dto.getEmail());
pstmt.setString(2, dto.getProfileImage());
pstmt.setLong(3, dto.getNum());
// sql 문 실행하고 변화된 row 의 갯수 리턴받기
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
public boolean updateEmail(UserDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 미완성의 sql 문
String sql = """
UPDATE users
SET email=?, updatedAt=SYSDATE
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값을 여기서 바인딩한다.
pstmt.setString(1, dto.getEmail());
pstmt.setLong(2, dto.getNum());
// sql 문 실행하고 변화된 row 의 갯수 리턴받기
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
public UserDto getData(String userName) {
UserDto dto=null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Connection Pool 로 부터 Connection 객체 하나 가져오기
conn = new DbcpBean().getConn();
//실행할 sql 문 작성
String sql = """
SELECT num, password, email, role, profileImage, createdAt, updatedAt
FROM users
WHERE userName=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값 바인딩할게 있으면 여기서 하기
pstmt.setString(1, userName);
//sql 문 실행하고 결과를 ResultSet 객체로 리턴받기
rs = pstmt.executeQuery();
if (rs.next()) {
dto=new UserDto();
dto.setNum(rs.getLong("num"));
dto.setUserName(userName);
dto.setPassword(rs.getString("password"));
dto.setEmail(rs.getString("email"));
dto.setRole(rs.getString("role"));
dto.setProfileImage(rs.getString("profileImage"));
dto.setCreatedAt(rs.getString("createdAt"));
dto.setUpdatedAt(rs.getString("updatedAt"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return dto;
}
public UserDto getData(long num) {
UserDto dto=null;
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Connection Pool 로 부터 Connection 객체 하나 가져오기
conn = new DbcpBean().getConn();
//실행할 sql 문 작성
String sql = """
SELECT userName, password, email, role, profileImage, createdAt, updatedAt
FROM users
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값 바인딩할게 있으면 여기서 하기
pstmt.setLong(1, num);
//sql 문 실행하고 결과를 ResultSet 객체로 리턴받기
rs = pstmt.executeQuery();
if (rs.next()) {
dto=new UserDto();
dto.setNum(num);
dto.setUserName(rs.getString("userName"));
dto.setPassword(rs.getString("password"));
dto.setEmail(rs.getString("email"));
dto.setRole(rs.getString("role"));
dto.setProfileImage(rs.getString("profileImage"));
dto.setCreatedAt(rs.getString("createdAt"));
dto.setUpdatedAt(rs.getString("updatedAt"));
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (rs != null)
rs.close();
if (pstmt != null)
pstmt.close();
if (conn != null)
conn.close();
} catch (Exception e) {
}
}
return dto;
}
public boolean insert(UserDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
// 실행할 SQL 문 작성
String sql = """
INSERT INTO users
(num, userName, password, email)
VALUES (users_seq.NEXTVAL, ?, ?, ?)
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값을 여기서 바인딩한다.
pstmt.setString(1, dto.getUserName());
pstmt.setString(2, dto.getPassword());
pstmt.setString(3, dto.getEmail());
// sql 문 실행하고 변화된 row 의 갯수 리턴받기
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
public boolean update(UserDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 미완성의 sql 문
String sql = """
UPDATE users
SET email=?, profileImage=?, updatedAt=SYSDATE
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값을 여기서 바인딩한다.
pstmt.setString(1, dto.getEmail());
pstmt.setString(2, dto.getProfileImage());
pstmt.setLong(3, dto.getNum());
// sql 문 실행하고 변화된 row 의 갯수 리턴받기
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
public boolean updatePassword(UserDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 미완성의 sql 문
String sql = """
UPDATE users
SET password=?, updatedAt=SYSDATE
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값을 여기서 바인딩한다.
pstmt.setString(1, dto.getPassword());
pstmt.setLong(2, dto.getNum());
// sql 문 실행하고 변화된 row 의 갯수 리턴받기
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
public boolean updateRole(UserDto dto) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 미완성의 sql 문
String sql = """
UPDATE users
SET role=?, updatedAt=SYSDATE
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값을 여기서 바인딩한다.
pstmt.setString(1, dto.getRole());
pstmt.setLong(2, dto.getNum());
// sql 문 실행하고 변화된 row 의 갯수 리턴받기
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
public boolean delete(long num) {
Connection conn = null;
PreparedStatement pstmt = null;
int rowCount = 0;
try {
conn = new DbcpBean().getConn();
//실행할 미완성의 sql 문
String sql = """
DELETE FROM users
WHERE num=?
""";
pstmt = conn.prepareStatement(sql);
// ? 에 값을 여기서 바인딩한다.
pstmt.setLong(1, num);
// sql 문 실행하고 변화된 row 의 갯수 리턴받기
rowCount = pstmt.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (conn != null)
conn.close();
if (pstmt != null)
pstmt.close();
} catch (Exception e) {
}
}
if (rowCount > 0) {
return true;
} else {
return false;
}
}
}
pwd-update-form
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/user/protected/pwd-update-form.jsp</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-T3c6CoIi6uLrA9TneNEoa7RxnatzjcDSCmG1MXxSR1GAsXEV/Dwwykc2MPK8M2HN" crossorigin="anonymous">
</head>
<body>
<div class="container" id="app">
<h1>비밀 번호 수정 페이지</h1>
<form action="pwd-update.jsp" method="post" id="myForm">
<div class="mb-2">
<label class="form-label" for="password">기존 비밀번호</label>
<input class="form-control"
@input="onPwdInput"
:class="{'is-invalid': !isPwdValid && isPwdDirty, 'is-valid':isPwdValid}" type="password" name="password" id="password"/>
<div class="invalid-feedback">반드시 입력하세요</div>
</div>
<div class="mb-2">
<label class="form-label" for="newPwd">새 비밀번호</label>
<input class="form-control" type="password" name="newPassword" id="newPassword"
@input="onNewPwdInput"
v-model="newPassword"
:class="{'is-invalid': !isNewPwdValid && isNewPwdDirty, 'is-valid':isNewPwdValid}"/>
<small class="form-text">반드시 입력하고 아래의 확인란과 동일해야 합니다</small>
<div class="invalid-feedback">새 비밀번호를 확인하세요</div>
</div>
<div class="mb-2">
<label class="form-label" for="newPassword2">새 비밀번호 확인</label>
<input class="form-control" type="password" id="newPassword2"
@input="onNewPwdInput" v-model="newPassword2"/>
</div>
<button class="btn btn-success" type="submit" :disabled="!isPwdValid || !isNewPwdValid">수정하기</button>
<button class="btn btn-danger" type="reset">리셋</button>
</form>
</div>
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<script>
new Vue({
el:"#app",
data:{
isPwdValid:false,
isNewPwdValid:false,
newPassword:"",
newPassword2:"",
isPwdDirty:false, //비밀번호 입력란에 한번이라도 입력했는지 여부
isNewPwdDirty:false //새비밀번호 입력한에 한번이라도 입력했는지 여부
},
methods:{
onPwdInput(e){
//현재까지 입력한 비밀번호
const pwd=e.target.value;
//공백이 아닌 한글자가 한번이상 반복 되어야 통과 되는 정규표현식
const reg_pwd=/[\S]+/;
if(reg_pwd.test(pwd)){
this.isPwdValid=true;
}else{
this.isPwdValid=false;
}
this.isPwdDirty=true;
},
onNewPwdInput(){
//공백이 아닌 글자를 하나이상 입력했는지 확인할 정규 표현식
const reg_pwd=/[\S]+/;
//만일 정규표현식도 통과하고 그리고 두개의 비밀번호가 같다면
if(reg_pwd.test(this.newPassword) && (this.newPassword === this.newPassword2)){
//새 비밀번호 유효성 여부를 true 로 변경
this.isNewPwdValid = true;
}else{//그렇지 않다면
//새 비밀번호 유효성 여부를 false 로 변경
this.isNewPwdValid = false;
}
this.isNewPwdDirty=true;
}
}
});
</script>
</body>
</html>
pwd-update
<%@page import="test.user.dto.UserDto"%>
<%@page import="test.user.dao.UserDao"%>
<%@page import="test.user.dto.SessionDto"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
SessionDto sessionDto=(SessionDto)session.getAttribute("sessionDto");
long num=sessionDto.getNum();
//폼 전송되는 구 비밀번호, 새 비밀번호 읽어오기
String password=request.getParameter("password");
String newPassword=request.getParameter("newPassword");
//작업의 성공여부
boolean isSuccess=false;
//현재 비밀번호
String currentPwd = UserDao.getInstance().getData(num).getPassword();
//만일 현재 비밀번호하고 입력한 비밀번호와 같으면
if(currentPwd.equals(password)){
//수정 작업을 진행
UserDto dto=new UserDto();
dto.setNum(sessionDto.getNum());
dto.setPassword(newPassword);
isSuccess=UserDao.getInstance().updatePassword(dto);
}
//만일 비밀번호 수정 성공이면
if(isSuccess){
//로그아웃 처리
session.invalidate();
}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>/user/private/pwd-update.jsp</title>
</head>
<body>
<div class="container">
<%if(isSuccess){ %>
<p>
비밀 번호를 수정하고 로그 아웃되었습니다.
<a href="${pageContext.request.contextPath }/user/login-form.jsp">다시 로그인</a>
</p>
<%}else{ %>
<p>
구 비밀번호가 일치하지 않습니다.
<a href="${pageContext.request.contextPath }/user/protected/pwd-update-form.jsp">다시 시도</a>
</p>
<%} %>
</div>
</body>
</html>
'공부의 기록 > 자바 풀 스택 : 수업내용정리' 카테고리의 다른 글
자바 풀 스택 1/23 오후 기록 044-2 (1) | 2025.01.23 |
---|---|
자바 풀 스택 1/22 오후 기록 043-2 (1) | 2025.01.22 |
자바 풀 스택 1/22 오전 기록 043-1 (1) | 2025.01.22 |
자바 풀 스택 1/21 오후 기록 042-2 (1) | 2025.01.21 |
자바 풀 스택 1/20 오후 기록 041-2 (2) | 2025.01.20 |