주니어 기초 코딩공부/JSP 기초

[JSP] 회원제 게시판 구현

jju_developer 2023. 1. 31. 17:26
728x90

안녕하세요 jju_developer입니다.

오늘은 학원에서 배운 회원제 게시판 구현에 대해 알아보도록 하겠습니다.

 

[ 지난 시간 ]

1. 예제를 위한 데이터 베이스 생성

2. 예제 이클립스 프로젝트 생성

3. 커넥션 관련 코드

(1) DBCPInitListener.java

(2) web.xml (서블릿정의, 파라미터, 필터)

// servlet: 자바클래스이며, http통신을 할 수 있다.(request, response)

init 메소드 , doGet 메서드

(3) ConnectionProvider.java (getConnection)

(4) dbconnTest.jsp (커넥션 테스트)

4. 캐릭터 인코딩 필터 설정 (필터이용한 구현 클래스 정의 doFilter, init 메서드 재정의)

-> 포스트 방식으로 데이터를 보낼 때에는 꼭 < % request.serCharacterEncording("uft-8");%>

매번 이거를 쓰기 귀찮아서 아래 코드로 정의

정의를 매번 하는 거 대신에 필터를 이용해서 정의 후 사용!

캐긹터 인코딩 필터 설정하기 위한 클래스

5. MVC 컨트롤러 코드

web.xml에 ControllerUsingURI를 위한 설정 추가.

WEB-INF아래 lib아래 jar 파일 필수

 

여기까지가 지난 시간에 배운 기본틀입니다.


회원 관련 주요 기능
 회원 가입
 회원 정보 수정하기
 로그인하기
 로그아웃하기
 로그인한 사람만 특정 기능 실행하기

 

회원 가입 기능 구현
 회원 가입 기능의 명세
• 회원 가입 요청을 하면 입력을 위한 폼이 필요합니다. (join.do를 치면 폼으로 이동)
• 입력 폼에 아이디, 이름, 암호, 암호 확인을 입력하고 전송하면 가입에 성공합니다.
• 동일한 아이디를 가진 회원이 존재하면 에러 메시지와 함께 다시 폼을 보여줍니다. (redirection)
• 입력한 암호와 암호 확인이 일치하지 않으면 에러 메시지와 함께 다시 폼을 보여줍니다.

 

join.do


                                                                                [MVC Model 2 방식 과정] 클래스 설계

browser -> request -> controller -> service -> dao - dbcp(jdbc) -> db
설명: 브라우저가 request를 보내면 controller(servlet, handler)가 받고 service로 가서 DAO로 넘기고 DB로 갑니다.
서비스에서는 dto(객체를 담았음), con(객체를 담았음) 을 가져와서 DAO로 넘깁니다.
DAO는 주로 데이터베이스 crud 기능을 하여 데이터베이스 (DB)에 저장합니다.
(crud : Create, Read, Update, Delete를 묶어서 일컫는 말이다.)

반대로 DB에서 member 테이블을 가져오고 member 객체인 vo를 만들고  session에 setAttribute로 맴버 객체를 담습니다.
담은 객체는 forward를 하게되는데, jsp로 넘겨줍니다. jsp는 뷰 역할만 하기로 했죠?
request.forward를 하여 jsp로 보내고 세션에서 session.getAttribute("member")를 해서 읽어옵니다.
읽어온 member를 response해주며 브라우저에 member 정보를 볼수 있게 되는 것 입니다.

 

get방식 : joinForm.jsp

post방식 : joinSucess.jsp

 

회원 가입 기능 구현 코드

 각 코드의 역할은 다음과 같습니다.
• JoinHandler : 사용자의 요청을 받습니다.
- joinForm.jsp : 회원 가입 폼을 보여줍니다.
- joinSuccess.jsp : 회원 가입 처리에 성공한 경우 결과를 보여줍니다.
• JoinService : 회원 가입 기능을 구현합니다.
- JoinRequest : 회원 가입할 때 필요한 데이터를 담습니다. 폼에 입력한 값을 이 객체에 담아 JoinService에 전달합니다.
• MemberDao : member 테이블과 관련된 쿼리를 실행합니다.
• Member : member 테이블과 관련된 클래스로서 회원 데이터를 담습니다. (member vo 객체)

 

 

