23.01.26

이동욱·2023년 8월 6일
0

NaverCloudCamp

목록 보기
18/42

학습내용

  1. 복습
  2. relative url
  3. eclips wep app 구조
  4. VO, DAO
  5. Connection Pool
  6. Servlet Config

복습

  • Container는 자기 마음대로 메서드를 실행하는 main과는 달리 정해진 method만 실행 가능하다.
  • HttpServlet은 abstract class이지만 abstract method가 없다 => overriding 없이 기존 method 사용하기
  • Servlet init(), service(), destroy()는 ServletContainer가 실행한다
  • .java 파일을 컴파일시 -d . 옵션을 추가하면 클래스에 명시한 패키지를 만들면서 패키지 하위에서 컴파일 한다.

URL, relative URL

  • URL

http://127.0.0.1:8080/PostDataTagServletMapping
-앞에 /가 붙으면 절대경로가 되어 브라우저에서 위 URI처럼 request를 보낸다

http://127.0.0.1:8080/edu/PostDataTagServletMapping
  • relative URL

http://127.0.0.1:8080/edu/jw02/edu/PostDataTagServletMapping
-앞에 /이 생략되면 상대경로로 인식되어 해당 html이 있는 폴더 밑에

http://127.0.0.1:8080/edu/jw02/PostDataTagServletMapping http://127.0.0.1:8080/edu/jw02/PostDataTagServletMapping

-relative URL(root path에 종속적이지않게 개발이 가능하다.)

http://127.0.0.1:8080/edu/PostDataTagServletMapping

Eclips WEB APP 구조

- Eclips는 java의 Web App 구조를 다음 위 사진처럼 제공한다. - 기존 Web App 구조에서 Serlvet class들을 넣어두는 classes폴더는 src/main/java에서 관리한다.

lib 폴더

  • 기존에는 로컬 pc에 라이브러리를 설치하고 classPath를 설정하여 해당 라이브러리를 사용하였지만 이는 환경이 변하면 classPath도 변경해야 하기에 환경변수에 종속적인 개발이다.
  • 이를 방지하기 위해 java의 Web App구조는 lib를 포함하며 해당 lib 폴더에 웹 서비스에서 필요한 라이브러리를 넣어 classPath에 독립적인 개발이 가능하다.

Login 예제를 통해 모듈화 해보기

Login

public class Login extends HttpServlet{

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		
		req.setCharacterEncoding("EUC_KR");
		res.setContentType("text/html;charset=EUC_KR");
		PrintWriter out = res.getWriter();
		
		
		String id = req.getParameter("id");
		String pwd = req.getParameter("pwd");
		
		String fromDbId = null;
		String fromDbPwd = null;
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			Connection conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:xe", "scott", "tiger");
			
			PreparedStatement pstmt =  conn.prepareStatement("select id, pwd from users where id = ?");
			pstmt.setString(1, id);
			ResultSet rs = pstmt.executeQuery();
			
			if(rs.next()) {
				fromDbId = rs.getString(1);
				fromDbPwd = rs.getString(2);
				System.out.println("db에서 조회한 id = " + fromDbId + " pwd = " + fromDbPwd);
			} else {
				System.out.println("db에 해당 id, pwd가 없습니다.");
			}
			
			rs.close();
			pstmt.close();
			conn.close();
			
		} catch (Exception e) {
			e.printStackTrace();
			System.out.println("JDBC 관련 에러발생");
		}
		
		
		out.println("<html>");
		out.println("<head></head>");
		out.println("<body>");
		out.println("<h2>Login 화면</h2>");
		
		if((fromDbId != null && fromDbPwd != null) && (id.equals(fromDbId) && pwd.equals(fromDbPwd))) {
			out.println(id + "님 환영합니다");
		}else {
			out.println("id, pwd를 확인하세요");
		}
		
		out.println("<p><p><a href='/edu/jw04/login.html'>뒤로</a>");
		out.println("</body>");
		out.println("</html>");
	}
}

Login Servlet은 Client request를 받아오기, DB 연결 가져오기, DB에 쿼리 날리기등 여러가지 일을 모두 담당하고 있다.
이는 하나의 class가 모든 일을 담당하기에 변화에 유연하지 않고 유지보수에 좋지 않다.

  1. Presentation layer(view), Business logic(model) 분리

LoginBean

