EL을 사용한 Model2 방식

woom·2023년 1월 27일
0

MVC

목록 보기
6/6
post-thumbnail

⭐ Model 2

  • 요청에 대한 처리는 하나의 servlet에서 실행, 응답(출력)은 jsp에서 실행 (생산성, 유지보수의 효율성 ↑ )
  1. controller 역할하는 서블릿(모든 요청)

  2. model 역할하는 클래스(model을 통해 요청에 대한 처리 구현)

  • 모델은 요청을 처리하기 위해 서비스(database를 module화 한것, 즉, 다수의 sql을 하나의 메소드로 사용할 수 있도록 모듈화) 이용,
  • 서비스가 dao(DB와 연동)호출. 모델클래스가 갖는 메소드를 호출해서 처리, 이동 관련 정보를 통해 redirect(요청 처리 후 client에게 다시요청) or 포워드 이동(스레드 이동으로 url주소 미변경)
  1. view 역할하는 jsp (응답문서(html)를 만들어서 client에 전달)
  • model2 작성순서 : 1. dao 2. service 3. controller 4. model 5. view
  • 특별한 확장자(*.do)로 웹프로그램을 요청할 수 있도록 작성

  • client가 요청, 응답할 때 controller 처리는 request와 response를 매개변수로 사용하고 모델, view, controller가 같이 사용

📕 userinfo DTO

package xyz.itwill.dto;

public class UserinfoDTO {
	private String userid;
	private String password;
	private String name;
	private String email;
	private int status;
	
	public UserinfoDTO() {
		// TODO Auto-generated constructor stub
	}

	public String getUserid() {
		return userid;
	}

	public void setUserid(String userid) {
		this.userid = userid;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getEmail() {
		return email;
	}

	public void setEmail(String email) {
		this.email = email;
	}

	public int getStatus() {
		return status;
	}

	public void setStatus(int status) {
		this.status = status;
	}
}





📕 userinfo DAO (model2)

  • dao클래스에서 catch 대신에 throws SQLException으로 처리

  • dao, service, module 에서 모두 예외 처리 시 비효율 → dao, service는 throws로 떠넘긴후 module에서 예외처리 한번에 처리


package xyz.itwill.dao;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import xyz.itwill.dto.UserinfoDTO;

public class UserinfoModelTwoDAO extends JdbcDAO {
	private static UserinfoModelTwoDAO _dao;
	
	private UserinfoModelTwoDAO() {
		// TODO Auto-generated constructor stub
	}
	
	static {
		_dao=new UserinfoModelTwoDAO();		
	}
	
	public static UserinfoModelTwoDAO getDAO() {
		return _dao;
	}
	
	public int insertUserinfo(UserinfoDTO userinfo) throws SQLException {
		Connection con=null;
		PreparedStatement pstmt=null;
		int rows=0;
		try {
			con=getConnection();
			
			String sql="insert into userinfo values(?,?,?,?,?)";
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, userinfo.getUserid());
			pstmt.setString(2, userinfo.getPassword());
			pstmt.setString(3, userinfo.getName());
			pstmt.setString(4, userinfo.getEmail());
			pstmt.setInt(5, userinfo.getStatus());
			
			rows=pstmt.executeUpdate();
		} finally {
			close(con, pstmt);
		}
		return rows;
	}
	
	public int updateUserinfo(UserinfoDTO userinfo) throws SQLException {
		Connection con=null;
		PreparedStatement pstmt=null;
		int rows=0;
		try {
			con=getConnection();
			
			String sql="update userinfo set password=?,name=?,email=?,status=? where userid=?";
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, userinfo.getPassword());
			pstmt.setString(2, userinfo.getName());
			pstmt.setString(3, userinfo.getEmail());
			pstmt.setInt(4, userinfo.getStatus());
			pstmt.setString(5, userinfo.getUserid());
			
			rows=pstmt.executeUpdate();
		} finally {
			close(con, pstmt);
		}
		return rows;
	}
	
	public int deleteUserinfo(String userid) throws SQLException {
		Connection con=null;
		PreparedStatement pstmt=null;
		int rows=0;
		try {
			con=getConnection();
			
			String sql="delete from userinfo where userid=?";
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, userid);
			
			rows=pstmt.executeUpdate();
		} finally {
			close(con, pstmt);
		}
		return rows;
	}
	
	public UserinfoDTO selectUserinfo(String userid) throws SQLException {
		Connection con=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		UserinfoDTO userinfo=null;
		try {
			con=getConnection();
			
			String sql="select * from userinfo where userid=?";
			pstmt=con.prepareStatement(sql);
			pstmt.setString(1, userid);
			
			rs=pstmt.executeQuery();
			
			if(rs.next()) {
				userinfo=new UserinfoDTO();
				userinfo.setUserid(rs.getString("userid"));
				userinfo.setPassword(rs.getString("password"));
				userinfo.setName(rs.getString("name"));
				userinfo.setEmail(rs.getString("email"));
				userinfo.setStatus(rs.getInt("status"));
			}
		} finally {
			close(con, pstmt, rs);
		}
		return userinfo;
	}
	
	public List<UserinfoDTO> selectUserinfoList() throws SQLException {
		Connection con=null;
		PreparedStatement pstmt=null;
		ResultSet rs=null;
		List<UserinfoDTO> userinfoList=new ArrayList<>();
		try {
			con=getConnection();
			
			String sql="select * from userinfo order by userid";
			pstmt=con.prepareStatement(sql);
			
			rs=pstmt.executeQuery();
			
			while(rs.next()) {
				UserinfoDTO userinfo=new UserinfoDTO();
				userinfo.setUserid(rs.getString("userid"));
				userinfo.setPassword(rs.getString("password"));
				userinfo.setName(rs.getString("name"));
				userinfo.setEmail(rs.getString("email"));
				userinfo.setStatus(rs.getInt("status"));
				userinfoList.add(userinfo);
			}
		} finally {
			close(con, pstmt, rs);
		}
		return userinfoList;
	}
}





📙 userinfo Service

  • Service 클래스 : 모델(Model) 클래스의 요청 처리 메소드에게 데이타베이스 관련 처리 기능을 제공하기 위한 클래스

    • 단위 프로그램(모듈 프로그램), 컴퍼넌트(Component) : 기능을 제공할 수 있는 최소 단위
  • 다수의 DAO 클래스의 메소드를 호출하여 필요한 기능을 제공하기 위한 메소드 작성 (모듈화)

  • 데이타베이스 관련 기능 구현시 발생되는 모든 문제에 대한 인위적 예외 발생

  • 싱글톤 디자인 패턴 적용

  1. 회원정보를 전달받아 USERINFO 테이블에 삽입하는 메소드

    • 전달받은 회원정보의 아이디가 USERINFO 테이블에 저장된 기존 회원정보의 아이디와 중복될 경우 인위적 예외 발생
  2. 회원정보를 전달받아 USERINFO 테이블에 저장된 회원정보를 변경하는 메소드

    • 전달받은 회원정보가 USERINFO 테이블에 없는 경우 인위적 예외 발생
  3. 아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 삭제하는 메소드

    • 전달받은 아이디의 회원정보가 USERINFO 테이블에 없는 경우 인위적 예외 발생
  4. 아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 검색하여 반환하는 메소드

    • 전달받은 아이디의 회원정보가 USERINFO 테이블에 없는 경우 인위적 예외 발생
  5. USERINFO 테이블에 저장된 모든 회원정보를 검색하여 반환하는 메소드

  6. 아이디와 비밀번호를 전달받아 인증 처리하는 메소드

    • 인증 실패시 인위적 예외 발생 (예외가 발생되지 않은 경우 인증 성공)

package xyz.itwill.service;

public class UserinfoService {
	private static UserinfoService _service;
	
	private UserinfoService() {
		// TODO Auto-generated constructor stub
	}
	
	static {
		_service=new UserinfoService();
	}
	
	public static UserinfoService getService() {
		return _service;
	}
	
	//1. 회원정보를 전달받아 USERINFO 테이블에 삽입하는 메소드
	// => 전달받은 회원정보의 아이디가 USERINFO 테이블에 저장된 기존 회원정보의 아이디와 
	//중복될 경우 인위적 예외 발생
	public void addUserinfo(UserinfoDTO userinfo) throws SQLException, ExistsUserinfoException {
		if(UserinfoModelTwoDAO.getDAO().selectUserinfo(userinfo.getUserid())!=null) {
			//예외가 발생될 경우 아래에 작성된 명령 미실행 (예외 객체를 생성하여 인위적인 예외 발생)
			throw new ExistsUserinfoException("이미 사용중인 아이디를 입력 하였습니다.");
		}
		UserinfoModelTwoDAO.getDAO().insertUserinfo(userinfo);
	}
	