회원 정보 보관을 위한 DB 테이블과 관련 Member 클래스

[board/sql/ddl.sql]

create table board.member (
memberid varchar(50) primary key,
name varchar(50) not null,
password varchar(10) not null,
regdate datetime not null
) engine=InnoDB default character set = utf8;

[board/src/member/model/Member.java]

 

sql의 테이블과 java의 member 클래스의 변수 이름이 조금 다릅니다.

지금은 데이터가 크지 않아 이름이 sql과 매칭이 되지 않아도 수동으로 매치해 줄 것이기 때문에

괜찮습니다.

 

MemberDao 구현

단순한 자바 클래스입니다.

package member.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

import jdbc.JdbcUtil;
import member.model.Member;

public class MemberDao {

	public Member selectById(Connection conn, String id) throws SQLException {
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = conn.prepareStatement(
					"select * from member where memberid = ?");
			pstmt.setString(1, id);
			rs = pstmt.executeQuery();
			Member member = null;
			if (rs.next()) {
				member = new Member(
						rs.getString("memberid"), 
						rs.getString("name"), 
						rs.getString("password"),
						toDate(rs.getTimestamp("regdate")));
			}
			return member;
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(pstmt);
		}
	}

	private Date toDate(Timestamp date) {
		return date == null ? null : new Date(date.getTime());
	}

	public void insert(Connection conn, Member mem) throws SQLException {
		try (PreparedStatement pstmt = 
				conn.prepareStatement("insert into member values(?,?,?,?)")) {
			pstmt.setString(1, mem.getId());
			pstmt.setString(2, mem.getName());
			pstmt.setString(3, mem.getPassword());
			pstmt.setTimestamp(4, new Timestamp(mem.getRegDate().getTime()));
			pstmt.executeUpdate();
		}
	}

	public void update(Connection conn, Member member) throws SQLException {
		try (PreparedStatement pstmt = conn.prepareStatement(
				"update member set name = ?, password = ? where memberid = ?")) {
			pstmt.setString(1, member.getName());
			pstmt.setString(2, member.getPassword());
			pstmt.setString(3, member.getId());
			pstmt.executeUpdate();
		}
	}
}

데이터 베이스를 구현할 수 있는 내용들이 나열되어 있습니다.

 

 

우선 화면을 먼저 봐볼까요?

web.xml을 보면

web.xml

~~~.do 를 적으면 해당하는 곳으로 이동합니다.

commandHandlerURLproperties

JoinHandler.java

package member.command;

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

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

import member.service.DuplicateIdException;
import member.service.JoinRequest;
import member.service.JoinService;
import mvc.command.CommandHandler;

public class JoinHandler implements CommandHandler {

	private static final String FORM_VIEW = "/WEB-INF/view/joinForm.jsp";
	private JoinService joinService = new JoinService();
	
	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) {
		if (req.getMethod().equalsIgnoreCase("GET")) {
			return processForm(req, res);
		} else if (req.getMethod().equalsIgnoreCase("POST")) {
			return processSubmit(req, res);
		} else {
			res.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
			return null;
		}
	}

	private String processForm(HttpServletRequest req, HttpServletResponse res) {
		return FORM_VIEW;
	}

	private String processSubmit(HttpServletRequest req, HttpServletResponse res) {
		JoinRequest joinReq = new JoinRequest();//자바빈객체 (DTO: data transfer object)
		joinReq.setId(req.getParameter("id"));
		joinReq.setName(req.getParameter("name"));
		joinReq.setPassword(req.getParameter("password"));
		joinReq.setConfirmPassword(req.getParameter("confirmPassword"));
		
		Map<String, Boolean> errors = new HashMap<>();
		req.setAttribute("errors", errors);
		
		joinReq.validate(errors);
		
		if (!errors.isEmpty()) {
			return FORM_VIEW;
		}
		
		try {
			joinService.join(joinReq);
			return "/WEB-INF/view/joinSuccess.jsp";
		} catch (DuplicateIdException e) {
			errors.put("duplicateId", Boolean.TRUE);
			return FORM_VIEW;
		}
	}

}