public class LoginBean extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		req.setCharacterEncoding("EUC_KR");
		res.setContentType("text/html;charset=EUC_KR");
		PrintWriter out = res.getWriter();
		
		
		String id = req.getParameter("id");
		String pwd = req.getParameter("pwd");
		
		DbBean dbBean = new DbBean();
		dbBean.setId(id);
		dbBean.setPwd(pwd);
		
		boolean isLogin = dbBean.getUser();
		
		out.println("<html>");
		out.println("<head></head>");
		out.println("<body>");
		out.println("<h2>Login 화면</h2>");
		
		if(isLogin) {
			out.println(id + "님 환영합니다");
		}else {
			out.println("id, pwd를 확인하세요");
		}
		
		out.println("<p><p><a href='/edu/jw04/loginBean.html'>뒤로</a>");
		out.println("</body>");
		out.println("</html>");
	}	
}

DbBean

public class DbBean {
	//field
	private String dbUrl = "jdbc:oracle:thin:@localhost:1521:xe";
	private String dbuser = "scott";
	private String dbpwd = "tiger";
	private String id;
	private String pwd;
	
	//constructor
	public DbBean() {
		super();
		// TODO Auto-generated constructor stub
	}

	//method
	public void setId(String id) {
		this.id = id;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public boolean getUser() {
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			con = DriverManager.getConnection(dbUrl, dbuser, dbpwd);
			
			pstmt =  con.prepareStatement("select id, pwd from users where id = ?");
			pstmt.setString(1, id);
			rs = pstmt.executeQuery();
			
			String str = null;
			
			if(rs.next()) {
				str = rs.getString("pwd");
				System.out.println("DB에서 확인 한 id, pwd ==> " + id +"/"+str);
			}else {
				System.out.println("db에 <"+ id +">에 해당하는 id, pwd가 없습니다.");
			}
			
			if(str != null && pwd.equals(str)) {
				return true;
			}else {
				return false;
			}
			
		} catch (Exception e) {
			e.printStackTrace();
			return false;
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
					
				}
			}
			if(pstmt != null) {
				try {
					pstmt.close();
				} catch (Exception e2) {
					
				}
			}
			if(con != null) {
				try {
					con.close();
				} catch (Exception e2) {
					
				}
			}
		}
	}	
}

이번에는 Client의 request와 response를 담당하는 Presentation layer와 DB와의 연결, 데이터 넣기를 담당하는 Business Logic으로 분리하였다.
이전 Login 예제보다는 간결해졌지만 DbBean에 보면 Client가 보낸 id, pwd를 필드로 받아서 처리하고있다. 이는 완전히 Presentation Layer와 Business Logic이 분리되었다고 보기 힘들다.

  1. VO 추가

LoginBeanVODao

public class LoginBeanVODao extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		req.setCharacterEncoding("EUC_KR");
		res.setContentType("text/html;charset=EUC_KR");
		PrintWriter out = res.getWriter();
		
		String id = req.getParameter("id");
		String pwd = req.getParameter("pwd");
		
		UserVO userVO = new UserVO();
		userVO.setId(id);
		userVO.setPwd(pwd);
		
		UserDao userDao = new UserDao();
		userDao.getUser(userVO);
		
		out.println("<html>");
		out.println("<head></head>");
		out.println("<body>");
		out.println("<h2>Login 화면</h2>");
		
		if(userVO.isActive()) {
			out.println(id + "님 환영합니다");
		}else {
			out.println("id, pwd를 확인하세요");
		}
		
		out.println("<p><p><a href='/edu/jw04/loginBeanVODao.html'>뒤로</a>");
		out.println("</body>");
		out.println("</html>");
	}	
}

UserVO

package jw04;

public class UserVO {
	//field
	private String id;
	private String pwd;
	private boolean active;
	
	//constructor
	public UserVO() {
		super();
		// TODO Auto-generated constructor stub
	}

	
	//method
	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	public boolean isActive() {
		return active;
	}

	public void setActive(boolean active) {
		this.active = active;
	}
}

UserDao

public class UserDao {
	//field
	private String dbUrl = "jdbc:oracle:thin:@localhost:1521:xe";
	private String dbuser = "scott";
	private String dbpwd = "tiger";
	
	//constructor
	public UserDao() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	//method
	public void getUser(UserVO userVO) {
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			Class.forName("oracle.jdbc.driver.OracleDriver");
			con = DriverManager.getConnection(dbUrl, dbuser, dbpwd);
			
			pstmt =  con.prepareStatement("select id, pwd from users where id = ? and pwd = ? ");
			pstmt.setString(1, userVO.getId());
			pstmt.setString(2, userVO.getPwd());
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				System.out.println("DB에서 확인한 id/pwd ==>  " + userVO.getId() + "/" + userVO.getPwd());
				userVO.setActive(true);
			}else {
				System.out.println("db에 <"+ userVO.getId() +">에 해당하는 id, pwd가 없습니다.");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
					
				}
			}
			if(pstmt != null) {
				try {
					pstmt.close();
				} catch (Exception e2) {
					
				}
			}
			if(con != null) {
				try {
					con.close();
				} catch (Exception e2) {
					
				}
			}
		}
	}
}