	//2. 회원정보를 전달받아 USERINFO 테이블에 저장된 회원정보를 변경하는 메소드
	// => 전달받은 회원정보가 USERINFO 테이블에 없는 경우 인위적 예외 발생
	public void modifyUserinfo(UserinfoDTO userinfo) throws SQLException, UserinfoNotFoundException {
		if(UserinfoModelTwoDAO.getDAO().selectUserinfo(userinfo.getUserid())==null) {
			throw new UserinfoNotFoundException("회원정보가 존재하지 않습니다.");
		}
		UserinfoModelTwoDAO.getDAO().updateUserinfo(userinfo);
	}
	
	//3. 아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 삭제하는 메소드
	// => 전달받은 아이디의 회원정보가 USERINFO 테이블에 없는 경우 인위적 예외 발생
	public void removeUserinfo(String userid) throws SQLException, UserinfoNotFoundException {
		if(UserinfoModelTwoDAO.getDAO().selectUserinfo(userid)==null) {
			throw new UserinfoNotFoundException("회원정보가 존재하지 않습니다.");
		}
		UserinfoModelTwoDAO.getDAO().deleteUserinfo(userid);
	}
	
	//4. 아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 검색하여 반환하는 메소드
	// => 전달받은 아이디의 회원정보가 USERINFO 테이블에 없는 경우 인위적 예외 발생
	public UserinfoDTO getUserinfo(String userid) throws SQLException, UserinfoNotFoundException {
		if(UserinfoModelTwoDAO.getDAO().selectUserinfo(userid)==null) {
			throw new UserinfoNotFoundException("회원정보가 존재하지 않습니다.");
		}
		return UserinfoModelTwoDAO.getDAO().selectUserinfo(userid);
	}
	
	//5. USERINFO 테이블에 저장된 모든 회원정보를 검색하여 반환하는 메소드
	public List<UserinfoDTO> getUserinfoList() throws SQLException {
		return UserinfoModelTwoDAO.getDAO().selectUserinfoList();
	}
	
	//6. 아이디와 비밀번호를 전달받아 인증 처리하는 메소드
	// => 인증 실패시 인위적 예외 발생 - 예외가 발생되지 않은 경우 인증 성공
	public void auth(String userid, String password) throws SQLException, AuthFailException {
		UserinfoDTO userinfo=UserinfoModelTwoDAO.getDAO().selectUserinfo(userid);
		if(userinfo==null) {//아이디 인증 실패
			throw new AuthFailException("입력된 아이디가 존재하지 않습니다.");
		}
		
		if(!userinfo.getPassword().equals(password)) {//비밀번호 인증 실패
			throw new AuthFailException("입력된 아이디가 잘못 되었거나 비밀번호가 맞지 않습니다.");
		}
	}
}





📌 예외 클래스

  1. 회원정보(아이디)가 중복될 경우 발생될 예외를 표현하기 위한 클래스

    • 예외 클래스는 반드시 Exception 클래스를 상속받아 작성
package xyz.itwill.exception;


public class ExistsUserinfoException extends Exception {
	private static final long serialVersionUID = 1L;
    //객체 직렬화
	
	public ExistsUserinfoException() { } //기본 생성자
	
	public ExistsUserinfoException(String message) {
		super(message);
	}
}




  1. 회원정보를 찾을 수 없을 경우 발생될 예외를 표현하기 위한 클래스
package xyz.itwill.exception;

public class UserinfoNotFoundException extends Exception {
	private static final long serialVersionUID = 1L;

	public UserinfoNotFoundException() { }
	
	public UserinfoNotFoundException(String message) {
		super(message);
	}
}




  1. 인증이 실패한 경우 발생될 예외를 표현하기 위한 클래스
package xyz.itwill.exception;

public class AuthFailException extends Exception {
	private static final long serialVersionUID = 1L;

	public AuthFailException() { }
	
	public AuthFailException(String message) {
		super(message);
	}
}




📙 ControllerServlet

  • 컨트롤러(Controller - Servlet) : 클라이언트의 모든 요청을 받아 모델(Model - Class)의 요청처리 메소드를 호출하여 요청을 처리하고 처리결과를 뷰(View - JSP)로 전달하여 응답되도록 제어하는 웹프로그램
    1. 클라이언트의 모든 요청을 받을 수 있도록 서블릿을 설정하여 단일 진입점의 기능 구현
    • Front Controller Pattern
    • @WebServlet("URL") : 서블릿 클래스를 웹프로그램(서블릿)으로 등록하고 요청 URL 주소를 매핑하는 어노테이션
    • 매핑 설정될 URL 주소에 패턴문자(* : 전체 또는 ? : 문자 하나)를 사용하여 URL 패턴 등록 가능
    • @WebServlet("*.do") : 클라이언트가 [XXX.do] 형식의 URL 주소로 요청한 경우 서블릿 실행
    • @WebServlet 어노테이션 대신 [web.xml] 파일에서 서블릿 클래스를 웹프로그램(서블릿)으로 등록하고 URL 주소 매핑 처리 (권장)
  • HttpServlet을 상속받을 경우 service 메소드 오버라이드 선언
    • 클라이언트의 요청을 처리하기 위한 자동 호출되는 메소드
    • 클라이언트가 서블릿(웹프로그램)을 요청할 때마다 서블릿 객체를 이용하여 반복적으로 호출
    1. 클라이언트 요청 분석 : 요청 URL 주소 이용 - http://localhost:8000/mvc/XXX.do
    • HttpServletRequest.getRequestURI() : 요청 URL 주소에서 URI 주소를 반환하는 메소드
    • String requestURI=request.getRequestURI();//requestURI = /mvc/XXX.do
    • HttpServletRequest.getContextPath() : 요청 URL 주소에서 컨텍스트 경로를 반환하는 메소드
    • String contextPath=request.getContextPath();//contextPath = /mvc
    • 클라이언트 요청에 대한 요청값을 반환받아 저장
    • String command=requestURI.substring(contextPath.length());//command = /XXX.do
    1. 클라이언트 요청을 모델(Model)을 사용하여 처리하고 뷰(View) 관련 정보를 반환받아 저장
  • 모델 역할의 Java 클래스로 객체를 생성하여 요청 처리 메소드 호출
  • 하나의 요청에 대해 하나의 모델이 처리되도록 설정 (Command Controller Pattern)
  • 회원관리 프로그램에서 클라이언트 요청에 대한 모델 객체가 매핑되도록 설계
    • => 로그인정보 입력페이지(환영메세지 출력페이지) - /loginForm.do >> LoginFormModel Class
    • => 로그인 처리페이지 - /login.do >> LoginModel Class
    • => 로그아웃 처리페이지 - /logout.do >> LogoutModel Class
    • => 회원정보 입력페이지 - /writeForm.do >> WriteFormModel Class
    • => 회원정보 삽입페이지 - /write.do >> WriteModel Class
    • => 회원목록 출력페이지 - /list.do >> ListModel Class
    • => 회원정보 출력페이지 - /view.do >> ViewModel Class
    • => 변경회원정보 입력페이지 - /modifyForm.do >> ModifyFormModel Class
    • => 회원정보 변경페이지 - /modify.do >> ModifyModel Class
    • => 회원정보 삭제페이지 - /remove.do >> RemoveModel Class
    • => 에러메세지 출력페이지 - /error.do >> ErrorModel Class
  • 모델 클래스가 상속받은 인터페이스를 이용하여 참조변수 선언
    • 참조변수에는 인터페이스를 상속받은 모든 자식클래스(모델)로 생성된 객체 저장 가능
		Action action=null;
		
		if(command.equals("/loginForm.do")) {
			action=new LoginFormModel();
		} else if(command.equals("/login.do")) {
			action=new LoginModel();
		} else {//요청에 대한 모델 클래스가 없는 경우
			action=new ErrorModel();
		}
  • 인터페이스 참조변수를 이용하여 추상메소드를 호출하면 참조변수에 저장된 모델 객체에 오버라이드 선언된 요청 처리 메소드 호출
    • 오버라이드에 의한 다형성 (동일한 요청처리 메소드(excute)로 다른 객체(model class)를 생성하여 처리 가능)
    • 요청 처리 메소드에 의해 요청 처리 후 응답 관련 정보가 저장된 ActionForward 객체를 반환받아 저장
    • ActionForward actionForward=action.execute(request, response);
    1. 응답 관련 정보가 저장된 ActionForward 객체를 이용하여 응답 처리
    • request.getRequestDispatcher(String url) : URL 주소가 저장된 RequestDispatcher 객체를 반환하는 메소드
    • RequestDispatcher 객체 : 다른 웹프로그램으로 스레드를 이동하기 위한 기능을 제공하는 객체
    • RequestDispatcher.forward(request, response) : 요청 웹프로그램에서 다른 웹프로그램으로 스레드를 이동시켜 응답처리하기 위한 메소드 (포워드 이동)
    • 요청 웹프로그램의 request 객체와 response 객체를 스레드가 이동되는 웹프로그램으로 전달
