본문 바로가기
WEB/✿JSP

[JSP] 🔗/MVC (2) 실습

by W_W_Woody 2022. 1. 25.

mvcBoard Dynamic Web Project>

1. 모델클래스 만들기 (servlet이 모델클래스를 먼저호출)
2. view 만들기
3. ActionMap.properties 에 정보를 넣어준다
(Key와 Value의 쌍으로 / 요청url과 모델클래스)
4.

MVC

다이나믹 웹 프로젝트를 새로 생성하고

생성 시 꼭 체크해주기

JavaSE 버전을 맞춰준다.

ojdbc8.jar 파일을 WEB-INF/lib파일에 넣어준다. (데이터베이스 연동을 하려면 ojdbc8.jar가 꼭 필요!)

 * SQL문과 DB사이에 매개가 되는게 JDBC이다. 드라이버는 Java문법이 적용되서 만들어진 프로그램인데 ORACLE에서 배포하며 .jar 확장자로 압축된 형태이다. 그래서 jdbc드라이버가 꼭 있어야한다.

DispatcherServlet.java 에서 직접 넣지않는다. 즉 Servlet에 access안한다. 

이 부분을 설정파일로 보내서 일정방식으로 명시하여 사용할 수 있도록 한다.

xml로 설정파일로 만들면 복잡해지므로 간단하게 key와 value의 쌍으로 설정할 수 있는 property 방식을 사용해본다.

src/main/java/kr.controller.(패키지)/ 

▼Action.java

더보기
package kr.controller;

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

public interface Action {
//추상메서드를 구현 (하나만 쓰도록)
//추상클래스 또는 인터페이스로 하나의 기준을 주는 것이다.
	
	public String execute(HttpServletRequest request, HttpServletResponse responsee)
							throws Exception;
}

DispatcherServlet.java
0.00MB

 

 

Action.java파일과 DispatcherServlet.java 파일을 넣어준다.

src/main/webapp/WEB-INF/lib / ~.jar 

jstl-1.2.jar
0.40MB
ojdbc8.jar
4.19MB

 

 

jstl.jar 파일과 ojdcbc8.jar 파일을 넣어준다.

 

src/main/webapp/WEB-INF/web.xml 

servlet을 사용해야하는데 매핑을 걸어야한다. web.xml에서 매핑을 걸어주자.

<url-pattern>끝에 만들어질 주소를 명시하고

<servlet-class>그 주소가 호출하는 파일 경로를 상단부터 작성한다.

<init-param>를 작성하고 하위에

<param-name>식별자를 작성한다(이 식별자를 통해 정보를 읽어서 servlet에 전달을 한다.)  

<param-value>설정파일 상단부터 작성한다. /WEB-INF/ActionMap.properties

 

ActionMap.properties 파일을 생성한다.

이 파일이 위에서 말했던 설정 파일이여서 클라이언트가 요청했을 때 어떤 모델클래스를 생성해야 할 지를 명시해준다.

그럼 그 모델클래스를 생성하여 사용한다.

 

src/main/webapp/WEB-INF/ActionMap.properies 

확장자 가이드가 없어서 File로 만든다.

주석은 # 사용

한글을 명시하면 자동으로 유니코드로 바뀌기 때문에 플러그인을 설치해야 한글을 볼 수 있다.

 

▼ 플러그인 (스프링에는 내장되어 있어서 별도로 설치할 필요 없음)

더보기
properties검색하기

SimpleProperitesEditor를 이용해서 보면 한글을 확인할 수 있다.

* WEB-INF/ActionMap.properties 원본 파일과

플러그인으로 연 창을 동시에 띄웠을 경우 저장 에러가 발생하기도 하므로

플러그인으로 연 창을 꺼주고 DispatcherServlet.java를 실행시켜준다. 


 

키와 밸류의 쌍으로 되어있다. 데이터를 만들고 데이터를 처리하게 한다.

 

 

src/main/webapp/index.jsp 

jsp실행, servlet연동실행 테스트를 해보자.

테스트 할 문자를 넣고 실행시켜보자.


매번 DispatcherServlet을 동작시켜서 *.do 라고 나오면 직접 list.do로 바꾸는 것이 아니라

indext.jsp 를 호출한다. 그렇게 되면 대문페이지인 list.do를 보여준다.

<% response.sendRedirect(request.getContextPath()+"/list.do"); %>

Servlet을 진입해야해서 DispatcherServlet.java을 호출해야 하는데,

호출하면 화면이 xml에서 매핑이 되어있기 때문에 list.do가 아니라 *.do 를 찾는다

그것이 에러가 나서 직접 list.do로 고치는 작업을 수행했었는데,

편리하게 사용하기위해서 index.jsp에서 Redirect기법을 쓴 것이다.

src/main/webapp/sql/table.sql 

백업용 sql파일을 만들고, SQL Developer 에서 TABLE과 SEQUENCE를 생성한다.

CREATE TABLE sboard(
   num number primary key, 
   title varchar2(150) not null,
   name varchar2(30) not null,
   passwd varchar2(12) not null,
   content clob not null,
   ip varchar2(50) not null,
   reg_date date not null
);
CREATE SEQUENCE sboard_seq;

- PRIMARY KEY  : UNIQUE제약조건, NOT NULL제약조건이 같이 들어간다.

시퀀스 수가 너무 올라가서 1부터 실행하고 싶다면

DROP SEQUENCE sboard_seq;  실행 후에 CREATE SEQUENCE sboard_seq; 한다.


src/main/java/kr.board.action(패키지)/ListAction.java 


src/main/webapp/WEB-INF/view/list.jsp 

호출할 때 모델클래스를 거쳐야 되는데 jsp에서 호출하면 안돼니까 클라이언트가 직접 jsp를 호출 할 수 없게끔 파일위치를 WEB-INT 밑으로 설정한다.

(jsp는 HTML을 만들고 HTML을 전송)
 * WEB-INT는 설정할 수 있는 공간이기 때문에 클라이언트가 직접 호출을 못하는 곳이고, forward방식으로만 호출이 된다
 * webapp밑에 넣어야 호출할 수 있음

기존에 <%= request.getContextPath() %> 표현식으로 사용한 것을 EL로 처리하여

<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css"> 작성한다.


 

src/main/webapp/css/layout.css 

css는 호출이 가능하게 webapp밑에 생성한다.


 

src/main/java/kr.board.action(패키지)/WriteFormAction.java  :  글 작성Form모델

implemnets

모델클래스는 데이터를 셋팅하지만 Form에는 데이터 셋팅할게 없다면 JSP경로만 반환한다

return "/WEB-INF/views/writeForm.jsp"


src/main/java/WEB-INF/views/writeForm.jsp  :  글 작성Form

css링크 해주고  UI작업 하고 유효성체크도 해준다.

유효성 체크도 링크걸어서 작업해주는 편이 좋을 수 있다

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>글쓰기</title>
<link rel="stylesheet" href="${pageContext.request.contextPath}/css/layout.css">
<script type="text/javascript">
	window.onload = function() {
		var myForm = document.getElementById('register_form');
		//이벤트연결
		myForm.onsubmit=function(){
			var title = document.getElementById('title');
			if(title.value.trim()==''){
				alert('제목을 입력하세요!');
				title.focus();
				title.value= '';
				return false;
			}
			var name = document.getElementById('name');
			if(name.value.trim()==''){
				alert('이름을 입력하세요!');
				name.focus();
				name.value= '';
				return false;
			}
			var passwd = document.getElementById('passwd');
			if(passwd.value.trim()==''){
				alert('비밀번호를 입력하세요!');
				passwd.focus();
				passwd.value= '';
				return false;
			}
			var comtent = document.getElementById('comtent');
			if(comtent.value.trim()==''){
				alert('내용을 입력하세요!');
				comtent.focus();
				comtent.value= '';
				return false;
			}
		}
	}