Presentation layer와 Business Logic은 서로 Client의 request를 캡슐화한 UserVO라는 객체만을 주고받기에 두 계층간의 독립이 이루어졌다.
그러나 DB를 통해 로직을 처리하는 UserDao는 dbDriver, dbUrl값을 하드코딩하고있어 DB에 종속적으로 로직을 처리한다.

  1. DB 정보 분리

loginBeanInitParam

public class LoginBeanInitParam extends HttpServlet {
	//field
	private String jdbcDriver;
	private String jdbcURL;
	private String jdbcUser;
	private String jdbcPasswd;
	
	//method
	@Override
	public void init(ServletConfig sc) throws ServletException {
		jdbcDriver = sc.getInitParameter("jdbcDriver");
		jdbcURL= sc.getInitParameter("jdbcURL");
		jdbcUser= sc.getInitParameter("jdbcUser");
		jdbcPasswd= sc.getInitParameter("jdbcPasswd");
		
		System.out.println("jdbcDriver : " + jdbcDriver);
		System.out.println("jdbcURL : " + jdbcURL);
		System.out.println("jdbcUser : " + jdbcUser);
		System.out.println("jdbcPasswd : " + jdbcPasswd);
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		req.setCharacterEncoding("EUC_KR");
		res.setContentType("text/html;charset=EUC_KR");
		PrintWriter out = res.getWriter();
		
		String id = req.getParameter("id");
		String pwd = req.getParameter("pwd");
		
		UserVO userVO = new UserVO();
		userVO.setId(id);
		userVO.setPwd(pwd);
		
		UserInitParamDao dao = new UserInitParamDao();
		dao.setJdbcDriver(jdbcDriver);
		dao.setJdbcURL(jdbcURL);
		dao.setJdbcUser(jdbcUser);
		dao.setJdbcPasswd(jdbcPasswd);
		
		dao.getUser(userVO);
		
		
		out.println("<html>");
		out.println("<head></head>");
		out.println("<body>");
		out.println("<h2>Login 화면</h2>");
		
		if(userVO.isActive()) {
			out.println(id + "님 환영합니다");
		}else {
			out.println("id, pwd를 확인하세요");
		}
		
		out.println("<p><p><a href='/edu/jw04/loginBeanInitParam.html'>뒤로</a>");
		out.println("</body>");
		out.println("</html>");
	}	
}

UserInitParamDao

public class UserInitParamDao {
	//field
	private String jdbcDriver;
	private String jdbcURL;
	private String jdbcUser;
	private String jdbcPasswd;
	
	//constructor
	public UserInitParamDao() {
		super();
		// TODO Auto-generated constructor stub
	}

	//method
	public void setJdbcDriver(String jdbcDriver) {
		this.jdbcDriver = jdbcDriver;
	}


	public void setJdbcURL(String jdbcURL) {
		this.jdbcURL = jdbcURL;
	}


	public void setJdbcUser(String jdbcUser) {
		this.jdbcUser = jdbcUser;
	}


	public void setJdbcPasswd(String jdbcPasswd) {
		this.jdbcPasswd = jdbcPasswd;
	}
	
	
	public void getUser(UserVO userVO) {
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			Class.forName(jdbcDriver);
			con = DriverManager.getConnection(jdbcURL, jdbcUser, jdbcPasswd);
			
			pstmt =  con.prepareStatement("select id, pwd from users where id = ? and pwd = ? ");
			pstmt.setString(1, userVO.getId());
			pstmt.setString(2, userVO.getPwd());
			
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				System.out.println("DB에서 확인한 id/pwd ==>  " + userVO.getId() + "/" + userVO.getPwd());
				userVO.setActive(true);
			}else {
				System.out.println("db에 <"+ userVO.getId() +">에 해당하는 id, pwd가 없습니다.");
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
					
				}
			}
			if(pstmt != null) {
				try {
					pstmt.close();
				} catch (Exception e2) {
					
				}
			}
			if(con != null) {
				try {
					con.close();
				} catch (Exception e2) {
					
				}
			}
		}
	}
}

웹 서비스의 부가적인 정보를 담아놓은 WEB.xml에 DB와 관련된 정보들을 입력 한 뒤 WEB.xml을 캡슐화한 SerlvetConfig class를 통해 DB 설정정보를 가져와서 DB와의 연결을 진행한다.
WEB.xml 한곳에만 DB 관련 정보를 저장하여 나중에 다른 DB로 교체된다하더라도 DB 관련된 로직을 수행하는 class들을 전부 바꾸는것이 아닌 WEB.xml만을 수정하기에 DB에 독립적인 개발이 가능하다.

  1. Connection Pool을 통해 DB Connection 부하 줄이기

LoginBeanPool