if(actionForward.isForward()) {//ActionForward 객체의 forward 필드값이 [true]인 경우 - 포워드 이동
//컨트롤러에서 뷰(XXX.jsp)로 스레드를 이동하여 JSP 문서의 실행결과(HTML 문서)를 클라이언트에게 전달하여 응답
request.getRequestDispatcher(actionForward.getPath()).forward(request, response);
} else {//ActionForward 객체의 forward 필드값이 [false]인 경우 - 라다이렉트 이동
//컨트롤러에서 클라이언트에게 요청 URL 주소(XXX.do)를 전달하여 재요청하도록 응답
response.sendRedirect(actionForward.getPath());
} 

🎀 효율적인 컨트롤러

  • 컨트롤러에서 클라이언트 요청을 받은 모델 클래스로 객체 생성하는 방법
  1. if문 이용 → 가독성 감소(많은 시간 소요)

  2. Map 객체 이용 → 유지보수 효율성 감소 (요청 모델을 클래스에 작성시 war파일로 만들어서 웹서버를 실행하면 수정할때마다 controller를 수정하고 이에 따라 수정된 war파일을 다시 다운로드 해야함) → text파일(properties)로 작성

  3. properties 파일 이용 ★ → 프로젝트가 바뀌어도 수정할 필요 없음 → 유지보수 효율성 증가

    • porperties 파일을 읽어 객체로 만든 후 map으로 만들어 줘야 함(문자열만으로는 객체 생성 불가)
    • 리플렉션 : 프로그램 명령 실행 시 클래스를 읽어 객체를 생성하고 메모리를 통해 직접 접근 (Spring에서 자동 실행)

  • Map 객체 이용
  • 요청정보(Key - String)와 모델 객체(Value - Action)를 하나의 요소(Entry)로 묶어 여러개 저장할 Map 객체의 필드 생성
    • Map 객체를 이용하여 요청정보(Key)로 모델 객체(Value)를 빠르게 제공받기 위해 사용
    • private Map<String, Action> actionMap;
  • 클라이언트 최초 요청에 의해 서블릿 객체가 생성된 후 가장 먼저 자동으로 1번만 호출되는 메소드 (init)
    • 서블릿 객체의 초기화 작업을 위해 오버라이드 선언
	@Override
	public void init(ServletConfig config) throws ServletException {
		//System.out.println("ControllerServlet 클래스의 init() 메소드 호출");
		actionMap=new HashMap<String, Action>();
		
		//Map 객체에 엔트리(Entry - Key : 요청정보, Value : 모델 객체) 추가
		actionMap.put("/loginForm.do", new LoginFormModel());
		actionMap.put("/login.do", new LoginModel());
		actionMap.put("/error.do", new ErrorModel());
	}

  • properties 파일 이용

  • Properties 파일에 요청정보와 모델 클래스를 저장하고 파일을 읽어 Map 객체의 엔트리 추가

  • 유지보수의 효율성 증가 - 컨트롤러를 변경하지 않고 Properties 파일만 변경하여 요청정보와 모델 객체 변경 가능

  • Properties 파일(XXX.properties) : 프로그램 실행에 필요한 값을 제공하기 위한 텍스트 파일

    • Properties 파일의 정보를 저장하기 위한 Properties 객체 생성
      Properties properties=new Properties();
    • ServletConfig.getInitParameter(String name) : [web.xml] 파일에서 init-param 엘리먼트로 제공되는 값을 읽어와 반환하는 메소드
      String configFile=config.getInitParameter("configFile"); : /WEB-INF/model.properties
    • Properties 파일의 시스템 경로를 반환받아 저장
      String configFilePath=config.getServletContext().getRealPath(configFile);
    • : C:\java\apache-tomcat-9.0.68\webapps\mvc\WEB-INF\model.properties
    • Properties 파일에 대한 입력스트림을 생성하여 저장
      FileInputStream in=new FileInputStream(configFilePath);
    • 입력스트림을 사용하여 Properties 파일의 내용을 읽어 Properties 객체에 엔트리로 저장
      properties.load(in);
    • Properties 객체의 모든 키(Key)를 반환받아 반복 처리
    • Properties.keySet() : Properties 객체에 저장된 모든 엔트리의 키(Key)를 Set 객체로 반환하는 메소드
      for(Object key:properties.keySet()) { : Set 객체로부터 요소를 하나씩 제공받아 반복 처리
    • Properties 객체에 저장된 엔트리의 키(Key) - 요청정보
      String actionCommand=(String)key;
    • Properties 객체에 저장된 엔트리의 값(Value) - 모델 클래스
      String actionClass=(String)properties.get(key);
  • 모델 클래스를 이용하여 모델 객체 생성 → 리플렉션 기능 사용

    • 리플렉션(Reflection) : 프로그램 실행시 클래스(Clazz)를 읽어 객체를 생성하고 객체의 필드 또는 메소드에 접근하도록 제공하는 기능
    • Class.forName(String className) : 문자열로 표현된 클래스를 전달받아 클래스를 읽어 메모리에 저장하고 Class 객체(Clazz)를 반환하는 메소드 → ClassNotFoundException 발생
    • Class.getDeclaredConstructor() : 메모리에 저장된 클래스(Class 객체)의 생성자가 저장된 Constructor 객체를 반환하는 메소드
    • Constructor.newInstance() : Constructor 객체에 저장된 생성자를 이용하여 Object 타입의 객체를 생성하여 반환하는 메소드
      Action actionObject=(Action)Class.forName(actionClass).getDeclaredConstructor().newInstance();
    • Map 객체에 엔트리(Entry - Key : 요청정보, Value : 모델 객체) 추가
      actionMap.put(actionCommand, actionObject);
    • Map 객체에 저장된 엔트리에서 요청정보(Key)를 이용하여 모델 객체(Value)를 반환받아 저장 (메모리 효율 및 가독성 증가)
      Action action=actionMap.get(command);




package xyz.itwill.mvc;


//1.클라이언트의 모든  요청을 받을 수 있도록 서블릿을 설정하여 단일 진입점의 기능 구현
//@WebServlet("URL") : 서블릿 클래스를 웹프로그램(서블릿)으로 등록하고 요청 URL 주소를 매핑하는 어노테이션
//@WebServlet("*.do") : 클라이언트가 [XXX.do] 형식의 URL 주소로 요청한 경우 서블릿 실행
//@WebServlet 어노테이션 대신 [web.xml] 파일에서 서블릿 클래스를 웹프로그램(서블릿)으로 등록하고 URL 주소 매핑 처리
public class ControllerServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	//요청정보(Key - String)와 모델 객체(Value - Action)를 하나의 요소(Entry)로 묶어 여러개
	//저장할 Map 객체의 필드
	// => Map 객체를 이용하여 요청정보(Key)로 모델 객체(Value)를 빠르게 제공받기 위해 사용
	private Map<String, Action> actionMap;
	
	//클라이언트 최초 요청에 의해 서블릿 객체가 생성된 후 가장 먼저 자동으로 1번만 호출되는 메소드
	// => 서블릿 객체의 초기화 작업을 위해 오버라이드 선언
	@Override
	public void init(ServletConfig config) throws ServletException {
		//System.out.println("ControllerServlet 클래스의 init() 메소드 호출");
		
		actionMap=new HashMap<String, Action>();
		
		/*
		//Map 객체에 엔트리(Entry - Key : 요청정보, Value : 모델 객체) 추가
		actionMap.put("/loginForm.do", new LoginFormModel());
		actionMap.put("/login.do", new LoginModel());
		actionMap.put("/logout.do", new LogoutModel());
		actionMap.put("/writeForm.do", new WriteFormModel());
		actionMap.put("/write.do", new WriteModel());
		actionMap.put("/list.do", new ListModel());
		actionMap.put("/view.do", new ViewModel());
		actionMap.put("/modifyForm.do", new ModifyFormModel());
		actionMap.put("/modify.do", new ModifyModel());
		actionMap.put("/remove.do", new RemoveModel());
		actionMap.put("/error.do", new ErrorModel());
		*/
		
		//Properties 파일에 요청정보와 모델 클래스를 저장하고 파일을 읽어 Map 객체의 엔트리 추가
		// => 유지보수의 효율성 증가 - 컨트롤러를 변경하지 않고 Properties 파일만 변경하여
		//요청정보와 모델 객체 변경 가능
		//Properties 파일(XXX.properties) : 프로그램 실행에 필요한 값을 제공하기 위한 텍스트 파일
		
		//Properties 파일의 정보를 저장하기 위한 Properties 객체 생성
		Properties properties=new Properties();
		
		//ServletConfig.getInitParameter(String name) : [web.xml] 파일에서 init-param 
		//엘리먼트로 제공되는 값을 읽어와 반환하는 메소드		
		String configFile=config.getInitParameter("configFile");
		//System.out.println("configFile = "+configFile);
		
		//Properties 파일의 시스템 경로를 반환받아 저장
		//String configFilePath=config.getServletContext().getRealPath("/WEB-INF/model.propeties");
		String configFilePath=config.getServletContext().getRealPath(configFile);
		//System.out.println("configFilePath = "+configFilePath);
		
		try {
			//Properties 파일에 대한 입력스트림을 생성하여 저장
			FileInputStream in=new FileInputStream(configFilePath);
			
			//입력스트림을 사용하여 Properties 파일의 내용을 읽어 Properties 객체에 엔트리로 저장
			properties.load(in);
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//Properties 객체의 모든 키(Key)를 반환받아 반복 처리
		//Properties.keySet() : Properties 객체에 저장된 모든 엔트리의 키(Key)를 Set 객체로 반환하는 메소드
		for(Object key:properties.keySet()) {//Set 객체로부터 요소를 하나씩 제공받아 반복 처리
			//Properties 객체에 저장된 엔트리의 키(Key) - 요청정보
			String actionCommand=(String)key;
			
			//Properties 객체에 저장된 엔트리의 값(Value) - 모델 클래스
			String actionClass=(String)properties.get(key);
			
			try {
				//모델 클래스를 이용하여 모델 객체 생성 - 리플렉션 기능 사용
				//리플렉션(Reflection) : 프로그램 실행시 클래스(Clazz)를 읽어 객체를 생성하고
				//객체의 필드 또는 메소드에 접근하도록 제공하는 기능
				//Class.forName(String className) : 문자열로 표현된 클래스를 전달받아 클래스를
				//읽어 메모리에 저장하고 Class 객체(Clazz)를 반환하는 메소드 - ClassNotFoundException 발생
				//Class.getDeclaredConstructor() : 메모리에 저장된 클래스(Class 객체)의 생성자가 저장된
				//Constructor 객체를 반환하는 메소드
				//Constructor.newInstance() : Constructor 객체에 저장된 생성자를 이용하여
				//Object 타입의 객체를 생성하여 반환하는 메소드
				Action actionObject=(Action)Class
					.forName(actionClass).getDeclaredConstructor().newInstance();
				
				//Map 객체에 엔트리(Entry - Key : 요청정보, Value : 모델 객체) 추가
				actionMap.put(actionCommand, actionObject);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	//클라이언트의 요청을 처리하기 위한 자동 호출되는 메소드
	// => 클라이언트가 서블릿(웹프로그램)을 요청할 때마다 서블릿 객체를 이용하여 반복적으로 호출
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//System.out.println("ControllerServlet 클래스의 service() 메소드 호출");
		
		//2.클라이언트 요청 분석 : 요청 URL 주소 이용 - http://localhost:8000/mvc/XXX.do
		//HttpServletRequest.getRequestURI() : 요청 URL 주소에서 URI 주소를 반환하는 메소드 
		String requestURI=request.getRequestURI();
		//System.out.println("requestURI = "+requestURI);//requestURI = /mvc/XXX.do
		
		//HttpServletRequest.getContextPath() : 요청 URL 주소에서 컨텍스트 경로를 반환하는 메소드 
		String contextPath=request.getContextPath();
		//System.out.println("contextPath = "+contextPath);//contextPath = /mvc
		
		//클라이언트 요청에 대란 요청값을 반환받아 저장
		String command=requestURI.substring(contextPath.length());
		//System.out.println("command = "+command);//command = /XXX.do
		
		//3.클라이언트 요청을 모델(Model)을 사용하여 처리하고 뷰(View) 관련 정보를 반환받아 저장
		// => 모델 역활의 Java 클래스로 객체를 생성하여 요청 처리 메소드 호출
		// => 하나의 요청에 대해 하나의 모델이 처리되도록 설정 - Command Controller Pattern
		
		//회원관리 프로그램에서 클라이언트 요청에 대한 모델 객체가 매핑되도록 설계
		// => 로그인정보 입력페이지(환영메세지 출력페이지) - /loginForm.do >> LoginFormModel Class
		// => 로그인 처리페이지 - /login.do >> LoginModel Class
		// => 로그아웃 처리페이지 - /logout.do >> LogoutModel Class
		// => 회원정보 입력페이지 - /writeForm.do >> WriteFormModel Class
		// => 회원정보 삽입페이지 - /write.do >> WriteModel Class
		// => 회원목록 출력페이지 - /list.do >> ListModel Class
		// => 회원정보 출력페이지 - /view.do >> ViewModel Class
		// => 변경회원정보 입력페이지 - /modifyForm.do >> ModifyFormModel Class
		// => 회원정보 변경페이지 - /modify.do >> ModifyModel Class
		// => 회원정보 삭제페이지 - /remove.do >> RemoveModel Class
		// => 에러메세지 출력페이지 - /error.do >> ErrorModel Class
		
		/*
		//모델 클래스가 상속받은 인터페이스를 이용하여 참조변수 선언
		// => 참조변수에는 인터페이스를 상속받은 모든 자식클래스(모델)로 생성된 객체 저장 가능
		Action action=null;
		
		if(command.equals("/loginForm.do")) {
			action=new LoginFormModel();
		} else if(command.equals("/login.do")) {
			action=new LoginModel();
		} else if(command.equals("/logout.do")) {
			action=new LogoutModel();
		} else if(command.equals("/writeForm.do")) {
			action=new WriteFormModel();
		} else if(command.equals("/write.do")) {
			action=new WriteModel();
		} else if(command.equals("/list.do")) {
			action=new ListModel();
		} else if(command.equals("/view.do")) {
			action=new ViewModel();
		} else if(command.equals("/modifyForm.do")) {
			action=new ModifyFormModel();
		} else if(command.equals("/modify.do")) {
			action=new ModifyModel();
		} else if(command.equals("/remove.do")) {
			action=new RemoveModel();
		} else if(command.equals("/error.do")) {
			action=new ErrorModel();
		} else {//요청에 대한 모델 클래스가 없는 경우
			action=new ErrorModel();
		}
		*/
		
		//Map 객체에 저장된 엔트리에서 요청정보(Key)를 이용하여 모델 객체(Value)를 반환받아 저장
		// => 메모리 효율 및 가독성 증가
		Action action=actionMap.get(command);
		if(action==null) {//참조변수에 요청에 대한 모델 객체가 저장되어 있지 않은 경우
			action=actionMap.get("/error.do");
		}
		
		//인터페이스 참조변수를 이용하여 추상메소드를 호출하면 참조변수에 저장된 모델 객체에
		//오버라이드 선언된 요청 처리 메소드 호출 - 오버라이드에 의한 다형성
		// => 요청 처리 메소드에 의해 요청 처리 후 응답 관련 정보가 저장된 ActionForward 
		//객체를 반환받아 저장
		ActionForward actionForward=action.execute(request, response);
		
		//4.응답 관련 정보를 저장된 ActionForward 객체를 이용하여 응답 처리
		if(actionForward.isForward()) {//ActionForward 객체의 forward 필드값이 [true]인 경우 - 포워드 이동
			//컨트롤러에서 뷰(XXX.jsp)로 스레드를 이동하여 JSP 문서의 실행결과(HTML 문서)를 
			//클라이언트에게 전달하여 응답
			request.getRequestDispatcher(actionForward.getPath()).forward(request, response);
		} else {//ActionForward 객체의 forward 필드값이 [false]인 경우 - 라다이렉트 이동
			//컨트롤러에서 클라이언트에게 요청 URL 주소(XXX.do)를 전달하여 재요청하도록 응답
			response.sendRedirect(actionForward.getPath());
		}
	}
}





🎀 컨트롤러 최종 요약

package xyz.itwill.mvc;

public class ControllerServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	private Map<String, Action> actionMap;

	@Override//자동으로 1번만 호출되는 init메소드 오버라이드 선언
	public void init(ServletConfig config) throws ServletException {
		
		actionMap=new HashMap<String, Action>();
		Properties properties=new Properties();
		
		String configFile=config.getInitParameter("configFile");
        //[web.xml] 파일에서 init-param 엘리먼트로 제공되는 값 : /WEB-INF/model.properties
		
		String configFilePath=config.getServletContext().getRealPath(configFile);
        //Properties 파일의 시스템 경로 : C:\java\apache-tomcat-9.0.68\webapps\mvc\WEB-INF\model.properties
		
		try {
			FileInputStream in=new FileInputStream(configFilePath);//파일에 대한 입력스트림
			properties.load(in);//Properties 파일을 읽어 Properties 객체에 엔트리로 저장
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		for(Object key:properties.keySet()) {//Set 객체로부터 properties의 키를 하나씩 제공받아 반복 처리
			String actionCommand=(String)key;//Properties 객체에 저장된 엔트리의 키 (요청정보)
			
			String actionClass=(String)properties.get(key);//엔트리의 값 (모델 클래스) : just 문자
			
			try {
				Action actionObject=(Action)Class.forName(actionClass).getDeclaredConstructor().newInstance();
				//모델 클래스를 이용하여 Object 타입의 모델 객체 생성 (리플렉션 이용)
                
				actionMap.put(actionCommand, actionObject);
                //Map 객체에 엔트리(Entry - Key : 요청정보, Value : 모델 객체) 추가
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}
	
	//클라이언트의 요청을 처리하기 위해 자동 호출되는 service메소드 오버라이드 (요청할때마다 반복 호출)
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		
		String requestURI=request.getRequestURI();//요청URI 주소(/mvc/XXX.do)
		String contextPath=request.getContextPath();//컨텍스트 경로 (/mvc)
		
		String command=requestURI.substring(contextPath.length());//client 요청값(/XXX.do)

		Action action=actionMap.get(command);
        //Map 객체에 저장된 엔트리에서 요청정보(Key:.do)를 이용하여 모델 객체(Value:model class)를 반환받아 저장
        //model 객체 클래스의 메소드 호출 (하나의 요청에 대해 하나의 모델 처리)
        
		if(action==null) {//참조변수에 요청에 대한 모델 객체가 저장되어 있지 않은 경우
			action=actionMap.get("/error.do");
		}

		ActionForward actionForward=action.execute(request, response);
        //모델 클래스에서 오버라이드 선언된 요청 처리 메소드 호출
		
		if(actionForward.isForward()) {//ActionForward 객체를 이용하여 응답 처리
			request.getRequestDispatcher(actionForward.getPath()).forward(request, response);
            //ActionForward 객체의 forward 필드값이 [true]인 경우 - 포워드(스레드) 이동
		} else {//ActionForward 객체의 forward 필드값이 [false]인 경우 - 라다이렉트 이동
			response.sendRedirect(actionForward.getPath());
            //[false]인 경우 - 라다이렉트(client에게 요청 URL 주소(XXX.do)를 전달하여 재요청) 이동
		}
	}
}





📌 properties 파일 생성

  • web에서 사용할 수 있도록 webapp 폴더 안의 web-inf에 저장 필수


#Command(Key - String) = ModelClass(Value - String)
/loginForm.do = xyz.itwill.mvc.LoginFormModel
/login.do = xyz.itwill.mvc.LoginModel
/logout.do = xyz.itwill.mvc.LogoutModel
/writeForm.do = xyz.itwill.mvc.WriteFormModel
/write.do = xyz.itwill.mvc.WriteModel
/list.do = xyz.itwill.mvc.ListModel
/view.do = xyz.itwill.mvc.ViewModel
/modifyForm.do = xyz.itwill.mvc.ModifyFormModel
/modify.do = xyz.itwill.mvc.ModifyModel
/remove.do = xyz.itwill.mvc.RemoveModel
/error.do = xyz.itwill.mvc.ErrorModel




📌 web.xml

  • web.xml : 현재 프로젝트가 WAS 프로그램에 의해 웹자원(WebContext)로 변형될 때 필요한 정보를 제공하기 위한 환경설정파일

    • XSD 파일(XML 스키마 파일)에 선언된 태그(엘리먼트)만 사용 가능
    • servlet : 서블릿 클래스를 웹프로그램(서블릿)으로 등록하기 위한 엘리먼트
    • servlet-mapping : 웹프로그램(서블릿)에 URL 패턴을 등록하기 위한 엘리먼트
    • load-on-startup : WAS 실행시 서블릿 클래스를 서블릿 객체로 생성하기 위한 엘리먼트
    • 클라이언트의 요청 없이 WAS 실행시 서블릿 객체를 미리 생성 - init() 메소드가 자동 호출되어 초기화 작업
    • 엘리먼트값은 0 이상의 정수값으로 설정하며 정수값이 작을수록 먼저 서블릿 객체로 생성
    • init-param : 서블릿 클래스에 필요한 값을 제공하기 위한 엘리먼트

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" id="WebApp_ID" version="4.0">
  <display-name>mvc</display-name>
  
  <!-- servlet : 서블릿 클래스를 웹프로그램(서블릿)으로 등록하기 위한 엘리먼트 -->
  <servlet>
  	<servlet-name>controller</servlet-name>
  	<servlet-class>xyz.itwill.mvc.ControllerServlet</servlet-class>
  	<!-- init-param : 서블릿 클래스에 필요한 값을 제공하기 위한 엘리먼트 -->
  	<init-param>
  		<param-name>configFile</param-name>
  		<param-value>/WEB-INF/model.properties</param-value>
  	</init-param>
  	<!-- load-on-startup : WAS 실행시 서블릿 클래스를 서블릿 객체로 생성하기 위한 엘리먼트 -->
  	<!-- => 클라이언트의 요청 없이 WAS 실행시 서블릿 객체를 미리 생성 - init() 메소드가 자동 호출되어 초기화 작업 -->
  	<!-- => 엘리먼트값은 0 이상의 정수값으로 설정하며 정수값이 작을수록 먼저 서블릿 객체로 생성 -->
  	<load-on-startup>1</load-on-startup>
  </servlet>
  
  <!-- servlet-mapping : 웹프로그램(서블릿)에 URL 패턴을 등록하기 위한 엘리먼트 -->
  <servlet-mapping>
  	<servlet-name>controller</servlet-name>
  	<url-pattern>*.do</url-pattern>
  </servlet-mapping>
  
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.jsp</welcome-file>
    <welcome-file>default.htm</welcome-file>
  </welcome-file-list>
</web-app>





📒 응답 관련 정보 클래스

  • 응답 관련 정보(뷰 - View)를 저장하기 위한 클래스

  • 이동 형식에 대한 정보를 저장하기 위한 필드

    • private boolean forward;
    • false : 리다이렉트 이동, true : 포워드 이동
    • 리다이렉트 이동 : 클라이언트에게 요청 URL 주소(/XXX.do)를 전달하여 다시 요청하도록 응답 처리
    • 클라이언트 브라우저의 요청 URL 주소 변경
    • 포워드 이동 : 서블릿(컨트롤러)에서 JSP(뷰)로 스레드를 이동하여 응답 처리
    • 클라이언트 브라우저의 요청 URL 주소 미변경
  • 이동될 웹프로그램의 경로를 저장하기 위한 필드
    • private String path;
    • 리다이렉트 이동 : /XXX.do, 포워드 이동 : /XXX.jsp

package xyz.itwill.mvc;

public class ActionForward {
	private boolean forward;
	
	//이동될 웹프로그램의 경로를 저장하기 위한 필드
	// => 리다이렉트 이동 : /XXX.do, 포워드 이동 : /XXX.jsp
	private String path;
	
	public ActionForward() { } //기본생성자

	public boolean isForward() {
		return forward;
	}

	public void setForward(boolean forward) {
		this.forward = forward;
	}

	public String getPath() {
		return path;
	}

	public void setPath(String path) {
		this.path = path;
	}
}





📒 인터페이스

  • 모든 모델 역할의 클래스가 반드시 상속받아야 되는 인터페이스 (모델클래스가 공통으로 가지고 있어야하는 메소드)

    • 모델 클래스의 요청 처리 메소드에 대한 작성 규칙 제공 (모든 모델클래스가 동일한 형태를 가질수 있음)
    • 컨트롤러 역활의 서블릿에서 모델 객체로 요청 처리 메소드를 쉽게 호출할 수 있으며 유지보수의 효율성 증가
  • 인터페이스에는 요청 처리 메소드를 추상 메소드로 선언

    • 인터페이스를 상속받은 모든 자식클래스에서 반드시 추상 메소드를 오버라이드 선언
  • 요청 처리 메소드는 HttpServletRequest 객체와 HttpServletResponse 객체를 매개변수로 전달받아 요청 처리하고 뷰 관련 정보를 ActionForward 객체로 반환하도록 작성

  • 요청 처리 메소드에서 발생되는 ServletException과 IOException는 예외 전달

package xyz.itwill.mvc;

import java.io.IOException;

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

public interface Action {
	ActionForward execute(HttpServletRequest request, HttpServletResponse response)
		throws ServletException,IOException;
}





📗 LoginFormModel

  • 클라이언트가 [/loginForm.do]로 요청한 경우 실행될 모델 클래스
    • [user_login.jsp]로 포워드 이동하기 위한 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

import java.io.IOException;

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

public class LoginFormModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		actionForward.setForward(true);
		actionForward.setPath("/model_two/user_login.jsp");
		return actionForward;
	}
}





📘 user_login.jsp

  • 비로그인 사용자인 경우

    • 사용자로부터 로그인정보를 입력받기 위한 JSP 문서
    • [로그인] 태그를 클릭한 경우 로그인 처리페이지(/login.do)로 이동 (입력값 전달)
  • 로그인 사용자인 경우 (환영메세지를 전달하는 JSP 문서)

    • [회원목록] 태그를 클릭한 경우 회원목록 출력페이지(/list.do)로 이동
    • [로그아웃] 태그를 클릭한 경우 로그아웃 처리페이지(/logout.do)로 이동
    • [회원등록] 태그를 클릭한 경우 회원정보 입력페이지(/writeForm.do)로 이동 (관리자에게만 제공)
  • 요청 웹프로그램(컨트롤러)의 URL 주소 경로와 응답 JSP 문서의 경로가 서로 다르므로 웹자원의 경로는 절대경로로 표현하는 것을 권장

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<%-- 요청 웹프로그램(컨트롤러)의 URL 주소 경로와 응답 JSP 문서의 경로가 서로 다르므로
웹자원의 경로는 절대경로로 표현하는 것을 권장 --%>
<%-- <link rel=stylesheet href="${pageContext.request.contextPath }/model_two/css/user.css" type="text/css"> --%>
<link rel=stylesheet href="<c:url value="/model_two/css/user.css"/>" type="text/css">
<script language="JavaScript">
function userLogin() {
	if ( f.userid.value == "" ) {
		alert("아이디를 입력하십시요.");
		f.userid.focus();
		return;
	} 
	if ( f.password.value == "" ) {
		alert("비밀번호를 입력하십시요.");
		f.password.focus();
		return;
	}	
	
	f.action = "login.do";
	f.submit();
}
</script>
</head>
<body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0>
<br>
<table width=780 border=0 cellpadding=0 cellspacing=0>
	<tr>
	  <td width="20"></td>
	  <td style="color: red;">${message }</td>			
	</tr>
	
	<tr>
		<td width="20"></td>
		<td>
		  	<!--contents-->
			<table width=590 border=0 cellpadding=0 cellspacing=0>
				<tr>
					<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 로그인</b></td>
				</tr>
			</table>
			<br>
		  	<c:choose>
			  	<c:when test="${empty(loginUserinfo) }"><%-- 비로그인 사용자인 경우 --%>
					<!-- login Form  -->
					<form name="f" method="post">
					<table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
						<tr>
							<td width=100 align=center bgcolor="E6ECDE" height="22">사용자 아이디</td>
							<td width=490 bgcolor="ffffff" style="padding-left:10px;">
								<input type="text" style="width:150" name="userid" value="${userid }">
							</td>
						</tr>
						<tr>
							<td width=100 align=center bgcolor="E6ECDE" height="22">비밀번호</td>
							<td width=490 bgcolor="ffffff" style="padding-left:10px;">
								<input type="password" style="width:150" name="password">
							</td>
						</tr>
					</table>
					</form>
					<br>
					<table width=590 border=0 cellpadding=0 cellspacing=0>
						<tr>
							<td align=center>
								<input type="button" value="로그인" onClick="userLogin();"> &nbsp;
							</td>
						</tr>
					</table>
				</c:when>
				<c:otherwise><%-- 로그인 사용자인 경우 --%>
					<table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
						<tr>
							<td align=center bgcolor="E6ECDE" height="22">
								${loginUserinfo.name }님, 환영합니다.
							</td>
						</tr>
					</table>
					<br>
					<table width=590 border=0 cellpadding=0 cellspacing=0>
						<tr>
							<td align=center>
								<button type="button" onclick="location.href='list.do';">회원목록</button>
								<button type="button" onclick="location.href='logout.do';">로그아웃</button>
								<c:if test="${loginUserinfo.status == 9 }">
									<button type="button" onclick="location.href='writeForm.do';">회원등록</button>
								</c:if>
							</td>
						</tr>
					</table>
				</c:otherwise>
			</c:choose>
		</td>
	</tr>
</table>  
</body>
</html>






📗 LoginModel

  • 클라이언트가 [/login.do]로 요청한 경우 실행될 모델 클래스

  • 로그인정보를 전달받아 USERINFO 테이블에 저장된 회원정보와 비교하여 인증 처리

    • 인증 성공 : 세션에 권한 관련 정보를 저장하고 [loginForm.do]로 리다이렉트 이동 (정보가 저장된 ActionForward 객체 반환)
    • 인증 실패 : [user_login.jsp]로 포워드 이동하기 위한 정보가 저장된 ActionForward 객체 반환 (에러메세지와 아이디를 request 속성값으로 저장하여 JSP 문서에 제공)
  • 모델 클래스의 요청 처리 메소드에서는 Service 객체로 메소드를 호출하여 데이타베이스 관련된 작업이 처리되도록 작성
  • 인증이 성공된 경우 세션에 권한 관련 정보(회원정보) 저장
    • 세션 바인딩하여 HttpSession 객체를 반환받아 저장
    • HttpSession session=request.getSession();
    • Session Scope : 동일한 세션을 사용하는 모든 웹프로그램에서 속성값을 반환받아 사용 가능
package xyz.itwill.mvc;

public class LoginModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		//요청을 처리하면서 발생되는 모든 예외를 처리하기 위한 예외처리 기능 구현
		try {
			if(request.getMethod().equals("GET")) {//비정상적인 요청인 경우
				throw new Exception();//인위적 예외 발생
			}
			
			//전달값을 반환받아 저장
			String userid=request.getParameter("userid"); 
			String password=request.getParameter("password");
			
			//모델 클래스의 요청 처리 메소드에서는 Service 객체로 메소드를 호출하여
			//데이타베이스 관련된 작업이 처리되도록 작성
			
			//UserinfoService 클래스의 auth() 메소드를 호출하여 인증 처리
			// => AuthFailException이 발생된 경우 인증 실패 
			UserinfoService.getService().auth(userid, password);
			
			//인증이 성공된 경우 세션에 권한 관련 정보(회원정보) 저장
			// => 세션 바인딩하여 HttpSession 객체를 반환받아 저장
			HttpSession session=request.getSession();
			//Session Scope : 동일한 세션을 사용하는 모든 웹프로그램에서 속성값을 반환받아 사용 가능
			// => 웹브라우저가 종료되면 클라이언트에 바인딩된 세션은 자동으로 제거
			session.setAttribute("loginUserinfo", UserinfoService.getService().getUserinfo(userid));
			
			actionForward.setForward(false);
			actionForward.setPath("loginForm.do");
		} catch (AuthFailException e) {
			//인증 실패에 의해 발생된 예외에 대한 처리 명령 작성
			//Request Scope : 스레드가 이동된 웹프로그램(JSP)에서만 속성값을 반환받아 사용 가능
			request.setAttribute("message", e.getMessage());
			request.setAttribute("userid", request.getParameter("userid"));
			actionForward.setForward(true);
			actionForward.setPath("/model_two/user_login.jsp");
		} catch (Exception e) {
			//모든 예외에 대한 처리 명령 작성 
			// => [error.do]로 리다이렉트 이동하기 위한 정보가 저장된 ActionForward 객체 반환
			e.printStackTrace();//서버 콘솔에 에러메세지 출력
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}
}




📗 LogoutModel

  • 클라이언트가 [/logout.do]로 요청한 경우 실행될 모델 클래스

    • 로그아웃 처리
    • [loginForm.do]로 리다이렉트 이동하기 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

public class LogoutModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpSession session=request.getSession();
		//session.removeAttribute("loginUserinfo");
		session.invalidate();
		
		ActionForward actionForward=new ActionForward();
		actionForward.setForward(false);
		actionForward.setPath("loginForm.do");
		return actionForward;
	}
}