</script>
</head>
<body>
<div class="page-main">
	<h2>글쓰기</h2>
	<form id="register_form" action="write.do" method="post">
		<ul>
			<li>
				<label for="title">제목</label>
				<input type="text" name="title" id="title" size="30" maxlength="30"> 
			</li>
			<li>
				<label for="name">이름</label>
				<input type="text" name="name" id="name" size="10" maxlength="10"> 
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input type="password" name="passwd" id="passwd" size="12" maxlength="12"> 
			</li>
			<li>
				<label for="content">내용</label>
				<textarea rows="5" cols="40" name="content" id="content"></textarea>
			</li>
			
		</ul>
		<div class="align-center">
			<input type="submit" value="글쓰기">
			<input type="button" value="목록" onclick="location.href='list.do'">
		</div>
	</form>
</div>
</body>
</html>

ActionMap.properies설 정파일에 경로를 지정해준다.

/writeForm.do=kr.board.action.WriteFormAction


src/main/java/kr.board.vo(패키지)/BoardVO.java

컬럼명과 일치하는 VO(자바빈)를 만든다.

 

VO역할을 하는 클래스이므로  (컬럼명과 일치시켜서) private한 프로퍼티(≒멤버변수) 를 만들고.

 

이 때 private Date reg_date; 변수는 데이터베이스에 연동하기 때문에

import java.util.Date; 를 사용하는 것이 아니라, import java.sql.Date; 를 사용한다.

 

gertters, settters를 만들어준다.

▼ code

생성된 get메서드/set메서드 와 프로퍼티 사이에 필요한 메서드를 생성할 수 있다. 

 

로그인을 할 것이기 때문에 비밀번호를 체크하는 메서드를 만들어보자

//비밀번호 체크
public boolean isCheckedPassword(String userPasswd) {
    if(passwd.equals(userPasswd)) { //비밀번호 일치
        return true;
    }
    return false; //비밀번호 불일치
}

private String passwd;

 

if(passwd.equals(userPasswd))

DB에 있는 비밀번호

사용자가 입력한 비밀번호


src/main/java/kr.board.dao(패키지)/BoardDAO.java

싱글톤 패턴을 만들어준다. 싱글톤 패턴을 구현하기 위해서는

 

static한 변수를 만들어서 그걸 통해 객체가 생성되게 한다.

private static BoardDAO instance = new MemberDAO();

(instance) 가 최초 호출되면 객체( new MemberDAO(); )가 생성이 되는데 계속 호출되더라도 기존에 있는 객체를 계속 사용한다.

 

그렇게 재활용을 하기 위해서 외부에서 호출을 해야하니까 public한 메서드도 만든다.