public class LoginBeanPool extends HttpServlet {

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException {
		req.setCharacterEncoding("EUC_KR");
		res.setContentType("text/html;charset=EUC_KR");
		PrintWriter out = res.getWriter();
		
		String id = req.getParameter("id");
		String pwd = req.getParameter("pwd");
		
		UserVO userVO = new UserVO();
		userVO.setId(id);
		userVO.setPwd(pwd);
		
		UserPoolDao userPoolDao = new UserPoolDao();
		userPoolDao.getUser(userVO);
		
		out.println("<html>");
		out.println("<head></head>");
		out.println("<body>");
		out.println("<h2>Login 화면</h2>");
		
		if(userVO.isActive()) {
			out.println(id + "님 환영합니다");
		}else {
			out.println("id, pwd를 확인하세요");
		}
		
		out.println("<p><p><a href='/edu/jw04/loginBeanPool.html'>뒤로</a>");
		out.println("</body>");
		out.println("</html>");
	}
}

UserPoolDao

public class UserPoolDao {
	//field
	//private String dbUrl = "jdbc:oracle:thin:@localhost:1521:xe";
	//private String dbuser = "scott";
	//private String dbpwd = "tiger";
	
	//constructor
	public UserPoolDao() {
		super();
		// TODO Auto-generated constructor stub
	}
	
	//method
	public void getUser(UserVO userVO) {
		Connection con = null;
		PreparedStatement pstmt = null;
		ResultSet rs = null;
		
		try {
			con = OracleConnectionPool.getInstance().getConnection();
		
			pstmt =  con.prepareStatement("select id, pwd from users where id = ? and pwd = ? ");
			pstmt.setString(1, userVO.getId());
			pstmt.setString(2, userVO.getPwd());
			
			rs = pstmt.executeQuery();
			
			if(rs.next()) {
				System.out.println("DB에서 확인한 id/pwd ==>  " + userVO.getId() + "/" + userVO.getPwd());
				userVO.setActive(true);
			}else {
				System.out.println("db에 <"+ userVO.getId() +">에 해당하는 id, pwd가 없습니다.");
			}
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			if(rs != null) {
				try {
					rs.close();
				} catch (Exception e2) {
					
				}
			}
			if(pstmt != null) {
				try {
					pstmt.close();
				} catch (Exception e2) {
					
				}
			}
			if(con != null) {
				try {
					con.close();
				} catch (Exception e2) {
					
				}
			}
		}
	}
}

OracleConnectionPool

public class OracleConnectionPool {
	private static OracleConnectionPool instance;
	private OracleConnectionCacheImpl occi;
	private String url = "jdbc:oracle:thin:@127.0.0.1:1521:xe";
	private String user = "scott";
	private String password = "tiger";
	private int minConn = 5;				//보유할 connnection의 최소수
	private int maxConn = 10;			//보유할 connnection의 최대수
	
	private OracleConnectionPool() {
		try {
			occi = new OracleConnectionCacheImpl();
			occi.setURL(url);
			occi.setUser(user);
			occi.setPassword(password);
			occi.setMinLimit(minConn);
			occi.setMaxLimit(maxConn);
		} catch(Exception e) {			e.printStackTrace();			}	
	}
	
	public static synchronized OracleConnectionPool getInstance() {		
		if(instance==null) instance = new OracleConnectionPool();		
		return instance;
	}
	
	public synchronized Connection getConnection() {
		Connection conn = null;
		try{	conn = occi.getConnection();	}
		catch(Exception e) {	e.printStackTrace();	}
		return conn;
	}
	
	// occi가 가지고 있는 con을 닫는다.(5 ~ 10)
	public synchronized void close() {
		try {	occi.close();		}
		catch(Exception e) {	e.printStackTrace();	}
	}

	public int getCacheSize()		{		return occi.getCacheSize();	 	}

	public int getActiveSize()		{		return occi.getActiveSize();		}	
}

DB와의 Connection을 생성하는 작업은 서버에 부하가 많이 가는 작업이다. 만약 모든 Client의 요청마다 DB와의 Connetion을 맺는다면 서버는 금방 터진다.
따라서 미리 Connection pool 안에 Connection을 생성하고 Client의 요청이 오면 생성해놓은 Connection을 할당해주는것이 Connection Pool 기술이다.

servlet config

서비스와 관련된 부가정보들을 작성해놓은 WEB.xml을 캡슐화한 객체이며 web.xml의 설정 정보를 가져올 수 있다.

Qusetion

  1. Java se, Java ee 차이
    Java se는 java를 만들때 필요한 기본적인 라이브러리들이 포함된 버전이다. java ee는 java se 위에 웹 프로그래밍에 필요한 기술들을 추가한 것이다.
profile
Backend Developer

0개의 댓글