📗 ErrorModel

  • 클라이언트가 [/error.do]로 요청한 경우 실행될 모델 클래스
    • [user_error.jsp]로 포워드 이동하기 위한 정보가 저장된 ActionForward 객체를 반환
package xyz.itwill.mvc;

public class ErrorModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		actionForward.setForward(true);
		actionForward.setPath("/model_two/user_error.jsp");
		return actionForward;
	}
}





📘 user_error.jsp

  • 에러메세지를 전달하는 JSP 문서
    • [로그인 페이지 이동] 태그를 클릭한 경우 로그인정보 입력페이지(loginForm.do)로 이동
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>MVC</title>
<style type="text/css">
body {
	text-align: center;
}
.message {
	color: red;
	font-size: 1.5em;
}
</style>
</head>
<body>
	<h1>에러페이지</h1>
	<hr>
	<p class="message">프로그램 실행에 예기치 못한 오류가 발생 하였거나 비정상적 방법으로
	프로그램을 요청하여 오류가 발생 하였습니다.</p>
	<button type="button" onclick="location.href='loginForm.do';">로그인 페이지 이동</button>
</body>
</html>





📗 WriteFormModel

  • 클라이언트가 [/writeForm.do]로 요청한 경우 실행될 모델 클래스
    • 관리자만 요청 가능하도록 권한 설정
    • [user_write.jsp]로 포워드 이동하기 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

