SMBMS 프로젝트 비밀번호 변경 기능 구현

비밀번호 변경 기능 개요

본 프로젝트에서는 사용자 비밀번호 변경 기능을 구현한다. 이 기능은 데이터베이스와 직접적으로 연동되어야 하며, 보안상 비밀번호를 평문으로 저장하지 않고 해시 처리하는 것이 일반적인做法이다. 그러나 본 튜토리얼에서는 기본적인密码 변경 기능의 구현 과정에 집중한다.

1. 프론트엔드 링크 설정

먼저 사용자가 비밀번호 변경 페이지에 접근할 수 있는 메뉴 링크를 추가해야 한다. JSP 페이지에서 다음과 같이 앵커 태그를 추가한다.

<li><a href="${pageContext.request.contextPath }/jsp/passwordModify.jsp">비밀번호 변경</a></li>

2. 아키텍처 설계 원칙

프로젝트 구현 시에는 일반적으로 하위 계층부터 상위 계층으로 진행한다. 즉, DAO(Data Access Object) Layer부터 시작하여 Service Layer, 그리고 마지막으로 Servlet Layer를 구현하는 순서로 진행한다. 이러한 방식은 각 계층 간의 의존성을 명확히 하고 코드 재사용성을 높인다.

3. DAO 인터페이스 정의

데이터베이스 접근을 위한 인터페이스를 먼저 선언한다. 이 인터페이스는 비밀번호 변경에 필요한 메서드를 정의한다.

// 현재 사용자의 비밀번호를 수정한다
public int modifyUserPassword(Connection connection, int userId, String newPassword) throws SQLException;

4. DAO 구현 클래스 작성

인터페이스를 구현하는 클래스를 작성한다. 이 클래스에서는 실제 SQL 문을 실행하여 데이터베이스의 비밀번호를 업데이트한다.

package com.hospital.dao.user;

import com.hospital.dao.BaseDao;
import com.hospital.pojo.User;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class UserDaoImpl implements UserDao {
    
    // 데이터베이스에서 사용자 정보 조회
    public User getLoginUser(Connection connection, String loginId) throws SQLException {
        PreparedStatement pstm = null;
        ResultSet rs = null;
        User user = null;

        if (connection != null) {
            String sql = "select * from smbms_user where userCode=?";
            Object[] params = {loginId};

            rs = BaseDao.execute(connection, pstm, rs, sql, params);
            if (rs.next()) {
                user = new User();
                user.setId(rs.getInt("id"));
                user.setUserCode(rs.getString("userCode"));
                user.setUserName(rs.getString("userName"));
                user.setUserPassword(rs.getString("userPassword"));
                user.setGender(rs.getInt("gender"));
                user.setBirthday(rs.getDate("birthday"));
                user.setPhone(rs.getString("phone"));
                user.setAddress(rs.getString("address"));
                user.setUserRole(rs.getInt("userRole"));
                user.setCreatedBy(rs.getInt("createdBy"));
                user.setCreationDate(rs.getTimestamp("creationDate"));
                user.setModifyBy(rs.getInt("modifyBy"));
                user.setModifyDate(rs.getTimestamp("modifyDate"));
            }
            BaseDao.closeResource(null, pstm, rs);
        }
        return user;
    }

    // 사용자 비밀번호 수정
    public int modifyUserPassword(Connection connection, int userId, String newPassword) throws SQLException {
        PreparedStatement pstm = null;
        int resultCount = 0;
        
        if (connection != null) {
            String sql = "update smbms_user set userPassword = ? where id = ?";
            Object params[] = {newPassword, userId};
            resultCount = BaseDao.execute(connection, pstm, sql, params);
            BaseDao.closeResource(null, pstm, null);
        }
        return resultCount;
    }
}

5. Service 인터페이스 정의

비즈니스 로직을 처리하기 위한 Service 계층을 구성한다. Servlet에서 직접 DAO에 접근하지 않고 Service를 경유하여 처리한다.

// 사용자 ID를 기반으로 비밀번호를 변경한다
public boolean modifyPassword(int userId, String newPassword);

6. Service 구현 클래스 작성

Service 인터페이스를 구현하는 클래스를 작성한다. 여기서 트랜잭션 관리가 이루어진다.

public boolean modifyPassword(int userId, String newPassword) {
    Connection connection = null;
    boolean success = false;

    try {
        connection = BaseDao.getConnection();
        if (userDao.modifyUserPassword(connection, userId, newPassword) > 0) {
            success = true;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        BaseDao.closeResource(connection, null, null);
    }
    return success;
}

7. Servlet 컨트롤러 구현

사용자의 요청을 처리하고 응답을 반환하는 Servlet을 구현한다. 여기서는 클라이언트로부터 새 비밀번호를 받아 Service 계층으로 전달한다.

package com.hospital.servlet.user;

import com.hospital.pojo.User;
import com.hospital.service.user.UserServiceImpl;
import com.hospital.util.Constants;
import com.mysql.jdbc.StringUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String action = req.getParameter("method");
        if ("savepwd".equals(action) && action != null) {
            this.changePassword(req, resp);
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }

    public void changePassword(HttpServletRequest req, HttpServletResponse resp) {
        Object userSession = req.getSession().getAttribute(Constants.USER_SESSION);
        String newPassword = req.getParameter("newpassword");

        boolean flag = false;
        if (userSession != null && !StringUtils.isNullOrEmpty(newPassword)) {
            UserServiceImpl userService = new UserServiceImpl();
            flag = userService.modifyPassword(((User) userSession).getId(), newPassword);
            if (flag) {
                req.setAttribute("message", "비밀번호가 성공적으로 변경되었습니다. 새 비밀번호로 다시 로그인해 주세요.");
                req.getSession().removeAttribute(Constants.USER_SESSION);
            } else {
                req.setAttribute("message", "비밀번호 변경에 실패했습니다.");
            }
        } else {
            req.setAttribute("message", "새 비밀번호 값이 올바르지 않습니다.");
        }
        try {
            req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

8. Servlet 매핑 등록

web.xml 파일 또는 어노테이션을 사용하여 Servlet을 등록하고 URL 패턴을 매핑한다. 이렇게 해야 클라이언트의 요청이 올바른 Servlet으로 전달된다.

9. 테스트 및 디버깅

구현完成后 테스트를 수행한다. 만약 비밀번호 변경이 실패한다면 다음과 같은 원인을 확인해야 한다:

  • 데이터베이스 연결이 정상적으로 수립되었는지 확인
  • SQL 문법이 올바른지 검증
  • 파라미터 값이 정확히 전달되고 있는지 로그를 통해 확인
  • 트랜잭션이 제대로 커밋되었는지 확인

가장 흔한 문제는 DAO 层에서 SQL 실행 시 문제가 발생하는 것이다.PreparedStatement의 파라미터 순서와 값이 제대로 매핑되었는지 반드시 확인해야 한다.

태그: java Servlet JSP MySQL DAO

5월 30일 22:59에 게시됨