자바 핸들러 상세 설명!☆

이 부분에서 일일이 입력받은 객체를 맵핑해 주기 위해서 각각의 변수에 수동으로 넣어주는 부분입니다.

일반적으로 회사에서는 파라미터를 입력하는 부분이 많기 때문에

스프링에서는 자동으로 맵핑이 되는 기능을 활용합니다.

그렇게 자동으로 하기 위해서는 파라미터로 넘어가는 변수 이름과 자바빈 객체에 있는 필드명이 동일해야 합니다.

☆즉, 화면에 있는 이름과 자바빈객체의 이름, 멤버 객체에 있는 필드명과 db 테이블에 있는 칼럼명이 같아야 합니다.

(-> 이렇게 하면 유지보수도 쉬워집니다.)

 

아무튼 여기서 조인 request 부분에 자바빈 객체를 서비스로 넘깁니다.

joinservice로 보내게 됩니다!

 

조인서비스 부분을 볼까요?

 

JoinService.java

package member.service;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;

import jdbc.JdbcUtil;
import jdbc.connection.ConnectionProvider;
import member.dao.MemberDao;
import member.model.Member;

public class JoinService {

	private MemberDao memberDao = new MemberDao();

	public void join(JoinRequest joinReq) {
		Connection conn = null;
		try {
			conn = ConnectionProvider.getConnection();
			conn.setAutoCommit(false);
			
			//memberDao로 이동!
			Member member = memberDao.selectById(conn, joinReq.getId());
			if (member != null) {
				JdbcUtil.rollback(conn);
				throw new DuplicateIdException();
			}

			memberDao.insert(conn, new Member(joinReq.getId(), joinReq.getName(), joinReq.getPassword(), new Date()));
			conn.commit();
		} catch (SQLException e) {
			JdbcUtil.rollback(conn);
			throw new RuntimeException(e);
		} finally {
			JdbcUtil.close(conn);
		}
	}
}

 

처음에 폼에 등록을 하게 될 때에는 테이블에 아무런 정보가 없습니다.

ID가 있는지 없는지를 확인하기 위한 조인 서비스 클래스입니다.

 

member 객체에 null을 넣고 신규 rs에 next가 없기 때문에 false 가 됩니다.

그렇다면 member변수를 return 합니다.

==> null 이 return 됩니다.

여기서 또 memberDAO로 이동합니다!!!

 

memberDao

package member.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;

import jdbc.JdbcUtil;
import member.model.Member;

public class MemberDao {

	public Member selectById(Connection conn, String id) throws SQLException {
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		try {
			pstmt = conn.prepareStatement(
					"select * from member where memberid = ?");
			pstmt.setString(1, id);
			rs = pstmt.executeQuery();
			Member member = null;
			if (rs.next()) {
				member = new Member(
						rs.getString("memberid"), 
						rs.getString("name"), 
						rs.getString("password"),
						toDate(rs.getTimestamp("regdate")));
			}
			return member;
		} finally {
			JdbcUtil.close(rs);
			JdbcUtil.close(pstmt);
		}
	}

	private Date toDate(Timestamp date) {
		return date == null ? null : new Date(date.getTime());
	}

	public void insert(Connection conn, Member mem) throws SQLException {
		try (PreparedStatement pstmt = 
				conn.prepareStatement("insert into member values(?,?,?,?)")) {
			pstmt.setString(1, mem.getId());
			pstmt.setString(2, mem.getName());
			pstmt.setString(3, mem.getPassword());
			pstmt.setTimestamp(4, new Timestamp(mem.getRegDate().getTime()));
			pstmt.executeUpdate();
		}
	}