public class WriteFormModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		try {
			HttpSession session=request.getSession();
			UserinfoDTO loginUserinfo=(UserinfoDTO)session.getAttribute("loginUserinfo");
			//비로그인 사용자이거나 로그인 사용자가 관리자가 아닌 경우 - 비정상적인 요청
			if(loginUserinfo==null || loginUserinfo.getStatus()!=9) {
				throw new Exception();
			}
			
			actionForward.setForward(true);
			actionForward.setPath("/model_two/user_write.jsp");
		} catch (Exception e) {
			e.printStackTrace();
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}
}





📘 user_write.jsp

  • 사용자로부터 회원정보를 입력받기 위한 JSP 문서
    • [회원등록] 태그를 클릭한 경우 회원정보 삽입페이지(write.do)로 이동 (입력값 전달)
    • [로그인] 태그를 클릭한 경우 로그인정보 입력페이지(loginForm.do)로 이동
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel=stylesheet href="<c:url value="/model_two/css/user.css"/>" type="text/css">
<script language="JavaScript">
function userCreate() {
	if ( f.userid.value == "" ) {
		alert("아이디를 입력하십시요.");
		f.userid.focus();
		return;
	} 
	if ( f.password.value == "" ) {
		alert("비밀번호를 입력하십시요.");
		f.password.focus();
		return;
	}
	if ( f.name.value == "" ) {
		alert("이름을 입력하십시요.");
		f.name.focus();
		return;
	}
	
	f.action = "write.do";
	f.submit();
}
</script>
</head>
<body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0>
<br>
<table width=780 border=0 cellpadding=0 cellspacing=0>
	<tr>
	  <td width="20"></td>
	  <td style="color: red;">${message }</td>			
	</tr>

	<tr>
	  <td width="20"></td>
	  <td>
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 회원등록</b></td>
		  </tr>
	  </table>  
	  <br>
	  
	  <form name="f" method="post">
	  <table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">아이디</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:150" name="userid" value="${userinfo.userid }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">비밀번호</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="password" style="width:150" name="password" value="${userinfo.password }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이름</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:240" name="name" value="${userinfo.name }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이메일</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:240" name="email" value="${userinfo.email }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">회원등급</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<select name="status">
					<option value="1" <c:if test="${userinfo.status == 1 }">selected</c:if>>일반회원</option>
					<option value="9" <c:if test="${userinfo.status == 9 }">selected</c:if>>관리자</option>
				</select>
			</td>
		  </tr>		  
	  </table>
	  </form>
	  <br>
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td align=center>
				<input type="button" value="회원등록" onClick="userCreate();">
				<input type="button" value="로그인" onClick="location.href='loginForm.do';">
			</td>
		  </tr>
	  </table>
	  </td>
	</tr>
