http://127.0.0.1:8080/PostDataTagServletMapping
-앞에 /가 붙으면 절대경로가 되어 브라우저에서 위 URI처럼 request를 보낸다
http://127.0.0.1:8080/edu/jw02/edu/PostDataTagServletMapping
-앞에 /이 생략되면 상대경로로 인식되어 해당 html이 있는 폴더 밑에
-relative URL(root path에 종속적이지않게 개발이 가능하다.)
http://127.0.0.1:8080/edu/PostDataTagServletMappingpublic 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가 모든 일을 담당하기에 변화에 유연하지 않고 유지보수에 좋지 않다.
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>");
}
}
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이 분리되었다고 보기 힘들다.
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>");
}
}
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;
}
}
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에 종속적으로 로직을 처리한다.
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>");
}
}
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에 독립적인 개발이 가능하다.
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>");
}
}
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) {
}
}
}
}
}
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 기술이다.
서비스와 관련된 부가정보들을 작성해놓은 WEB.xml을 캡슐화한 객체이며 web.xml의 설정 정보를 가져올 수 있다.