오늘도 오라클 연동하는 연습을 해봤다. 이번에는 영화 목록을 띄우고 댓글까지 달 수 있는 프로그램이다.
댓글을 달기 위해서는 로그인을 해주는 기능을 만들어야 해서, 먼저 오라클에서 테이블을 만들어서 로그인에 필요한 정보들을 저장해줬다.
CREATE TABLE webMember (
id VARCHAR2(20),
name VARCHAR2(30) CONSTRAINT wm_name_nn NOT NULL,
sex VARCHAR2(10),
CONSTRAINT wm_id_pk PRIMARY KEY(id),
CONSTRAINT wm_sex_ck CHECK(sex IN('남자', '여자'))
);
CREATE TABLE webReply (
no NUMBER,
mno NUMBER,
id VARCHAR2(20),
name VARCHAR2(30),
msg CLOB CONSTRAINT wr_msg_nn NOT NULL,
regdate DATE DEFAULT SYSDATE,
CONSTRAINT wr_no_pk PRIMARY KEY(no),
CONSTRAINT wr_mno_fk FOREIGN KEY(mno)
REFERENCES movie(mno),
CONSTRAINT wr_id_fk FOREIGN KEY(id)
REFERENCES webMember(id)
);
ALTER TABLE movie ADD CONSTRAINT movie_mno_pk PRIMARY KEY(mno);
CREATE SEQUENCE wr_no_seq
START WITH 1
INCREMENT BY 1
NOCYCLE
NOCACHE;
ALTER TABLE webMember ADD pwd VARCHAR2(10) CONSTRAINT wm_pwd_nn NOT NULL;
ALTER가 여러번 쓰인걸 보면 알 수 있듯이 한 번에 깔끔하게 만들지는 못했고 수정을 거듭해서 만들어줬다.
일단 PRIMARY에 해당하는 id, no를 지정해주고, 댓글 테이블의 경우에는 작성일자도 뜰 수 있도록 regdate도 만들어 준다. default 값은 당연히 sysdate이다.
테이블을 다 만들어 줬으면 각각 테이블에 대응하는 VO 파일도 만들어 준다.
package com.sist.dao;
import lombok.Getter;
import lombok.Setter;
/*
* MNO NOT NULL NUMBER(4)
TITLE VARCHAR2(100)
GENRE VARCHAR2(100)
POSTER VARCHAR2(200)
ACTOR VARCHAR2(300)
REGDATE VARCHAR2(100)
GRADE VARCHAR2(50)
DIRECTOR VARCHAR2(100)
*/
@Setter
@Getter
public class MovieVO {
private int mno;
private String title;
private String genre;
private String poster;
private String actor;
private String regdate;
private String grade;
private String director;
}
이거는 목록 출력을 위한 VO이다. 저번 시간 부터는 lombok을 사용했기 때문에 소스가 길어지지 않고 깔끔하다
package com.sist.dao;
/*
*
NO NOT NULL NUMBER
MNO NUMBER
ID VARCHAR2(20)
NAME VARCHAR2(30)
MSG NOT NULL CLOB
REGDATE DATE
*/
import java.util.*;
import lombok.Getter;
import lombok.Setter;
@Setter
@Getter
public class ReplyVO {
private int no;
private int mno;
private String id;
private String name;
private String msg;
private Date regdate;
private String dbday;
}
이거는 댓글 출력을 위한 VO. dbday는 시간까지 입력을 해주기 위해서 만들어준 변수이다. 아직 사용은 안해서 어떻게 쓰일지 궁금하다.
DAO파일에서 오라클 연결하기 까지는 항상 같은 패턴이기 때문에 생략하고, 바로 로그인 기능을 위한 코드부터 적어보고 시작하겠다.
public String isLogin(String id,String pwd)
{
String result="";
try
{
// 1. 연결
getConnection();
// 2. SQL문장 => ID가 존재하는지 여부
String sql="SELECT COUNT(*) FROM webMember "
+"WHERE id=?";
ps=conn.prepareStatement(sql);
// ?에 값을 채운다
ps.setString(1, id);
// 실행후에 결과값을 받는다
ResultSet rs=ps.executeQuery();
rs.next();
int count=rs.getInt(1);
rs.close();
if(count==0) //ID가 존재하지 않는 경우
{
result="NOID"; // alert()
}
else // ID가 존재하는 경우
{
// 비밀번호 검색
sql="SELECT pwd,name FROM webMember "
+"WHERE id=?";
ps=conn.prepareStatement(sql);
// ?에 값을 채운다
ps.setString(1, id);
// 실행 결과값가 가지고 온다
rs=ps.executeQuery();
rs.next();
String db_pwd=rs.getString(1);
String name=rs.getString(2);
rs.close();
// 비밀번호가 있냐?
if(db_pwd.equals(pwd)) // 비밀번호가 맞는 상태 => 로그인
{
// 영화목록으로 이동
result=name; // id,name=> session => 댓글사용이 안된다
}
else // 비밀번호가 틀린 상태
{
result="NOPWD";
}
}
}catch(Exception ex)
{
// 오류 확인
System.out.println(ex.getMessage());
}
finally
{
// 닫기
disConnection();
}
return result;
}
로그인 정보는 당연히 id와 pwd를 받아서 확인하기 때문에 매개변수로 두개를 받아온다.
로그인의 경우 세가지 경우의 수가 있다.
1. 등록된 아이디가 없는 경우
2. 비밀번호가 일치하지 않는 경우
3. 둘다 맞아서 로그인에 성공하는 경우
일단 sql문 count를 가져와서 id가 존재하는지 여부를 확인해준다. 일치하는 아이디가 있으면 1을, 없으면 0을 결과값으로 받아오기 때문에, 유무를 확인하기 편하다.
ID가 존재하지 않는 경우에는 result 값으로 NOID를 채워준다.
ID가 존재하는 경우에는 해당하는 id의 비밀번호와 이름을 가져와서 저장한다.
비밀번호가 있다면 로그인에 성공한것으로, 이름값을 보내주고 영화목록으로 이동한다.
비밀번호가 일치하지 않으면 result 값으로 NOPWD를 채워준다.
여기까지 만들어주고 LoginServlet파일을 만들어 준다.
package com.sist.movie;
import java.io.*;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.sist.dao.*;//오라클 연결
@WebServlet("/LoginServlet")
public class LoginServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 로그인 화면 => JSP (파일을 두개를 만들어서 처리)
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 1. HTML을 전송 (요청한 클라이언트의 브라우저로 전송)
// => HTML을 보낸다는 메세지를 브라우저에 알려준다 (text/html,text/xml,text/plain(JSON))
response.setContentType("text/html;charset=UTF-8");
// 1조외에 다른조는 EUC-KR
// 클라이언트 브라우저에서 HTML을 읽어 갈 수 있는 위치 확인(메모리)
PrintWriter out=response.getWriter();
out.println("<html>");
out.println("<head>");
// => CSS,JavaScript,Title => AJAX
// CSS 사용 => 외부 CSS
out.println("<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css\">");
out.println("<style type=text/css>");
// container(960px) , container-fluid(Full 화면)
out.println(".row { width:350px;margin:0px auto;}");//<center>태그는 사용금지
// <center> => margin:0px auto;
out.println("h3{text-align:center}");
out.println("</style>");
out.println("</head>");
out.println("<body>");
// => 화면 출력하는 태그를 이용한다
out.println("<div class=container>");
out.println("<h3>Login</h3>");
out.println("<div class=row>");
// 전송 준비
out.println("<form method=post action=LoginServlet>");
// LoginServlet클래스의 doPost()로 입력된 데이터를 보낸다
out.println("<table class=\"table table-condensed\">");
out.println("<tr>");
out.println("<th width=20% class=\"danger text-right\">ID</th>");
out.println("<td width=80%>");
out.println("<input type=text name=id size=20>");
out.println("</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<th width=20% class=\"danger text-right\">Password</th>");
out.println("<td width=80%>");
out.println("<input type=password name=pwd size=20>");
out.println("</td>");
out.println("</tr>");
out.println("<tr>");
out.println("<td colspan=2 class=text-center>");
out.println("<input type=submit value=로그인 class=\"btn btn-sm btn-primary\">");
out.println("<input type=button value=취소 class=\"btn btn-sm btn-danger\">");
out.println("</td>");
out.println("</tr>");
out.println("</table>");
out.println("</form>");
out.println("</div>");
out.println("</div>");
out.println("</body>");
out.println("</html>");
}
// 사용자가 입력한 ID,PWD를 받아서 처리 => 로그인 (영화목록으로 이동)
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// HTML 전송
response.setContentType("text/html;charset=UTF-8");
PrintWriter out=response.getWriter();
// 1.사용자가 보내준 id,password를 받는다
String id=request.getParameter("id"); // <input type=text name=id>
String pwd=request.getParameter("pwd");//<input type=password name=pwd>
// 2.DAO연동 => 결과
MovieDAO dao=new MovieDAO();
String result=dao.isLogin(id, pwd);
// 3.이동 시도
if(result.equals("NOID")) //ID가 없는 경우
{
out.println("<script>");
out.println("alert(\"아이디가 존재하지 않습니다\");");
out.println("history.back();");// 로그인 화면으로 이동
out.println("</script>");
}
else if(result.equals("NOPWD")) // ID는 존재 => 비밀번호가 틀린 경우
{
out.println("<script>");
out.println("alert(\"비밀번호가 틀립니다\");");
out.println("history.back();");// 로그인 화면으로 이동
out.println("</script>");
}
else // ID,비밀번호가 일치 => 로그인이 되는 상태
{
// 1. 서버에 ID,Name을 저장 => 프로그램 종료시까지 기억 : 세션
HttpSession session=request.getSession();
session.setAttribute("id", id); //Map방식 => key,value
session.setAttribute("name", result);
// 이동
response.sendRedirect("MovieListServlet");
}
}
}
doGet에서 입력되는 id와 password값을 doPost로 받아와 준다.
ID가 존재하지 않으면 alert창을 이용해서 경고창을 띄워준다. 비밀번호가 틀린경우에도 마찬가지로 alert창을 띄워준다.
이때 history.back()을 써서 로그인 화면으로 되돌아 갈 수 있게 만들어준다.
만약에 둘다 일치해서 로그인에 성공하는 경우에는 session에 id와 name을 저장한다.
session은 Map방식을 사용하고 있기 때문에 반드시 key값과 value값을 같이 저장해주어야 한다.
저장을 해주고 나면 MovieListServlet 파일, 즉 리스트를 출력해주는 곳으로 이동하면 된다.
package com.sist.movie;
import java.io.*;
import java.util.ArrayList;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.sist.dao.MovieDAO;
import com.sist.dao.MovieVO;
@WebServlet("/MovieListServlet")
public class MovieListServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out=response.getWriter();
// session을 가지고 온다 => 각 클라이언트당 한개만 생성 => request를 이용해서 생성
//HttpSession session=request.getSession();// 세션을 가지고 온다
String page=request.getParameter("page");
// 디폴트 설정 => page=1
if(page==null)
page="1";
int curpage=Integer.parseInt(page); // 현재 보고 있는 페이지
// 총페이지
MovieDAO dao=new MovieDAO();
int totalpage=dao.movieTotalPage();
// 해당 페이지에 해당되는 데이터 읽기
ArrayList<MovieVO> list=dao.movieListData(curpage);
out.println("<html>");
out.println("<head>");
// CSS 사용 => 외부 CSS
out.println("<link rel=\"stylesheet\" href=\"https://maxcdn.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css\">");
out.println("<style type=text/css>");
// container(960px) , container-fluid(Full 화면)
out.println(".row { width:960px;margin:0px auto;}");//<center>태그는 사용금지
// <center> => margin:0px auto;
out.println("h3{text-align:center}");
out.println("</style>");
out.println("</head>");
out.println("<body>");
/*
* out.println("<center>"); out.println("<h3>영화 목록</h3>");
* out.println("<h4>ID:"+session.getAttribute("id")+"</h4>");
* out.println("<h4>이름:"+session.getAttribute("name")+"</h4>");
* out.println("</center>");
*/
out.println("<div style=\"height:50px\"></div>");
out.println("<div class=container>");
out.println("<div class=row>");
/*
* <div class="col-md-4">
<div class="thumbnail">
<a href="/w3images/lights.jpg">
<img src="/w3images/lights.jpg" alt="Lights" style="width:100%">
<div class="caption">
<p>Lorem ipsum...</p>
</div>
</a>
</div>
</div>
*/
for(MovieVO vo:list)
{
out.println("<div class=\"col-md-3\">");// 12가 되면 => 자동으로 밑으로 내려간다
out.println("<div class=\"thumbnail\">");
out.println("<a href=\"#\">");
out.println("<img src=\""+vo.getPoster()+"\" class=img-rounded style=\"width:220;height:300px\">");
out.println("<div class=\"caption\">");
out.println("<p>"+vo.getTitle()+"</p>");
out.println("</div>");
out.println("</a>");
out.println("</div>");
out.println("</div>");
}
out.println("</div>");
out.println("</div>");
out.println("</body>");
out.println("</html>");
}
}
이건 다 완성된 페이지는 아니고 일단 col을 이용해서 구역을 나눠줘서 영화 데이터들을 출력해 줬다. 이제 내일은 다음페이지에 넘어가도 보이는 프로그램을 짜주지 않을까 싶다.
아마 시퀀스도 이용하고 상세보기도 연결해서 댓글까지 달아주는 프로그램을 완성할 예정이다.
+) 아 그리고 eclipse에서 git으로 바로 파일을 commit하는 방법도 배웠다.
형상관리 프로그램이라고 부른다고 한다. 면접에서 물어볼 가능성이 크기 때문에 잊어버리지 않기 위해 블로깅에 적어뒀다.
'programming > Gukbi' 카테고리의 다른 글
국비 교육 48일차 - 댓글 수정, 삭제 (0) | 2021.03.08 |
---|---|
국비 교육 47일차 - 댓글 달기, 댓글 많은순으로 출력 (0) | 2021.03.04 |
국비 교육 45일차 - 오라클 연동 (게시판 마무리), CSS (0) | 2021.03.02 |
국비 교육 44일차 - 오라클 연동 (게시판 만들기) (0) | 2021.03.01 |
국비 교육 43일차 - 오라클 연결 웹 프로젝트, servlet, HTML (input, attribute) (0) | 2021.02.25 |