</table>  
</body>
</html>





📗 WriteModel

  • 클라이언트가 [/write.do]로 요청한 경우 실행될 모델 클래스

    • 회원정보를 전달받아 USERINFO 테이블에 삽입 처리
    • [loginForm.do]로 리다이렉트 이동하기 위한 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

public class WriteModel implements Action {

	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		UserinfoDTO userinfo=null;
		try {
			if(request.getMethod().equals("GET")) {
				throw new Exception();
			}
			
			request.setCharacterEncoding("utf-8");
			
			String userid=request.getParameter("userid");
			String password=request.getParameter("password");
			String name=request.getParameter("name");
			String email=request.getParameter("email");
			int status=Integer.parseInt(request.getParameter("status"));
			
			userinfo=new UserinfoDTO();
			userinfo.setUserid(userid);
			userinfo.setPassword(password);
			userinfo.setName(name);
			userinfo.setEmail(email);
			userinfo.setStatus(status);
			
			//UserinfoService 클래스의 addUserinfo() 메소드 호출
			// => 전달받은 아이디가 USERINFO 테이블에 저장된 기존 회원의 아이디와 중복될 경우
			//ExistsUserinfoException 발생
			UserinfoService.getService().addUserinfo(userinfo);
			
			actionForward.setForward(false);
			actionForward.setPath("loginForm.do");
		} catch (ExistsUserinfoException e) {
			//아이디가 중복될 경우 발생되는 예외에 대한 처리 명령 작성
			request.setAttribute("message", e.getMessage());
			request.setAttribute("userinfo", userinfo);
			actionForward.setForward(true);
			actionForward.setPath("/model_two/user_write.jsp");
		} catch (Exception e) {
			e.printStackTrace();
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}

}