	public void update(Connection conn, Member member) throws SQLException {
		try (PreparedStatement pstmt = conn.prepareStatement(
				"update member set name = ?, password = ? where memberid = ?")) {
			pstmt.setString(1, member.getName());
			pstmt.setString(2, member.getPassword());
			pstmt.setString(3, member.getId());
			pstmt.executeUpdate();
		}
	}
}

멤버 DAO에서 이제 아이디가 일치하는 것이 없으니까

객체들을 저장해 주기 위해서 set을 해주게 됩니다!!

 

pstmt.executeUpdate(); 을 실행하게 되면  insert가 되고 문제가 없으면 con.commit을 하게 됩니다.

 

그다음 ControllerUsingURL.java에서 뷰로써 보여주게 되는 것이죠!

 

 

JoinForm.jsp

<%@ page contentType="text/html; charset=utf-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<title>가입</title>
</head>
<body>
<form action="join.do" method="post">
<p>
	아이디:<br/><input type="text" name="id" value="${param.id}">
	<c:if test="${errors.id}">ID를 입력하세요.</c:if>
	<c:if test="${errors.duplicateId}">이미 사용중인 아이디입니다.</c:if>
</p>
<p>
	이름:<br/><input type="text" name="name" value="${param.name}">
	<c:if test="${errors.name}">이름을 입력하세요.</c:if>
</p>
<p>
	암호:<br/><input type="password" name="password">
	<c:if test="${errors.password}">암호를 입력하세요.</c:if>
</p>
<p>
	확인:<br/><input type="password" name="confirmPassword">
	<c:if test="${errors.confirmPassword}">확인을 입력하세요.</c:if>
	<c:if test="${errors.notMatch}">암호와 확인이 일치하지 않습니다.</c:if>
</p>
<input type="submit" value="가입">
</form>
</body>
</html>

 

 

ControllerUsingURI

package mvc.controller;

import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import mvc.command.CommandHandler;
import mvc.command.NullHandler;

public class ControllerUsingURI extends HttpServlet {

    // <커맨드, 핸들러인스턴스> 매핑 정보 저장
    private Map<String, CommandHandler> commandHandlerMap = 
    		new HashMap<>();

    public void init() throws ServletException {
        String configFile = getInitParameter("configFile");
        Properties prop = new Properties();
        String configFilePath = getServletContext().getRealPath(configFile);
        try (FileReader fis = new FileReader(configFilePath)) {
            prop.load(fis);
        } catch (IOException e) {
            throw new ServletException(e);
        }
        Iterator keyIter = prop.keySet().iterator();
        while (keyIter.hasNext()) {
            String command = (String) keyIter.next();
            String handlerClassName = prop.getProperty(command);
            try {
                Class<?> handlerClass = Class.forName(handlerClassName);
                CommandHandler handlerInstance = 
                        (CommandHandler) handlerClass.newInstance();
                commandHandlerMap.put(command, handlerInstance);
            } catch (ClassNotFoundException | InstantiationException 
            		| IllegalAccessException e) {
                throw new ServletException(e);
            }
        }
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        process(request, response);
    }

    protected void doPost(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }

    private void process(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
		String command = request.getRequestURI();
		if (command.indexOf(request.getContextPath()) == 0) {
			command = command.substring(request.getContextPath().length());
		}
        CommandHandler handler = commandHandlerMap.get(command);
        if (handler == null) {
            handler = new NullHandler();
        }
        String viewPage = null;
        try {
            viewPage = handler.process(request, response);	//"/WEB-INF/view.joinForm.jsp"
        } catch (Throwable e) {
            throw new ServletException(e);
        }
        if (viewPage != null) {
	        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
	        dispatcher.forward(request, response);
        }
    }
}

 viewPage = handler.process(request, response); ==> "/WEB-INF/view.joinForm.jsp"

 

ControllerUsingURI 여기서 join sucess로 가는데요!

 

 

joinSucess.jsp

 

 

 

이렇게 갔다가 문제가 없으면 조인핸들러에서 조인 success로 가서 화면을 출력해 줍니다!!

 


이제 회원가입이 끝났으니, 

다음장에서 로그인 기능 구현에 대해서 보겠습니다.

 

 

 

728x90