public static BoardDAO getInstance() {

   return instance ;  

 

생성자를 직접 호출 할 수 없게 private하게 만든다.(외부X, 내부에서만 호출할 수 있게)

private MemberDAO() {}

싱글톤패턴

DAO 만들 때 가장 적합한 패턴 = 싱글톤 패턴(Singleton Pattern )

생성자를  외부에서 호출할 수 없도록 private으로 지정해서 처리하고
static 메서드를 호출해서 객체가 한 번만 생성되고 생성된 객체를 공유할 수 있도록 처리하는 방식을 의미한다. 
* 메모리 관리 차원에서 효율적

∴ 멤버변수가 없는 경우(DAO)에는  메서드만 있기 때문에 객체를 하나만 만들고 재활용하여 서버에 부담을 줄이기 위해 싱글톤 패턴을 만들어서 활용을 한다.

JSP/SERVLET 이용 시 싱글톤 패턴을 사용한다.

VO에 있는 멤버변수는 매번 객체 생성해서 쓰는 반면에

DAO는 멤버변수를 가지고 있지 않고 메서드 단위로 동작을 한다. 그렇기 때문에  공유가 가능하다.

(객체를 여러개 만들면 부하가 걸리므로 계속 호출 되어도 하나의 객체만 반환하게 한다.  →  Singleton Pattern  ) 

 

 

DAO에서는 커넥션 풀을 이용 할건데, 커넥션 풀을 사용하여 정보를 읽어오려면 설정 파일(context.xml)이 필요하다.

META-INF 에 context.xml파일을 넣어준다.  [JSP] 🔗JDBC와 커넥션 풀

▼ context.xml파일

더보기
<?xml version="1.0" encoding="UTF-8"?>
<Context>
     <Resource name="jdbc/xe" →  DAO에서 읽어올 명칭
              auth="Container"  → Container를 자원관리자로 기술
              type="javax.sql.DataSource"  →  반환 타입은 javax.sql.DataSource으로 
              username="scott"
              password="tiger"
              driverClassName="oracle.jdbc.OracleDriver"
              url="jdbc:oracle:thin:@localhost:1521:xe"
              maxTotal="20"  → 톰캣이 제공하는 커넥션 풀에서 생성되는 최대 커넥션 숫자를 명시
              maxIdle="10" />  →   데이터베이스 연동이 없더라도 커넥션 풀 유지를 위한 최대 대기커넥션 숫자
</Context>

이제, (JNDI 방식으로) context.xml의 정보를 읽어와서 커넥션 풀로부터 커넥션을 할당받아 작업을 해보자.

 

동작하면 커넥션을 반환하게하는, 내부에서만 호출되는 메서드를 만든다.

private Connection getConnection()throws Exception{ 

 

context.xml의 정보를 읽어올 때는 Context객체를 생성해야한다.

   Context initCtx = new InitialContext();

 * javax.naming으로 Context와 InitialContext에 import해야한다. 

  import javax.naming.Context;

  import javax.naming.InitialContext;

 

context.xml 정보를 읽어올 수 있게 됐으니, 이제 이 getConnection()메서드를 이용해서 context.xml의 <Resource />를 찾아서(찾는메서드 = .lookup) 데이터 소스를 반환해준다.

   DataSource ds = (DataSource)initCtx.lookup("java:comp/env/jdbc/xe");

 * javax,sql로 DataSource를 import 해준다.

  import javax.sql.DataSource;

식별자를 넣을 때는 그냥 식별자만 넣으면 검색을 못하고 앞에 전체적인 서비스명을 붙여줘야 하는데, 전체적인 서비스명은java:comp/env/  로 고정되어있다.

(대한민국의/ 김연아 이런느낌)

 

이제 데이터 소스가 커넥션풀에 접근해서 커넥션을 반환해준다.

return ds.getConnection();

 

∴getConnection() 메서드만 호출하면 커넥션 풀로 부터 커넥션을 할당받을 수 있다!

→ JDBC 1단계, 2단계를 수행한 게 된다 !

 

자원정리도 빼먹지않고 해준다.

 

순서에맞게끔 데이터를 처리해준다

데이터베이스에 연동할 메서드들을 생 성 할 예정이다.

◎글 저장

◎글 총 갯수

◎목록

◎글 상세 정보

글 삭제

 

◎ 글 저장 insert(BoardVO boardvo)

▼code

더보기
//글 저장
	public void insert(BoardVO boardVO)throws Exception{
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		try {
			//num,title,name,passwd,content,ip,reg_date
			conn = getConnection(); //커넥션 풀로 부터 커넥션을 할당
			sql = "INSERT INTO sboard (num,title,name,passwd,content,ip,reg_date)"
					+ "VALUES(sboard_seq.nextval,?,?,?,?,?,SYSDATE)";
			pstmt = conn.prepareStatement(sql); //PreparedStatement객체 생성
			//?에 바인딩
			pstmt.setString(1, boardVO.getTitle());
			pstmt.setString(2, boardVO.getName());
			pstmt.setString(3, boardVO.getPasswd());
			pstmt.setString(4, boardVO.getContent());
			pstmt.setString(5, boardVO.getIp());
			pstmt.executeUpdate(); //SQL문 실행
		} catch (Exception e) {
			throw new Exception(e);
		}finally { //자원 정리
			executeClose(null, pstmt, conn);
		}
	}

pstmt.executeUpdate(); 는 메서드의 반환 값은 해당 SQL 문 실행에 영향을 받는 행 수를 반환합니다
pstmt.executeQuery();Select 문에서만 실행, 데이터베이스에서 데이터를 가져와서 결과 집합을 반환합니다.

 

이제 WriteAction 을 작성한다.


◎ 글의 총 갯수 getCount()

sql의 테이블명만 바뀌고, 나머지코드는 거의 항상 똑같음! 패턴화

▼code

더보기
//글의 총 갯수
   public int getCount() throws Exception{
            Connection conn = null;
            PreparedStatement pstmt = null;
            ResultSet rs = null;
            String sql = null;

            int count = 0;
            try {
                conn = getConnection(); //커넥션 풀로 부터 커넥션을 할당
                sql = "SELECT COUNT(*) FROM sboard"; //SQL문 작성
                pstmt = conn.prepareStatement(sql); //PreparedStatement 객체 생성
                rs = pstmt.executeQuery(); //sql문을 테이블에 반영하고 결과행을 Resultset에 담음
                if(rs.next()) {
                    count = rs.getInt(1); //컬럼인덱스
                }
            } catch (Exception e) {
                throw new Exception(e);
            }finally{
                executeClose(rs, pstmt, conn);
            }
            return count;
        }


◎ 목록 getList(int startRow, int endRow)

목록같은 경우도 SQL문의 테이블명 빼고 거의 패턴화 되어있음 

 /* date타입은 년월일만 나오므로 string으로 반환하면 시분초까지 처리 가능 */

sql작성 참고 :  [JSP] 🔗모델1 구조(3) 실습 

 

자바빈을 ArrayList에 저장하는 것까지 마무리해주는 걸 잊지않는다!

list.add(boardVO);

▼code

더보기
public List<BoardVO> getList(int startRow, int endRow) throws Exception{
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		List<BoardVO> list = null;
		String sql = null;
		try {
			conn = getConnection(); //커넥션풀로부터 커넥션 할당
			//SQL문 작성
			sql = "SELECT * FROM(SELECT A.*, rownum rnum FROM(SELECT * FROM sboard ORDER BY num DESC)A)"
					+ "WHERE rnum>= ? AND rnum <= ?";
			pstmt = conn.prepareStatement(sql); //PreparedStatement객체 생성
			pstmt.setInt(1, startRow); //?에 데이터 바인딩
			pstmt.setInt(2, endRow); 
			rs = pstmt.executeQuery(); //sql문을 테이블에 반영하고 결과행들을 RS에 담음
			//★ArrayList 객체 생성
			list = new ArrayList<BoardVO>();
			while(rs.next()) { //반복문을 이용해서 반복하면 자바빈을 생성하고 정보를 저장
				//num, title, name, passwd, content, ip, reg_date
				BoardVO boardVO = new BoardVO();
				boardVO.setNum(rs.getInt("num"));
				boardVO.setTitle(rs.getNString("title"));
				boardVO.setName(rs.getString("name"));
				boardVO.setReg_date(rs.getDate("reg_date"));
				
				list.add(boardVO); //자바빈을 ArryList에 저장
			}
		} catch (Exception e) {
			throw new Exception(e);
		}finally { //자원 정리
			executeClose(rs, pstmt, conn);
		}
		return list;
	}


MemberVO에 정보를 받아서 반환한다. String id가 들어와서 체크를 해준다

public MemberVO checkMember(String id)throws Exception{ 

 * import kr.member.vo.MemberVO;

 

연동을 시킨다.

Connection conn = null;

PreparedStatement pstmt = null;

ResultSet rs = null;

MemberVO 를 사용하고있고 MemberVO 에 필요한 데이터를 담는다

MemberVO member = null;

String sql = null;

 

기존의 try-catch-finally 를 적어보자면 

try{ jdbc 수행단계들  }catch(Exception e){ e.printStackTrace(); }finally{ } return member;

( return member; 를 하면 memberVO를 반환한다. )

기존에는 예외가 발생하면 catch(Exception e){} 블럭으로 이동해서 e.printStackTrace(); 로 예외문구를 뿌렸다.

JSP로 연동할 땐 예외 발생 시 화면으로 만들었는데,
DAO에서는 DAO가 클래스기 때문에 화면을 만들 수는 없고 신호만 보낼 수있다.

이렇게 되면 예외가 발생하더라도 return member ; 로써 null이 반환되는데 (MemberVO member = null; )
이 결과는 메서드 동작에 아무런 문제가 없다고 보게된다.
사용자 측면에선 null이 오류라고 인지할 수 없다. JSP에선 에러가 발생하면 에러페이지를 전송하기 때문에 
프론트쪽에서 에러가 나던, 백엔드쪽에서 에러가 나던, 상황에 따라서  에러페이지가 전송되는 게 프로그램 처리 시 좋다

따라서 에러가 발생하면 에러를 던져서(throw) 에러페이지를 만들려고 한다.

e.printStackTrace();

throw new Exception(e);

→ 콘솔창에 에러 문구도 찍히고, UI 측면으로 보면 에러페이지도 전송이 된다.

 

이제 try { } 블럭에서 JDBC수행을 해보자.

 

getConnection()메서드를 호출해서 JDBC1,2단계를 수행한다.

(커넥션 풀로부터 커넥션을 할당함으로서, 메서드 단위로 작업할 때 코드가 간단해지는 효과를 볼 수 있다.)

conn = getConnection();

SQL문을 작성하고 PreparedStatement객체를 생성한 후 ? 에 데이터를 바인딩한다.

sql = "SELECT * FROM smember WHERE id=?";

pstmt = conn.prepareStatement(sql);

pstmt.setString(1,id);

SQL문을 테이블에 반영하고 결과'행'을 ResultSet에담는다 (id가 유니크하기때문에 여러행이 만들어질 수 없다)

rs = pstmt.executeQuery();

 

if(rs.next()) {

행이 있으면 자바빈을 생성해서 전달한다. (행이 없으면 생성을 안하니까 null이 전달)

MemberVO 객체 생성

member = new MemberVO();

아이디, num, 비밀번호를 넣어준다

member.setId(rs.getString("id"));

member.setNum(rs.getInt("num"));

member.setPasswd(rs.getString("passwd"));

}

예외가 발생했을 때 에러를 던져서(throw) 에러페이지를 만든다.

catch (Exception e) {

throw new Exception(e);

자원정리

}finally {

executeClose(rspstmtconn);

}return member;

아이디가 중복 됐을 때  if(rs.next()) { } 을 수행하여 객체가 생성되고 생성된 객체를 반환해준다.

아이디가 중복 되지 않아 if(rs.next()) { } 에 진입을 못하면 객체 생성을 못하고

MemberVO member = null; 에 따라서 return member;에서 null값을 반환한다.

이 반환된 값은 confirmId.jsp 에서 사용된다.

 

◎ 회원가입

	public void insertMember(MemberVO member)throws Exception{
		Connection conn = null;
		PreparedStatement pstmt = null;
		String sql = null;
		try {
			conn = getConnection(); //커넥션 풀로부터 커넥션을 할당
			
			//SQL문 작성
			sql = "INSERT INTO smember(num,id,name,passwd,email,"
					+ "phone,reg_date) VALUES (smember_seq.nextval,?,?,?,?,?,SYSDATE)";
			
			//PreparedStatement객체 생성
			pstmt = conn.prepareStatement(sql);
			
			pstmt.setString(1,member.getId());
			pstmt.setString(2,member.getName());
			pstmt.setString(3,member.getPasswd());
			pstmt.setString(4,member.getEmail());
			pstmt.setString(5,member.getPhone()); //자바빈에있는 내용을 읽어 올 수있다
			//SQL문 반영
			pstmt.executeUpdate(); //반환타입이 void
		} catch (Exception e) {
			throw new Exception(e);
		}finally{
			executeClose(null, pstmt, conn);
		}
	}

form에서 submit으로 연결했던 registerUser.jsp로 데이터를 보낸다 .

 

◎ 회원 상세 정보

수정폼에도 사용(재활용)

하나의 레코드 정보를 자바빈(VO)에 담는다.

public MemberVO getMember(int num)throws Exception{ 

 

행이 하나밖에 없으므로 if문 / 여러행이었으면 while문

if(rs.next()) { 

자바빈(VO)객체 생성

member = new MemberVO();

사용할 것들을 담아준다. 전체를 다 담고 표시할 때 뽑아내는 방법을 사용해보자. (아래의 전체 코드 참고)
표시할 것만 담고 필요한것만 뽑아도 되는 방법도 있다.

서버 상에만 있는 정보기 때문에 클라이언트는 알 수 없다.

member.setNum(rs.getInt("num"));

member.setId(rs.getString("id"));

member.setPasswd(rs.getString("passwd"));

....

자원정리 후 

return member; 의 값은 myPage.jsp로  전달된다.

public MemberVO getMember(int num)throws Exception{
		Connection conn = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		MemberVO member = null;
		String sql = null;
		
		try {
			//커넥션 풀로 부터 커넥션을 할당
			 conn = getConnection();
			 //SQL문 작성
			 sql = "SELECT * FROM smember WHERE num=?";
			 //preparedStatement 객체 생성
			 pstmt = conn.prepareStatement(sql);
			 //?에 데이터 바인딩
			 pstmt.setInt(1, num);
			 //SQL문을 테이블에 반영하고 결과행을 ResultSet에 담음
			 rs = pstmt.executeQuery();
			 if(rs.next()) {
				 member = new MemberVO(); //자바빈 객체 생성
				 member.setNum(rs.getInt("num"));
				 member.setId(rs.getString("id"));
				 member.setPasswd(rs.getString("passwd"));
				 member.setName(rs.getString("name"));
				 member.setEmail(rs.getString("email"));
				 member.setPhone(rs.getString("phone"));
				 member.setReg_date(rs.getDate("reg_date"));
			 }
		} catch (Exception e) {
			throw new Exception(e);
		}finally { //자원정리
			executeClose(rs, pstmt, conn);
		}
		return member; //이게 myPage.jsp 로 전달
	}

◎ 회원정보 수정

 자바빈(vo)에 담아서 작업을 해준다.

id와 reg_date는  수정을 못하게 정한다. (기획 시에 변경할 것과 변경하지 못한 것을 미리 정해둔다.)

SQL문장을 잘 수행하는게 가장 중요하고 SQL문 반영하는 4단계(pstmt.executeUpdate();)수행이 중요하다.
4단계 수행을 안 할 경우에는 SQL이 오류가 나더라도 아무 반응이없다.

◎ 회원정보 삭제(회원탈퇴)

프라이머리키(int num)가 전달이 된다.

 


src/main/java/kr.board.action(패키지)/WriteAction.java

모델클래스의 형태가 똑같아야 하니까 Action을 implements 를 해준다.

(추상 메서드 구현하기)

post방법으로 전송되니까 전송된 데이터 인코딩 처리해준다.

모델2에서는 자동처리 안됀다. (스프링에서는 자동처리 해줌)
자바빈(vo)객체를 먼저 생성하고 전송된 객체들 셋팅한다.  그러나 ip는 전송된게 아니라서 넘겨야 될 데이터를 만든다.

[JSP] 🔗기본 객체.

BoardDAO에 넘겨주기 위해서 DAO를 호출하고 BoardDAO의 insert메서드에 boardVO를 넘겨준다.

→ 데이터베이스 연동이 되서 데이터를 추가 해줌

마지막으로 JSP경로 반환

return "/WEB-INF/views/write.jsp";

 

 

▼ code

더보기
package kr.board.action;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import kr.board.dao.BoardDAO;
import kr.board.vo.BoardVO;
import kr.controller.Action;

public class WriteAction implements Action{
	@Override
	public String execute(HttpServletRequest request, HttpServletResponse responsee) throws Exception {
		
		request.setCharacterEncoding("utf-8"); //post방법으로 전송되니까 전송된 데이터 인코딩 처리
		
		//자바빈(vo)객체 생성
		BoardVO boardVO = new BoardVO();
		boardVO.setTitle(request.getParameter("title"));
		boardVO.setName(request.getParameter("name"));
		boardVO.setPasswd(request.getParameter("passwd"));
		boardVO.setContent(request.getParameter("content"));
		boardVO.setIp(request.getRemoteAddr());
		
		//BoardDAO호출 
		BoardDAO dao  = BoardDAO.getInstance();
		//글 작성
		dao.insert(boardVO);
		//JSP경로 반환
		return "/WEB-INF/views/write.jsp";
	}
}

src/main/java/WEB-INF/views/write.jsp  :  글 작성

생성된 코드를 다 지우고 자바스크립트로 작업을 해준다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<script type="text/javascript">
	alert('글쓰기 완료!');
	location.href='list.do';
</script>

ActionMap.properies설 정파일에 경로를 지정해준다.

/write.do=kr.board.action.WriteAction


이제 목록작업을 할 수 있는데 목록작업은 기본적으로 페이징 처리한다.

src/main/java/kr.util(패키지)/PagingUtil.java

페이징 처리 작업을 하기 위해, PagingUtil.java 파일을 넣어준다.

BoardDAO로 가서 글의 총 갯수와 목록 메서드작업을 해준다.

src/main/webapp/css/layout.css

대문페이지를 생성하기 전에  전체 페이지에 적용할 css파일도 생성하고


src/main/webapp/views/main.java : 회원관리 메인 !

대문 페이지를 작성해보자.

링크를 걸어서 css파일을 불러오는데  href="../css/layout.css" 방법은 HTML에서만 쓰는 방법이고

프로그래밍이 들어가고 경로가 복잡해지면 컨텍스트 경로부터 명시한다

<link rel="stylesheet" href=<%= request.getContextPath() %>/css/layout.css">

실제 서비스할 때 이 경로들은 사라짐.

메뉴을 작성하는데 세션으로 로그인 여부를 확인하여 페이지를 나눈다.  [JSP] 🔗세션

<% 
	String user_id = (String)session.getAttribute("user_id"); 
%>

if문을 사용하여 세션 값으로 null 여부 판단한다.

           

<% if(user_id == null){ //로그인이 되어있지 않은 경우 %>

<a href="registerUserForm.jsp">회원가입</a>

<a href="loginForm.jsp">로그인</a>

 

<% }else//로그인  경우 %>

<a href="myPage.jsp">MyPage</a>   → 회원정보수정, 회원탈퇴  

<a href="logout.jsp">로그아웃</a>   

 

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원관리 메인</title>
<%-- <link rel="stylesheet" href="../css/layout.css"> --%>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css"> 
<body>
<% 
	String user_id = (String)session.getAttribute("user_id"); //null이면 로그인이 안됀것
%>
<div class="page-main">
	<h1>회원관리 메인</h1>
	<div class="align-right">
		<%
			if(user_id == null){ //로그인이 되어있지 않은 경우
		%>
		<a href="registerUserForm.jsp">회원가입</a> 
		<a href="loginForm.jsp">로그인</a>
		<%
			}else{ //로그인 된 경우
		%>
		<a href="myPage.jsp">MyPage</a>
		[ <b><%= user_id %></b>님이 로그인 중 ] 
		<a href="logout.jsp">로그아웃</a>	
		<%
			}
		%>
	</div>
</div>
</body>
</html>


src/main/webapp/views/registerUserForm.jsp   : 회원가입Form

링크를 걸어서 css파일을 불러오고

js 라이브러리를 사용해야 하므로 webapp에 js폴더를 만들어서  jquery-3.6.0.min.js 파일을 넣어준다

 jquery 스크립트도 컨텍스트경로를 동일한 방법으로 링크를 걸어준다.

<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">

<script type="text/javascript" src="<%= request.getContextPath() %>/js/jquery-3.6.0.min.js"></script>

 

<body>에 UI작업을 해주고

서버 프로그램을 만들어야하기 때문에 views폴더에 아이디 중복체크를 해주는 파일을 만들어준다.

 

AJAX통신을 해주자.

submit이 아니고 click이므로 함수가 빠져나가게끔 return false;가 아니라 return;

$(function(){
	var count =0;
	
	$('#confirm_id').click(function(){
		if($('#id').val().trim()==''){
			alert('아이디를 입력하세요');
			$('#id').val('').focus(); 
			return;
		}

 

그 안에서 서버 연동작업을 해준다. 옵션 값들을 나열해준다. count로 다 구별해줘야한다.

		$.ajax({
			url:'confirmId.jsp',
			type:'post',
			data:{id:$('#id').val()},
			dataType:'json',
			cache:false,
			timeout:30000,
			success:function(param){
				if(param.result=='idDuplicated'){
					count = 0;
					$('#id_signed').text('아이디 중복').css('color','red');
					$('#id').val('').focus();
				}else if(param.result =='idNotFound'){
					count = 1; //아이디를 사용할 수 있는 경우
					$('#id_signed').text('사용 가능한 아이디').css('color','black');
				}else{
					count = 0;
					alert('오류가 발생했습니다!')
				}
			},
			error:function(){
				count = 0;
				alert('네트워크 오류 발생');
			}
		});
    });//end of click

insert는 DAO쪽에 메서드를 만들고나서 insert삽입한다.

(아이디 중복체크 테스트를 하려면 대문페이지(회원관리메인)실행해서 중복체크 테스트 해본다.

아직 db에 데이터가 없어서 임의로 데이터를 넣으면 시퀀스가 있어서 충돌나기 때문에 데이터 넣고 바로 제거한다.) 

이제 DAO 로 가서 회원가입 메서드를 만들어보자

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css"> 
<script type="text/javascript" src="<%= request.getContextPath() %>/js/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
$(function(){
	var count =0;
	
	$('#confirm_id').click(function(){
		if($('#id').val().trim()==''){
			alert('아이디를 입력하세요');
			$('#id').val('').focus(); 
			return;
		}
		//서버 연동
		$.ajax({
			url:'confirmId.jsp',
			type:'post',
			data:{id:$('#id').val()},
			dataType:'json',
			cache:false,
			timeout:30000,
			success:function(param){
				if(param.result=='idDuplicated'){
					count = 0;
					$('#id_signed').text('아이디 중복').css('color','red');
					$('#id').val('').focus();
				}else if(param.result =='idNotFound'){
					count = 1; //아이디를 사용할 수 있느 경우
					$('#id_signed').text('사용 가능한 아이디').css('color','black');
				}else{
					count = 0;
					alert('오류가 발생했습니다!')
				}
			},
			error:function(){
				count = 0;
				alert('네트워크 오류 발생');
			}
		});
		
	});//end of click
	
	//keyup 부분, 변경 작업하는 부분
	$('#register_form #id').keyup(function(){
		count = 0;
		$('#id_signed').text('');
	});
	
	$('#register_form').submit(function(){
		if($('#id').val().trim()==''){
			alert('아이디를 입력하세요!');
			$('#id').val('').focus();
			return false;
		}
		
		if(count == 0){
			alert('아이디 중복체크 필수');
			return false;
		}
		
		if($('#name').val().trim()==''){
			alert('이름을 입력하세요!');
			$('#name').val('').focus();
			return false;
		}
		
		if($('#passwd').val().trim()==''){
			alert('비밀번호를 입력하세요!');
			$('#passwd').val('').focus();
			return false;
		}
		
		if($('#email').val().trim()==''){
			alert('이메일을 입력하세요!');
			$('#email').val('').focus();
			return false;
		}
	});
});
</script>
</head>
<body>
<div class="page-main">
	<h1>회원가입</h1>
	<form action="registerUser.jsp" method="post" id="register_form">
		<ul>
			<li>
				<label for="id">아이디</label>
				<input type="text" name="id" id="id" size="7" maxlength="12"> 
				<input type="button" id="confirm_id" value="ID중복확인">
				<span id="id_signed"></span>
			</li>
			<li>
				<label for="name">이름</label>
				<input type="text" name="name" id="name" maxlength="10"> 
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input type="password" name="passwd" id="passwd" maxlength="12"> 
			</li>
			<li>
				<label for="email">이메일</label>
				<input type="email" name="email" id="email" maxlength="50"> 
			</li>
			<li>
				<label for="phone">전화번호</label>
				<input type="text" name="phone" id="phone" maxlength="15"> 
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="등록">
			<input type="button" value="홈으로" onclick="location.href='main,jsp'"> 
		</div>
	</form>
</div>
</body>
</html>


src/main/webapp/views/confirmId.jsp : 아이디 중복체크하는 서버프로그램

이 중복 체크해주는 파일은 여기에서 데이터베이스 연동을 하는 것이 아니다.

DAO를 만들었기 때문에  DAO에서 정보를 읽어서 처리해주는 것이다. 

즉 json문자열을 만들어 처리하는 부분이라고 볼 수 있다.

문자열만 처리하므로 

<%@ page language="java" contentType="text/plain; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%> 

위 부분만 남기고 다지워준다.

 

자원을 사용하려고 하므로 임포트 해준다.

<%@ page import="kr.member.dao.MemberDAO" %>

<%@ page import="kr.member.vo.MemberVO" %>

 

DAO에서 메서드 형태로 작업을 해주면 이 쪽에서 호출을 해주는 방식이다.

 

import만 해놓고 DAO 쪽으로 가서 (아이디 중복체크)메서드 작업을 마무리한 뒤 완성을 한다.

 

id가 post방법으로 전송될 것이므로 전송된 데이터 인코딩 처리와 데이터 반환 처리를 해준다.

<%

request.setCharacterEncoding("utf-8");

String id = request.getParameter("id");

 

데이터베이스 연동을 해서 아이디가 등록됬는지 안됐는지 확인해야한다.

근데 여기서 데이터베이스 연동하는 것이 아니라 DAO에서 연동한다고 했으므로, DAO객체를 생성한다.

MemberDAO dao = new MemberDAO()하지만 이렇게 호출하면 생성자를 private으로 막아놨기 때문에

외부에서 호출은 불가하다.

따라서 static한 메서드는 공개가 되어있기 때문에

MemberDAO dao = MemberDAO.getInstance(); 이렇게 객체 생성을 해준다.

DAO메서드에서 MemberVO에 필요한 데이터를 담았으니 VO를 반환받아야 한다.

MemberVO member = dao.checkMember(id); 

(id 중복O = 객체반환 / id 중복X = null반환)

//아이디가 중복 됐을 때

if(member!=null){  %> 

json문자열을 만들어준다.

    {"result":"idDuplicated"} 

//아이디가 미 중복

<% }else%> 

    {"result":"idNotFound"} 

<%  } %> 

 

registerUserForm.jsp에서confirmId.jsp 를 호출해서 데이터를 처리하면 된다.

▼ code

더보기
<%@ page language="java" contentType="text/plain; charset=UTF-8" pageEncoding="UTF-8" trimDirectiveWhitespaces="true"%>
<%@ page import="kr.member.dao.MemberDAO" %>
<%@ page import="kr.member.vo.MemberVO" %>
<%
	//전송된 데이터 인코딩 처리
	request.setCharacterEncoding("utf-8");

	//전송된 데이터 반환
	String id = request.getParameter("id");
	
	//MemberDAO dao = new MemberDAO(); 아님
	MemberDAO dao = MemberDAO.getInstance();
	MemberVO member = dao.checkMember(id);
	if(member!=null){ //아이디 중복됐을때
%>
	{"result":"idDuplicated"}
<%
	}else{//아이디 미중복
%>
	{"result":"idNotFound"}
<%
	}
%>


src/main/webapp/views/registerUser.jsp : 회원가입

자원을 사용하려고 하므로 임포트 해준다.

<%@ page import="kr.member.dao.MemberDAO" %> 

 

id가 post방법으로 전송될 것이므로 전송된 데이터 인코딩 처리와 데이터 반환 처리를 해준다.

<% request.setCharacterEncoding("utf-8"); %> 

 

setproperty 를 이용해서 request에 담겨있는 정보를 자바빈으로 넘겨주는 작업을 한다.

JSP에서 자바빈 객체를 생성할 때 사용하는 <jsp:useBean>액션 태그를 사용한다.

<jsp:useBean id="member" class="kr.member.vo.MemberVO"/> 

- id : jsp 페이지에서 자바빈 객체에 접근할 때 사용할 이름을 명시함

- class : 패키지 이름을 포함한 자바빈 클래스의 완전한 이름을 입력함

 

자바빈 객체의 프로퍼티 값을 설정 하는<jsp:setProperty>액션 태그를 사용한다.

<jsp:setProperty name="member" property="*" /> 

- name : 프로퍼티의 값을 변경할 자바빈 객체의 이름. <jsp:useBean> 액션 태그의 id 속성에서 지정한 값을 사용

- property : 값을 지정할 프로퍼티의 이름

식별자(name="member" )를 이용해서 자바빈에 접근해서 모든 프로퍼티(property="*" )에 대해 검색을 하고 class(class="kr.member.vo.MemberVO"/)에 넣어준다.

자바빈이 만들어졌으니 DAO에 전달을 해준다

<%MemberDAO dao = MemberDAO.getInstance(); 

dao.insertMember(member); %>  (insertMember에 member를 넘겨준다)

예외가 발생하지 않으면 정상적으로 처리가 되는데 회원가입이 완료되는 것이다. 태그에 css.stylesheet를 link걸고 회원가입이 되었다는 화면을 만들어준다.

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="kr.member.dao.MemberDAO" %>
<%
	//전송된 데이터 인코딩 처리
	request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="member" class="kr.member.vo.MemberVO"/>
<jsp:setProperty property="*" name="member" />
<%
	MemberDAO dao = MemberDAO.getInstance();
	dao.insertMember(member);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css"> 
</head>
<body>
<div class="page-main">
	<h1>회원가입 완료</h1>
	<div class="result-display"> 
		<div class="align-center">
			회원가입 성공! <br>
			<button onclick="location.href='main.jsp'">홈으로</button>
		</div>
	</div>
</div>
</body>
</html>

 


src/main/webapp/views/loginForm.jsp : 로그인Form

css 링크를 넣어주고

<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css"

<body>태그에 UI작업을 해주고

유효성 체크를 해준다. 자바스크립트를 사용한다. 

<script type="text/javascript"

 

DAO에 메서드를 만들어놔서 재활용할 수 있다. 호출만 하기 위해 login.jsp 만든다.

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 폼</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
<script type="text/javascript">
	window.onload=function(){
		var form = document.getElementById('login_form');
		form.onsubmit=function(){
			var id = document.getElementById('id');
			if(id.value.trim()==''){
				alert('id를 입력하세요!');
				id.focus();
				id.value='';
				return false;
			}
			var passwd = document.getElementById('passwd');
			if(passwd.value.trim()==''){
				alert('비밀번호를 입력하세요!');
				passwd.focus();
				passwd.value='';
				return false;
			}
		}
	};
</script>
</head>
<body>
<div class="page-main">
	<h1>로그인</h1>
	<form action="login.jsp" method="post" id="login_form">
		<ul>
			<li>
				<label for="id">아이디</label>
				<input type="text" name="id" id="id" maxlength="12">
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input type="password" name="passwd" id="passwd" maxlength="12">
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="로그인">
			<input type="button" value="홈으로" onclick="location.href='main.jsp'">
		</div>
	</form>
</div>
</body>
</html>


src/main/webapp/views/login.jsp : 로그인

DAO에 아이디 중복체크/ 로그인 체크 하는 메서드인 checkMember()를 호출만 하는 jsp이기 때문에 html다 지우고,

DAO,VO임포트하고 

<%@ page import="kr.member.dao.MemberDAO" %> 

<%@ page import="kr.member.vo.MemberVO" %> 

전송된 데이터 인코딩처리

<% request.setCharacterEncoding("UTF-8"); 

전송된 데이터 반환 받고

String id = request.getParameter("id"); 

String passwd = request.getParameter("passwd"); 

아이디를 체크해서 인증처리 해야하니 DAO호출한다.

MemberDAO dao = MemberDAO.getInstance(); 

id 존재 여부 확인

MemberVO member = dao.checkMember(id); 

체크 인증 받기 위해서 boolean타입의 변수를 하나 지정한다.(나중에 조건 체크 하려고)

boolean check = false; 

 

아이디가 존재하면 비밀번호체크해야한다.

if(member!= null){ 

memberVO에 미리 비밀번호를 체크하는 메서드를 만들어놨다.

public class MemberVO {
	private int num; //회원번호
	private String id; //회원아이디
	private String name; //회원
	private String passwd; //비밀번호
	private String email; //이메일
	private String phone; //전화번호
	private Date reg_date; //가입일
	
	//비밀번호 체크
	public boolean isCheckedPassword(String userPasswd) {
		if(passwd.equals(userPasswd)) { //비밀번호 일치
			return true;
		}
		return false; //비밀번호 불일치
	}

MemberVO가 데이터베이스로부터 저장된 비밀번호를 읽어오고 유저가 입력한 비밀번호와 비교한다.

사용자가 입력한 비밀번호와 table에 저장된 비밀번호 일치 여부 확인한다.

check = member.isCheckedPassword(passwd); 

check 가 true 일 경우 = 로그인 처리

if(check){

user_num은 프라이머리키이기 때문에 저장을 한다.

session.setAttribute("user_num", member.getNum());

아이디 정보를 읽어올 때. 메뉴를 user_id의 유무에 따라 정보를 처리했으므로 그 때 활용하기 위해 저장을 한다.

session.setAttribute("user_id", id);

Redirect기법을 이용해서 주소를 변경시킨다.

response.sendRedirect("main.jsp");

 

인증 실패 시 자바스크립트로 처리해준다.

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="kr.member.dao.MemberDAO" %>
<%@ page import="kr.member.vo.MemberVO" %>
<%
	//전송된 데이터 인코딩 처리
	request.setCharacterEncoding("UTF-8");
	//전송된 데이터 반환
	String id = request.getParameter("id");
	String passwd = request.getParameter("passwd");

	MemberDAO dao = MemberDAO.getInstance();
	//id존재여부 확인
	MemberVO member = dao.checkMember(id);
	boolean check = false; // 나중에 조건체크하려고
	
	if(member!= null){ //아이디 존재
		//사용자가 입력한 비밀번호와 table에 저장된 비밀번호 일치 여부 확인
		check = member.isCheckedPassword(passwd); //일치하면 check=true 불일치하면 check=false
	}
	if(check){ //true. 인증성공
		//로그인 처리
		session.setAttribute("user_num", member.getNum()); 
		session.setAttribute("user_id", id);
		response.sendRedirect("main.jsp");//로그인 성공한다음 "main.jsp"로 주소가 바뀜
	}else{ //false. 인증실패
%>
	<script type="text/javascript">
		alert('아이디 또는 비밀번호가 불일치');
		history.go(-1);//전페이지(폼)으로 돌아감
	</script>
<%
	}
%>

로그아웃까지 작성하고 테스트를 해주자.


src/main/webapp/views/logout.jsp : 로그아웃

메뉴만 바뀌면 로그아웃된 것을 알 수 있다. 별도의 ui, 안내문구가 필요없기에 코드를 다 지워준다.

 

세션에 있는 속성들을 다 지우면 로그아웃 된 것을 알 수 있다.

<% session.invalidate();

 

response.sendRedirect("main.jsp"); %>

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
	//로그아웃
	session.invalidate(); //세션에 있는 데이터를 지워버림
	response.sendRedirect("main.jsp");

	//여기에 문구를 넣어도 상관없음
%>


src/main/webapp/views/myPage.jsp : 회원 상세정보

DAO,VO 자원을 import 해준다. css도  링크해준다.

로그인이 된 상태에서 진입해야 하니까 세션에있는 user_num(PK)을 호출해서 로그인 여부를 확인하기 위해 조건체크를 해준다.

Integer user_num =  (Integer)session.getAttribute("user_num");

이 때 getAttribute는 무조건 object형태로 반환하기 때문에  (Integer)로  다운  캐스팅해준다.

 

<body>에 회원 상세정보를 작성한다.

전화번호 표시란에 null이라고 출력이 안되게하고 비어있게 하기위해서 조건문을 넣어준다.

if(member.getPhone()==null){

 member.setPhone("");  }

▼ code

더보기
<%@page import="javax.management.MBeanAttributeInfo"%>
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="kr.member.dao.MemberDAO"%>
<%@ page import="kr.member.vo.MemberVO"%>
<!-- 로그인이 된 상태에서 진입해야한다. -->
<%
Integer user_num = (Integer) session.getAttribute("user_num");
if (user_num == null) { //로그인이 되지 않은경우 이므로 로그인을 하게끔한다
	response.sendRedirect("loginForm.jsp");
} else { //로그인이 되어있는 경우는 페이지를 보여준다
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 상세 정보</title>
<link rel="stylesheet" href="<%=request.getContextPath()%>/css/layout.css">
</head>
<body>
	<%
	MemberDAO dao = MemberDAO.getInstance();
	MemberVO member = dao.getMember(user_num);
	/* 전화번호 에 null이라고 출력안되고 비어있게 하기위해서 */
	if (member.getPhone() == null) {
		//member.setPhone("입력안함");
		member.setPhone("");
	}
	%>
	<div class="pase_main">
		<h1>회원 상세 정보</h1>
		<ul>
			<li>아이디 : <%=member.getId()%></li>
			<li>이름 : <%=member.getName()%></li>
			<!-- 비밀번호는 보여지지않음 -->
			<li>이메일 : <%=member.getEmail()%></li>
			<li>전화번호 : <%=member.getPhone()%></li>
			<li>가입일 : <%=member.getReg_date()%></li>
		</ul>
		<hr width="100%" size="1" noshade="noshade"><!-- "noshade" 진하게보이기 -->
		<div class="align-right">
			<input type="button" value="회원정보수정" onclick="location.href='modifyUserForm.jsp'"> 
           	 <input type="button" value="회원탈퇴" onclick="location.href='deleteUserForm.jsp'"> 
           	 <input type="button" value="홈으로" onclick="location.href='main.jsp'">
		</div>
	</div>
</body>
</html>
<%
}
%>


src/main/webapp/views/modifyUserForm.jsp : 회원정보 수정Form

DAO,VO 자원을 import 해준다. css도 링크해준다.

세션 값인 "user_num"값을 가져와아 하고 역시 로그인이 되어있는 상태여야 한다.

 

DAO의 회원상세정보 메서드가 회원수정폼에서도 이용된다.

<% MemberDAO dao = MemberDAO.getInstance();

      MemberVO member = dao.getMember(user_num);

 

UI를 만들고 UI의 폼에 미리보기 만든다.

원래 수정하려면 프라이머리키가 있어서 하나의 레코드에 접근해야하는데.

JSP방식으로 UPDATE할 때는 <input type="hidden" name="num" value="<%= num %>">

이런식으로 pk를 "hidden"으로 넘겨줬었다.

여기서는 세션안에 num이 저장되어 있어서 페이지에서 공유가 가능하기 때문에  hidden방식 안쓴다.

(세션으로부터 num값을 확보한 다음 → 그 num을 통해서 하나의 레코드에 접근 →  데이터 수정작업)

 

비밀번호는 value값을 넣지않고 미리보기 안한다.

비밀번호는 보통 따로 분리해서 작성하는 경향이 있지만 여기선 같이 작성하도록 하자.

 

유효성체크를 자바스크립트로 작성을 해준다. (제이쿼리형태로 명시해도 상관없음)

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="kr.member.dao.MemberDAO" %>
<%@ page import="kr.member.vo.MemberVO" %>
<%
	Integer user_num = (Integer)session.getAttribute("user_num");
	if(user_num==null){ //로그인이 되지 않은 경우 (or 세션이 만료 되었을때)
		response.sendRedirect("loginForm.jsp");
	}else{ //로그인 된 경우
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 정보 수정</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
<script type="text/javascript">
	window.onload=function(){
		var form = document.getElementById('modify_form');
		form.onsubmit=function(){
			var name = document.getElementById('name');
			if(name.value.trim()==''){
				alert('이름을 입력하세요!');
				name.focus();
				name.value ='';
				return false;
			}
			var passwd = document.getElementById('passwd');
			if(passwd.value.trim()==''){
				alert('비밀번호를 입력하세요!');
				passwd.focus();
				passwd.value ='';
				return false;
			}
			var email = document.getElementById('email');
			if(email.value.trim()==''){
				alert('이메일을 입력하세요!');
				email.focus();
				email.value ='';
				return false;
			}
		}
	};
</script>
</head>
<body>
<%
	MemberDAO dao = MemberDAO.getInstance();
	MemberVO member = dao.getMember(user_num);
	if(member.getPhone()==null){
		member.setPhone("");
	}
%>
<div class="page-main">
	<h1>회원정보 수정</h1>
	<form action="modifyUser.jsp" method="post" id="modify_form">
		<ul>
			<li>
				<label for="name">이름</label>
				<input type="text" name="name" id="name" value="<%=member.getName()%>" maxlength="10">
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input type="password" name="passwd" id="passwd" maxlength="12">
			</li>
			<li>
				<label for="email">이메일</label>
				<input type="email" name="email" id="email" value="<%=member.getEmail()%>" maxlength="50">
			</li>
			<li>
				<label for="phone">전화번호</label>
				<input type="text" name="phone" id="phone" value="<%=member.getPhone()%>" maxlength="15">
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="수정">
			<input type="button" value="홈으로" onclick="location.href='main.jsp'">
		</div>
	</form>
</div>
</body>
</html>
<%
	}
%>


src/main/webapp/views/modifyUser.jsp : 회원정보 수정완료

DAO에서 update메서드를 완성시키고 오자.

DAO자원을 import 해준다. css도 링크해준다.

useBean액션태그(풀네임 명시)를 사용하니까 VO는 가져올 필요없다.

로그인이 안됐을 경우에 로그인하는 창으로 돌려보내고, 로그인이 됐을 때 전송된 데이털르 인코딩처리하며 작업을 시작한다.

<%  Integer user_num = (Integer)session.getAttribute("user_num");

      if(user_num==null){

            response.sendRedirect("loginForm.jsp");

      }else//로그인  경우

            request.setCharacterEncoding("utf-8");  %>

(else 닫는 중괄호는 맨밑에 명시.)

 

request에있는 모든 파라미터명과 MemberVO에 있는 프러퍼티와 대조해서 일치하면 셋팅

<jsp:useBean id="member" class="kr.member.vo.MemberVO"/>

<jsp:setProperty  name="member" property="*" />

이 때 (셋팅되어)전송되어진 값은 이름, 비밀번호, 이메일, 전화번호 이고, 셋팅이 안됀건 num 값이다.

전송되지 않아서 셋팅이 안돼있는 정보(num)는 별도로 셋팅을 해줘야한다.
session에 저장된 num을 이용한다. (세션에num이 있어서 일부러 전송안한 것)

member.setNum(user_num);

 

필요로 하는 데이터를 다 얻었으니(셋팅했으니) DAO를 호출하고 updateMeber()메서드에 넘겨서 회원정보 수정 작업을 한다.

MemberDAO dao = MemberDAO.getInstance();
dao.updateMember(member);

 

<body>에  수정이 잘됬음을 알려주는 UI작업을 해준다.

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="kr.member.dao.MemberDAO" %>
<%
	Integer user_num = (Integer)session.getAttribute("user_num");
	if(user_num==null){
		response.sendRedirect("loginForm.jsp");
	}else{ //로그인 된 경우
		//전송된 데이터 인코딩 처리
		request.setCharacterEncoding("utf-8");
%>
<jsp:useBean id="member" class="kr.member.vo.MemberVO"/>
<jsp:setProperty property="*" name="member"/>
<%
	member.setNum(user_num);
	
	MemberDAO dao = MemberDAO.getInstance();
	dao.updateMember(member);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원정보 수정 완료</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
</head>
<body>
<div class="page-main">
	<h1>회원정보 수정 완료</h1>
	<div class="result-display">
		<div class="align-center">
		회원정보 수정 완료! <br>
		<button onclick="location.href='main.jsp'">홈으로</button>
		</div>
	</div>
</div>
</body>
</html>
<%
	}	
%>


src/main/webapp/views/deleteUserForm.jsp : 회원탈퇴Form

DAO에서 회원 정보 삭제메서드를 완성시키고 오자.

<%  Integer user_num = (Integer)session.getAttribute("user_num");

      if(user_num==null){

            response.sendRedirect("loginForm.jsp");

      }else//로그인  경우

까지는 회원정보수정과 똑같은 코드 . 로그인이 된 경우에 페이지를 구성하는 UI를 <body>작성하자.

<label for="cpasswd">비밀번호 확인</label> 은 옵션이다. 필요없으면 빼도 되는 기능 (최소한의 보안)

 

디자인통일을 위해 css링크해주고 스크립트넣어준다.

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%
	Integer user_num = (Integer)session.getAttribute("user_num");
	if(user_num==null){
		response.sendRedirect("loginForm.jsp");
	}else{ //로그인이 된 경우
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 탈퇴 폼</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css"> 
<script type="text/javascript">
	window.onload = function(){
		var form = document.getElementById('delete_form');
		form.onsubmit=function(){
			var id = document.getElementById('id');
			if(id.value.trim()==''){
				alert('아이디를 입력하세요!');
				id.focus();
				id.value='';
				return false;
			}
			var passwd = document.getElementById('passwd');
			if(passwd.value.trim()==''){
				alert('비밀번호를 입력하세요!');
				passwd.focus();
				passwd.value='';
				return false;
			}
			var cpasswd = document.getElementById('cpasswd'); /* cpasswd:최소한의 보안 */
			if(cpasswd.value.trim()==''){
				alert('비밀번호 확인을 입력하세요!');
				cpasswd.focus();
				cpasswd.value='';
				return false;
			}
			//비밀번호와 비밀번호 확인 일치여부 체크
			if(passwd.value!=cpasswd.value){
				alert('비밀번호와 비밀번호 확인이 불일치 합니다')
				cpasswd.focus();
				cpasswd.value='';
				return false;
			}
		};
	};
</script>
</head>
<body>
<div class="page-main">
	<h1>회원탈퇴</h1>
	<form action="deleteUser.jsp" method="post" id="delete_form">
		<ul>
			<li>
				<label for="id">아이디</label>
				<input  type="text" name="id"  id="id" maxlength="12">
			</li>
			<li>
				<label for="passwd">비밀번호</label>
				<input  type="password" name="passwd"  id="passwd" maxlength="12">
			</li>
			<li>
				<label for="cpasswd">비밀번호 확인</label>
				<input  type="password" name="cpasswd"  id="cpasswd" maxlength="12">
			</li>
		</ul>
		<div class="align-center">
			<input type="submit" value="회원탈퇴">
			<input type="button" value="홈으로" onclick="location.href='main.jsp'">
		</div>
	</form>
</div>
</body>
</html>
<%
	}
%>


src/main/webapp/views/deleteUser.jsp : 회원탈퇴 완료

인증할 때 VO객체를 반환하기 때문에 DAO, VO 둘 다  import해준다.

css도 link걸어준다.

 

여기서는 탈퇴하려는 아이디와 로그인되어있는 아이디를 비교하기위해 user_num아니라 user_id를 사용한다. 
(user_num을 이용해서 작성해도 된다) 

String user_id = (String)session.getAttribute("user_id");

cpasswd는 UI에서 체크하는 용도로만 썼기 때문에 전송된 데이터 반환을 하지않는다.

 

아이디와 비밀번호 일치 여부를 체크하는데

내가 입력한 아이디가 데이터가 있을 때 && 로그인 할 때 사용한 아이디랑 삭제하려는 아이디가 일치(친구의 아이디나 자신의 다른계정을 지울 수도 있기 때문에)

if(member!=null && user_id.equals(id)){

일치 했을 때 회원정보 삭제

dao.deleteMemeber(member.getNum());
회원정보가 삭제되었기 때문에 로그아웃처리를 해줘야한다.
session.invalidate();

 

 

노란줄이 뜨는 에러는 코드 위치상 HTML태그의 밖에 스크립트 코드가 명시되어있어서인데,

동적프로그래밍이므로,

스크립트코드는 탈퇴했을 때 만들어진 코드가 아니기 때문에 동작 상 아무런 문제가 없다.

▼ code

더보기
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ page import="kr.member.dao.MemberDAO" %>
<%@ page import="kr.member.vo.MemberVO" %>
<%
	String user_id = (String)session.getAttribute("user_id");
	if(user_id==null){ //로그인이 되지 않은 경우
		response.sendRedirect("loginForm.jsp");
	}else{ //로그인이 된 경우
		//전송된 데이터 인코딩 처리
		request.setCharacterEncoding("utf-8");
		//전송된 데이터 반환
		String id = request.getParameter("id");
		String passwd = request.getParameter("passwd");
		//cpasswd는 ui에서 체크하는 용도로만 썼기 때문에 여기서는 쓰지 않는다
		//id와 비밀번호 일치 여부 체크
		MemberDAO dao = MemberDAO.getInstance();
		MemberVO member = dao.checkMember(id);
		boolean check = false;
        
		if(member!=null && user_id.equals(id)){
			//비밀번호 일치 여부 체크
			check = member.isCheckedPassword(passwd);
            
		}if(check){ //인증 성공
			dao.deleteMemeber(member.getNum()); //회원 정보 삭제
			session.invalidate(); //로그아웃
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원 탈퇴</title>
<link rel="stylesheet" href="<%= request.getContextPath() %>/css/layout.css">
</head>
<body>
<div class="page-main">
	<h1>회원탈퇴 완료</h1>
	<div class="result-display">
		<div class="align-center">
			회원탈퇴가 완료되었습니다. <br>
			<input type="button" value="홈으로" onclick="location.href='main.jsp'">
		</div>
	</div>
</div>
</body>
</html>
<%
		}else{ //인증 실패 (아이디 또는 비밀번호가 잘못 됐을 경우)
%>
<script type="text/javascript">
	alert('아이디 또는 비밀번호가 불일치합니다.');
	history.go(-1);
</script>
<%
		}
	}
%>

 


회원관리

방명록

 

'WEB > ✿JSP' 카테고리의 다른 글

[JSP] 🔗MVC (4-1) 실습  (0) 2022.01.25
[JSP] 🔗/MVC (3) 실습  (0) 2022.01.25
[JSP] 🔗MVC  (0) 2022.01.20
[JSP] 🔗/EL & JSTL  (0) 2022.01.20
[JSP] 🔗모델1 구조(3) 실습  (0) 2022.01.18

댓글