📗 ListModel

  • 클라이언트가 [/list.do]로 요청한 경우 실행될 모델 클래스

    • 로그인 사용자만 요청 가능하도록 권한 설정
    • USERINFO 테이블에 저장된 모든 회원정보를 검색하여 request 속성값으로 저장
    • [user_list.jsp]로 포워드 이동하기 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

public class ListModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		try {
			HttpSession session=request.getSession();
			UserinfoDTO loginUserinfo=(UserinfoDTO)session.getAttribute("loginUserinfo");
			//비로그인 사용자인 경우 - 비정상적인 요청
			if(loginUserinfo==null) {
				throw new Exception();
			}
			
			//UserinfoService 클래스의 getUserinfoList() 메소드를 호출하여 반환된 회원목록을
			//포워드 이동될 JSP에서 사용하기 위해 request 속성값으로 저장
			request.setAttribute("userinfoList", UserinfoService.getService().getUserinfoList());
			
			actionForward.setForward(true);
			actionForward.setPath("/model_two/user_list.jsp");
		} catch (Exception e) {
			e.printStackTrace();
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}

}





📘 user_list.jsp

  • request 속성값으로 제공된 회원목록을 전달하는 JSP 문서

    • 회원정보에서 [회원이름]을 클릭한 경우 회원정보 출력페이지(view.do)로 이동 (아이디 전달)
    • [회원등록] 태그를 클릭한 경우 회원정보 입력페이지(writeForm.do)로 이동 (관리자에게만 제공)
    • [로그아웃] 태그를 클릭한 경우 로그아웃 처리페이지(logout.do)로 이동
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel=stylesheet href="<c:url value="/model_two/css/user.css"/>" type="text/css">
</head>
<body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0>
<br>
<table width=780 border=0 cellpadding=0 cellspacing=0>
<tr>
	<td width="20"></td>
	<td>
	  	<table width=590 border=0 cellpadding=0 cellspacing=0>
		  	<tr>
				<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 회원목록</b></td>
		  	</tr>
	  	</table>  
	  	<br>
	  
	  	<table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
		  	<tr>
				<td width=190 align=center bgcolor="E6ECDE" height="22">아이디</td>
				<td width=200 align=center bgcolor="E6ECDE">이름</td>
				<td width=200 align=center bgcolor="E6ECDE">이메일</td>
		  	</tr>
		  	
		  	<c:forEach var="userinfo" items="${userinfoList }">
			  	<tr>
					<td width=190 align=center bgcolor="ffffff" height="20">
						${userinfo.userid }
					</td>
					<td width=200 align=center bgcolor="ffffff">
						<a href="view.do?userid=${userinfo.userid }" class="user">
							${userinfo.name }
						</a>
					</td>
					<td width=200 align=center bgcolor="ffffff">
						${userinfo.email }
					</td>
			  	</tr>
		  	</c:forEach>
	  	</table>

		<br>
	  	<table border="0" cellpadding="0" cellspacing="1" width="590">
			<tr>
				<td align="right">
					<c:if test="${loginUserinfo.status == 9 }">
						<input type="button" value="회원등록" onclick="location.href='writeForm.do';"/>
					</c:if>
					<input type="button" value="로그아웃" onclick="location.href='logout.do';"/>
				</td>
			</tr>
		</table>		
	</td>
</tr>
</table>  
</body>
</html>





📗 ViewModel

  • 클라이언트가 [/view.do]로 요청한 경우 실행될 모델 클래스

    • 로그인 사용자만 요청 가능하도록 권한 설정
    • 아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 검색하여 request 속성값으로 저장
    • [user_view.jsp]로 포워드 이동하기 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

public class ViewModel implements Action {

	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		try {
			HttpSession session=request.getSession();
			UserinfoDTO loginUserinfo=(UserinfoDTO)session.getAttribute("loginUserinfo");
			//비로그인 사용자인 경우 - 비정상적인 요청
			if(loginUserinfo==null) {
				throw new Exception();
			}
			
			if(request.getParameter("userid")==null) {
				throw new Exception();
			}
			
			String userid=request.getParameter("userid");
			
			//UserinfoService 클래스의 getUserinfo() 메소드를 호출하여 반환된 회원정보를
			//포워드 이동될 JSP에서 사용하기 위해 request 속성값으로 저장
			// => UserinfoService 클래스의 getUserinfo() 메소드에서 해당 아이디의 회원정보가
			//검색되지 않은 경우 UserinfoNotFoundException 발생 >> 에러페이지 이동
			request.setAttribute("userinfo", UserinfoService.getService().getUserinfo(userid));
			
			actionForward.setForward(true);
			actionForward.setPath("/model_two/user_view.jsp");
		} catch (Exception e) {
			e.printStackTrace();
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}

}





📘 user_view.jsp

  • request 속성값으로 제공된 회원정보를 전달하는 JSP 문서

    • [수정] 태그를 클릭한 경우 변경회원정보 입력페이지(modifyForm.do)로 이동 (아이디 전달)
    • [삭제] 태그를 클릭한 경우 회원정보 삭제페이지(remove.do)로 이동 (아이디 전달)
    • [목록] 태그를 클릭한 경우 회원목록 출력페이지(list.do)로 이동
    • [수정] 태그와 [삭제] 태그는 관리자에게만 제공
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel=stylesheet href="<c:url value="/model_two/css/user.css"/>" type="text/css">
<script language="JavaScript">
function userRemove(userid) {
	if (confirm("정말로 삭제 하시겠습니까?") ) {
		location.href='remove.do?userid='+userid;
	}
}
</script>
</head>
<body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0>
<br>
<table width=780 border=0 cellpadding=0 cellspacing=0>
	<tr>
	  <td width="20"></td>
	  <td>
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 회원정보</b></td>
		  </tr>
	  </table>  
	  <br>
	  
	  <table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">아이디</td>
			<td width=490 bgcolor="ffffff"  style="padding-left:10px;">
				${userinfo.userid }
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이름</td>
			<td width=490 bgcolor="ffffff"  style="padding-left:10px;">
				${userinfo.name }
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이메일</td>
			<td width=490 bgcolor="ffffff"  style="padding-left:10px;">
				${userinfo.email }
			</td>
		  </tr>		  
	  </table>
	  <br>
	  
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td align=center>
			<c:if test="${loginUserinfo.status == 9 }">
				<input type="button" value="수정" onClick="location.href='modifyForm.do?userid=${userinfo.userid}';">
				<input type="button" value="삭제" onClick="userRemove('${userinfo.userid}');">
			</c:if>
			<input type="button" value="목록" onClick="location.href='list.do';"> 
			</td>
		  </tr>
	  </table>

	  </td>
	</tr>
</table>  
</body>
</html>




📗 ModifyFormModel

  • 클라이언트가 [/modifyForm.do]로 요청한 경우 실행될 모델 클래스

    • 관리자만 요청 가능하도록 권한 설정
    • 아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보를 검색하여 request 속성값으로 저장
    • [user_modify.jsp]로 포워드 이동하기 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

public class ModifyFormModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		try {
			HttpSession session=request.getSession();
			UserinfoDTO loginUserinfo=(UserinfoDTO)session.getAttribute("loginUserinfo");
			//비로그인 사용자이거나 로그인 사용자가 관리자가 아닌 경우 - 비정상적인 요청
			if(loginUserinfo==null || loginUserinfo.getStatus()!=9) {
				throw new Exception();
			}
			
			if(request.getParameter("userid")==null) {
				throw new Exception();
			}
			
			String userid=request.getParameter("userid");
			
			//UserinfoService 클래스의 getUserinfo() 메소드를 호출하여 반환된 회원정보를
			//포워드 이동될 JSP에서 사용하기 위해 request 속성값으로 저장
			// => UserinfoService 클래스의 getUserinfo() 메소드에서 해당 아이디의 회원정보가
			//검색되지 않은 경우 UserinfoNotFoundException 발생 >> 에러페이지 이동
			request.setAttribute("userinfo", UserinfoService.getService().getUserinfo(userid));
			
			actionForward.setForward(true);
			actionForward.setPath("/model_two/user_modify.jsp");
		} catch (Exception e) {
			e.printStackTrace();
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}

}





📘 user_modify.jsp

  • request 속성값으로 제공된 회원정보를 입력태그의 초기값으로 설정하고 변경할 회원정보를 사용자로부터 입력받기 위한 JSP 문서
    • [수정] 태그를 클릭한 경우 회원정보 변경페이지(modify.do)로 이동 (입력값 전달)
    • [목록] 태그를 클릭한 경우 회원목록 출력페이지(list.do)로 이동
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>MVC</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel=stylesheet href="<c:url value="/model_two/css/user.css"/>" type="text/css">
<script language="JavaScript">
function userModify() {
	if ( f.name.value == "" ) {
		alert("이름을 입력하십시요.");
		f.name.focus();
		return false;
	}
	f.action = "modify.do";
	f.submit();
}
</script>
</head>
<body bgcolor=#FFFFFF text=#000000 leftmargin=0 topmargin=0 marginwidth=0 marginheight=0>
<br>
<table width=780 border=0 cellpadding=0 cellspacing=0>
	<tr>
	  <td width="20"></td>
	  <td>
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td bgcolor="f4f4f4" height="22">&nbsp;&nbsp;<b>회원관리 - 회원정보수정</b></td>
		  </tr>
	  </table>  
	  <br>
	  
	  <form name="f" method="post">
	  <input type="hidden" name="userid" value="${userinfo.userid }">
	  <table border="0" cellpadding="0" cellspacing="1" width="590" bgcolor="BBBBBB">
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">아이디</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				${userinfo.userid }
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">비밀번호</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="password" style="width:150" name="password">
				<span style="color: red;">** 비밀번호를 변경하지 않을 경우 입력하지 마세요. **</span>
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이름</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:240" name="name" value="${userinfo.name }">
			</td>
		  </tr>
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">이메일 주소</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<input type="text" style="width:240" name="email" value="${userinfo.email }">
			</td>
		  </tr>		  
		  <tr>
			<td width=100 align=center bgcolor="E6ECDE" height="22">회원등급</td>
			<td width=490 bgcolor="ffffff" style="padding-left:10px;">
				<select name="status">
					<option value="1" <c:if test="${userinfo.status == 1 }">selected</c:if>>일반회원</option>
					<option value="9" <c:if test="${userinfo.status == 9 }">selected</c:if>>관리자</option>
				</select>
			</td>
		  </tr>	
	  </table>
	  </form>
	  <br>
	  
	  <table width=590 border=0 cellpadding=0 cellspacing=0>
		  <tr>
			<td align=center>
			<input type="button" value="수정" onClick="userModify();">
			<input type="button" value="목록" onClick="location.href='list.do';">
			</td>
		  </tr>
	  </table>

	  </td>
	</tr>
</table>  
</body>
</html>





📗 ModifyModel

  • 클라이언트가 [/modify.do]로 요청한 경우 실행될 모델 클래스

    • 회원정보를 전달받아 USERINFO 테이블에 저장된 회원정보 변경 처리
    • [view.do]로 리다이렉트 이동하기 위한 정보가 저장된 ActionForward 객체 반환 (아이디 전달)
package xyz.itwill.mvc;

public class ModifyModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		try {
			if(request.getMethod().equals("GET")) {
				throw new Exception();
			}
			
			request.setCharacterEncoding("utf-8");
			
			String userid=request.getParameter("userid");
			String password=request.getParameter("password");
			String name=request.getParameter("name");
			String email=request.getParameter("email");
			int status=Integer.parseInt(request.getParameter("status"));
			
			UserinfoDTO userinfo=new UserinfoDTO();
			userinfo.setUserid(userid);
			if(password==null || password.equals("")) {
				//비밀번호 전달값이 없는 경우 - 기존 회원의 비밀번호 사용
				userinfo.setPassword(UserinfoService.getService().getUserinfo(userid).getPassword());
			} else {
				//비밀번호 전달값이 있는 경우 - 입력된 비밀번호 사용
				userinfo.setPassword(password);
			}
			userinfo.setName(name);
			userinfo.setEmail(email);
			userinfo.setStatus(status);
			
			//UserinfoService 클래스의 modifyUserinfo() 메소드 호출
			UserinfoService.getService().modifyUserinfo(userinfo);
			
			actionForward.setForward(false);
			actionForward.setPath("view.do?userid="+userid);
		} catch (Exception e) {
			e.printStackTrace();
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}

}





📗 RemoveModel

  • 클라이언트가 [/remove.do]로 요청한 경우 실행될 모델 클래스

    • 관리자만 요청 가능하도록 권한 설정
    • 아이디를 전달받아 USERINFO 테이블에 저장된 해당 아이디의 회원정보 삭제 처리
    • [list.do]로 리다이렉트 이동하기 위한 정보가 저장된 ActionForward 객체 반환
    • 관리자가 자신 계정의 회원정보를 삭제한 경우 [logout.do]로 리다이렉트 이동하기 위한 정보가 저장된 ActionForward 객체 반환
package xyz.itwill.mvc;

public class RemoveModel implements Action {
	@Override
	public ActionForward execute(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		ActionForward actionForward=new ActionForward();
		try {
			HttpSession session=request.getSession();
			UserinfoDTO loginUserinfo=(UserinfoDTO)session.getAttribute("loginUserinfo");
			//비로그인 사용자이거나 로그인 사용자가 관리자가 아닌 경우 - 비정상적인 요청
			if(loginUserinfo==null || loginUserinfo.getStatus()!=9) {
				throw new Exception();
			}
			
			if(request.getParameter("userid")==null) {
				throw new Exception();
			}
			
			String userid=request.getParameter("userid");

			//UserinfoService 클래스의 removeUserinfo() 메소드 호출
			UserinfoService.getService().removeUserinfo(userid);
			
			actionForward.setForward(false);
			if(loginUserinfo.getUserid().equals(userid)) {
				actionForward.setPath("logout.do");
			} else {
				actionForward.setPath("list.do");
			}
		} catch (Exception e) {
			e.printStackTrace();
			actionForward.setForward(false);
			actionForward.setPath("error.do");
		}
		return actionForward;
	}
}






profile
Study Log 📂

0개의 댓글