일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 답변형 게시판
- SQL
- 부트스트랩
- 한글 인코딩
- oracle
- rownum
- Oracle SQL
- JavaScript
- Java
- sql developer
- HTML
- HTTP Status 404
- 제약조건
- github
- distinct
- CRUD
- tomcat
- git
- alias
- group by
- 과정평가형
- ||
- JSP
- jQuery
- 모조칼럼
- 이클립스
- Bootstrap
- 성적프로그램
- Oracle DB
- HTTP Status 500
초급의 끄적거림
[MVC] 서블릿 개요, JSP 형식 출력 본문
1. MVC
- MVC : Model - View - Controller
1-1) MVC 패턴의 구성 및 흐름
1-2) 모델 1
- 한 페이지에 Model과 View가 모두 존재하는 형태
- 한 페이지에 다같이 존재하기 때문에 페이지가 지저분해지고 디자인과 비즈니스 로직이 분리되지 않아 추가로 수정해야하는 단점
- Controller가 존재하지 않으며, Model과 View가 한 곳에 붙어 있으므로 Controller가 존재하는 것이 의미가 없음
1-3) 모델2 (Model 2)
- 백엔드와 프론트엔드의 경계를 넓힘 (각자 분리하여 역할을 수행)
- 화면 출력 부분 (디자인 부분)을 view 라고 하고, 데이터 베이스와 연동하는 부분 등의 로직을 Model이라고 한다
- Controller는 이 두 부분을 적절하게 연결시켜주는 역할
- Model과 View를 독립적으로 코딩하기 때문에 Controller를 만들어 둘 사이에 개입하여 서로 연동하는 역할을 함
1-4) 요청 파라미터로 명령어를 전달하는 방법
2. 자바 개발 방식
2-1) .jsp 만을 이용
- basicWeb 을 말함
- 덜 의존적이라 프로그래밍하기가 더 쉽고 편하지만 보안에 취약
2-2) .java → Servlet 클래스
2-3) .jsp + .java (DTO, DAO)
* 같은 내용을 .jsp만 이용하고 .java만 이용하여 각자의 장점과 단점 확인 → 하나에 치우쳐서 만들기에는 불편한점이 많기 때문에 혼재하여 사용
3. .jsp 페이지
3-1) mvcTest 프로젝트 / control 폴더와 welcome.jsp
3-2) servlet-api.jar 복사-붙여넣기
- 이클립스 루나 버전에서는 servlet을 직접 복사 붙여넣기 해야함
- tomcat 서버에서 직접 복사 (tomcat-8.0/lib/servlet-api.jar) → 프로젝트 mvcTest/WebContent/WEB-INF/lib
3-3) html5 구조로 변경
3-4) JSP 페이지
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>환영합니다</title>
</head>
<body>
<!-- JSP 코드만 사용한 페이지 -->
<strong>대한민국</strong>
<hr>
<span style="color: brown">사계</span>
<hr>
<table border="1">
<tr>
<th>이름</th>
<td>김태연</td>
</tr>
</table>
</body>
</html>
4. .java (오직 자바만 이용)
- view단을 구성하기에 번거롭다는 단점
- java코드를 구성하는데는 편리
4-1) mvcTest 프로젝트/Java Resources/src/net.control/Welcome.java
- 'Superclass'에서 'HttpServlet'
- 클래스의 부모가 class : extends / 클래스의 부모가 interface : implements
- Welcome 서빌릿은 web.xml (배치관리자, 배치기술자)에 등록해야 한다.
req : 내부객체 request
resp : 내부객체 response
package net.control;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class Welcome extends HttpServlet {
@Override // 물려받은 메소드 재정의 (리폼)
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//<form method=get> 방식으로 요청하면 호출되는 함수
//req : 내부객체 request와 동일
//resp : 내부객체 response와 동일
try{
//단순 문자열로 응답 (AJAX) - 대체로 다 spring 처리하는 것이 편함
//resp.setContentType("text/plain; charset=UTF-8");
//HTML 문서 구조로 응답
resp.setContentType("text/html; charset=UTF-8"); //welcome.jsp에서 인코딩부분 복사
//요청한 사용자에게 응답하기 위한 객체
PrintWriter out=resp.getWriter();
//같은 내용이 나타나게 하기 위해서 welcome.jsp 내용을 전체 복사해서 String으로
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset='UTF-8'>");
out.println("<title>환영합니다</title>");
out.println("</head>");
out.println("<body>");
out.println("<strong>대한민국</strong>");
out.println("<hr>");
out.println("<span style='color: brown'>사계</span>");
out.println("<hr>");
out.println("<table border='1'>");
out.println(" <tr>");
out.println(" <th>이름</th>");
out.println(" <td>김태연</td>");
out.println(" </tr>");
out.println("</table>");
out.println("</body>");
out.println("</html>");
out.close(); // 자원반납 (한 번 응답을 했으면 끊어내기 위해서)
}catch(Exception e){
System.out.println("요청실패 : "+e);
}//try end
}//doGet() end
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// <form method=post> 방식으로 요청했을 때 호출
}//doPost() end
}//class end
4-2) Source - Override/Implement Methods
- class GenericServlet{}
- class HttpServlet extends GenericServlet{}
- class Welcome extends HttpServlet{}
- class HttpServlet - doGet 체크
4-3) Welcome 서블릿은 web.xml (배치관리자, 배치기술자)에 등록해야 한다
- 첫페이지 자동호출
- 세션시간 등록
- 커스텀 태그를 이용해 서블릿을 등록함
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>mvcTest</display-name>
<!--
첫페이지 자동호출
http://localhost:8090/mvcTest/
-->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<!-- 세션시간(20분) 등록 -->
<session-config>
<session-timeout>1200</session-timeout>
</session-config>
<!-- 커스텀태그 - 서블릿 등록 -->
<!-- servlet과 mapping 은 짝꿍 -->
<servlet>
<servlet-name>hello</servlet-name> <!-- mapping의 servlet-name과 동일해야함 -->
<servlet-class>net.control.Welcome</servlet-class> <!-- servlet이 들어가 있는 class 패키지명을 복사해오고 Welcome 이라는 클래스명도 적어줌 -->
</servlet>
<servlet-mapping>
<servlet-name>hello</servlet-name>
<url-pattern>/wel.do</url-pattern>
</servlet-mapping>
4-4) 결과 확인
- 3-4) 에서 나온 것과 동일한 결과
- 결과 확인 (web.xml에서 지정한 url-pattern에 해당하는 /wel.do)
→ http://localhost:8090/mvcTest/wel.do ( /mvcTest/ 까지만 쓰면 web.xml에 등록된 index.jsp가 불려옴)
5. LifeCycle (생명 주기)
- HttpServlet 클래스 상속
- 클라이언트가 Servlet에 요청을 하면, Servlet이 바로 호출 되는 것이 아니라 Servlet이 객체를 생성하고 초기화 작업을 거친 후, 요청을 처리하는 생명주기를 가지고 있음
- Source - Override/Implement
: HttpServlet - doGet, doPost, service(HttpServletRequest, ~) 체크
: GenericServlet - destroy(), init() 체크
service() 메소드가
사용자가 요청한 폼이 method=get 방식이면 doGet() 호출
method=post 방식이면 doPost() 호출
HttpServletRequest
- 특정한 자원을 주소에 요청시, 그 때 생성됨
- 요청에 따른 응답이 발생하면 사라짐 (일회성)
init() |
단 1번만 호출 서블릿이 서비스하기 위해 필요한 초기화 작업을 수행 init() 메소드가 service() 메소드 호출 |
service() |
request당 1개씩 호출 클라이언트의 요청 (새로고침)이 있을 때마다 실행 |
destroy() |
1번만 호출 - 관리 컨테이너가 종료될 때 - 타임아웃 되었을 때 - 클래스의 내용이 변경되었을 때 (재컴파일) 호출 |
package net.control;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class LifeCycle extends HttpServlet {
/*
web.xml에 LifeCycle 서블릿 등록
결과확인
http://localhost:8090/mvcTest/life.do
class GenericServlet{}
class HttpServlet extends GenericServlet{}
HttpServlet 생명주기 -----------------------------------
init() 서블릿이 시작되면 1번만 호출
→ service() 사용자가 요청할 때마다 호출
→ service()
→ service()
→ service()
→ destroy() 서버가 중지되면 1번만 호출
----------------------------------------------------------
*/
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//method=get 방식 요청이 들어오면
super.doGet(req, resp);
System.out.println("doGet() 호출 . . .");
}//doGet() end
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
//method=post 방식 요청이 들어오면
super.doPost(req, resp);
System.out.println("doPost() 호출 . . .");
}//doPost() end
@Override
protected void service(HttpServletRequest arg0, HttpServletResponse arg1)
throws ServletException, IOException {
//method=get 방식 요청이 들어오면 doGet()호출
//method=post 방식 요청이 들어오면 doPost()를 구분해서 호출하는 역
super.service(arg0, arg1);
System.out.println("service( )호출 . . . ");
}//service() end
@Override
public void destroy() {
// 서버가 중지되면 1번만 자동 실행
super.destroy();
System.out.println("destory() 호출 . . . ");
}//destroy() end
@Override
public void init() throws ServletException {
// 서블릿이 최초로 호출될 때 1번만 자동 호출
// 초기환경 구출할 때 사용
super.init();
System.out.println("init() 호출 . . . ");
}//init() end
}//class end
- web.xml에 LifeCycle 서블릿 등록 (web.xml 수정시, 서버 재시작)
<!-- HttpServelt 생명주기 서블릿 등록 -->
<servlet>
<servlet-name>lifecycle</servlet-name> <!-- 원하는 이름 지정 -->
<servlet-class>net.control.LifeCycle</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>lifecycle</servlet-name>
<url-pattern>/life.do</url-pattern> <!-- 외부에서 부를 때 -->
</servlet-mapping>
5-1) 실행
- 톰캣서버 재실행 후, 콘솔창에서 에러가 나지않는지 확인
- 결과확인 URL 실행 → 콘솔창에 메세지 발행
: get 방식으로 호출했기 때문에 get이 나타남
: 새로고침을 누르면 그 횟수만큼 호출이 되는데 init의 경우, 최초 호출될 때 한번만 호출되는 모습
: Servers 탭에서 서버를 중지시킬 경우, destroy 메세지 호출
6. loginForm
6-1) loginForm.jsp
- WebContent/control/loginForm.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>loginForm.jsp</title>
</head>
<body>
<h3>* 회원 로그인 *</h3>
<form method="get" action="loginproc.do">
아이디 : <input type="text" name="uid"><br>
비밀번호 : <input type="password" name="upw"><br>
<input type="submit" value="확인">
</form>
</body>
</html>
6-2) servlet을 이용하여 실행하기 (net.control/LoginForm.java)
- net.control/LoginForm.java 생성
<페이지 이동>
redirect (리다이렉트) |
- 클라이언트가 새로 페이지를 요청한 것과 같은 방식으로 페이지 이동 - request, response가 유지되지 않고 새로 만들어짐 - 이동된 url이 화면에 보임 <방법> - response.sendRedirect("이동할 페이지"); |
forword (포워드) |
- request 에 담긴 값이 유효하다 (request, response 유지) - 이동된 url이 화면에 안 보인다 (사용자는 이동했는지 알 수 없음) <방법> 1) pageContext.forward("이동할 페이지"); |
package net.control;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.omg.CORBA.Request;
public class LoginForm extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// method=get 방식 요청
// <페이지 이동방법>
/* 1) 와 2)의 결과는 동일
1)
http://localhost:8090/mvcTest/login.do
resp.sendRedirect("control/loginForm.jsp");
*/
//2)
String view="control/loginForm.jsp";
RequestDispatcher rd=req.getRequestDispatcher(view);
rd.forward(req, resp);
}//doGet() end
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// method=post 방식 요청
}//doPost() end
- jsp를 그냥 실행하면 url이 http://localhost:8090/mvcTest/control/loginForm.jsp 이렇게 발생
그러나 servlet을 이용하여 실행시 http://localhost:8090/mvcTest/login.do 로 실행
- LoginForm.java에 doGet과 doPost를 오버라이드 하고, web.xml에 서블릿생성
<!-- loginForm -->
<servlet>
<servlet-name>Loginform</servlet-name>
<servlet-class>net.control.LoginForm</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Loginform</servlet-name>
<url-pattern>/login.do</url-pattern>
</servlet-mapping>
7. loginForm.jsp
- form 태그의 action에 loginproc.do 로 연결함
- web.xml에 loginproc.do를 서블릿으로 등록
: servlet-class에 LoginProc를 적었기 때문에 이에 해당하는 LoginProc.java 만들기
<!-- action="loginProc.do" 서블릿 등록 -->
<servlet>
<servlet-name>loginproc</servlet-name> <!-- 원하는 이름 지정 -->
<servlet-class>net.control.LoginProc</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>loginproc</servlet-name>
<url-pattern>/loginproc.do</url-pattern> <!-- 외부에서 부를 때 -->
</servlet-mapping>
7-1) LoginProc.java
- 결과확인 : localhost:8090/mvcTest/login.do 에서 아이디와 비밀번호를 입력함
- 입력한 내용이 뜨게 됨
package net.control;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.omg.CORBA.Request;
public class LoginProc_v1 extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// loginForm.jsp에서 method=post 방식
//<form method=post action=loginproc.do>
//서블릿에서는 이전에 request라고 쓰였던 것이 req 로, response라고 쓰였던 것이 resp 로 쓰임
try{
//1) 한글 인코딩
resp.setCharacterEncoding("UTF-8");
//2) 사용자가 요청한 정보를 변수에 옮겨담기
String uid=req.getParameter("uid").trim();
String upw=req.getParameter("upw").trim();
//3) 요청한 사용자에게 응답 (Welcome.java에서 복사)
//HTML 문서 구조로 응답
resp.setContentType("text/html; charset=UTF-8");
//요청한 사용자에게 응답하기 위한 객체
PrintWriter out=resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset='UTF-8'>");
out.println("<title>로그인 결과</title>");
out.println("</head>");
out.println("<body>");
out.println(" 아이디 : <strong>"+uid+"</strong>");
out.println(" <hr>");
out.println("비밀번호 : <strong>"+upw+"</strong>");
out.println("</body>");
out.println("</html>");
//자원 반납
out.close();
}catch(Exception e){
System.out.println("요청실패 : "+e);
}//try end
}//doPost() end
//만일 post에서 get으로 method 방식을 바꾼 경우
//doGet을 오버라이드 하고 post 방식에서 쓴 내용을 복사 붙여넣기 하면 됨
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
// method=get 방식
try{
//1) 한글 인코딩
resp.setCharacterEncoding("UTF-8");
//2) 사용자가 요청한 정보를 변수에 옮겨담기
String uid=req.getParameter("uid").trim();
String upw=req.getParameter("upw").trim();
//3) 요청한 사용자에게 응답 (Welcome.java에서 복사) view 단에 해당
//HTML 문서 구조로 응답
resp.setContentType("text/html; charset=UTF-8");
//요청한 사용자에게 응답하기 위한 객체
PrintWriter out=resp.getWriter();
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<meta charset='UTF-8'>");
out.println("<title>로그인 결과</title>");
out.println("</head>");
out.println("<body>");
out.println(" 아이디 : <strong>"+uid+"</strong>");
out.println(" <hr>");
out.println("비밀번호 : <strong>"+upw+"</strong>");
out.println("</body>");
out.println("</html>");
//자원 반납
out.close();
}catch(Exception e){
System.out.println("요청실패 : "+e);
}//try end
}//doGet() end
}//class end
7-2) post방식에서 get방식으로 바꾼 경우
- 결과는 6-1)의 post 방식과 동일하지만 url에서 차이를 보이고 있음
- post로 들어올 때와 get으로 들어올 때 똑같이 들어옴
→ 위에처럼 중복해서 사용하지 않음, 주로 함수(8. result.jsp 참고)를 이용해서 표현
7-3) 위에처럼 java로만 만들면 view 단을 표현하는데 번거로움이 큼. (테이블도 다 out.print에 일일이 넣는 등)
때문에 이를 분리하여 result.jsp 라고 하여 jsp로 만들기
8. result.jsp
- LoginProc.java 이름변경 → LoginProc_v1.java 후, LoginProc.java 생성
- doGet, doPost 오버라이딩 → 위에서처럼 두 군데 코딩하는 것이 아니라 제3의 함수를 만듦
8-1) 제3의 함수 prcoess 만들기
- get방식과 post 방식일 경우, process 함수를 불러올 수 있게 process(req, resp); 넣어주기
8-2) LoginProc.java와 loginResult.jsp 공유 공간 필요 (전역변수)
- 로그인 정보는 시간이 지나면 사라져야하는 정보이기 때문에 session에 올림
- 실행 방법을 보기 위해 request, session, application 모두를 실시
LoginProc.java
package net.control;
import java.io.IOException;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
public class LoginProc extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp); //get방식이면 process함수에서 불러오기
}//doGet() end
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
process(req, resp); //post방식이면 process함수에서 불러오기
}//doPost() end
//override를 지우고 제3의 함수 (process)를 만들기 → doGet도 가져다 쓰고, doPost도 가져다 씀, 수정과 작성은 제 3의 함수인 process에서 해결
protected void process(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
try{
req.setCharacterencoding("UTF-8");
String uid=req.getParameter("uid").trim();
String upw=req.getParameter("upw").trim();
//공유공간에 값 올리기
//공유공간 : request, session, application
//session 객체 선언 (시간이 지나면 자연스럽게 사라짐)
HttpSession session=req.getSession();
//application 객체 선언
ServletContext application=req.getServletContext();
if(uid.equals("fullmoon") && upw.equals("1234")){
//로그인 성공 (id와 비번)
req.setAttribute("r_uid", uid);
req.setAttribute("r_upw", upw);
session.setAttribute("s_uid", uid);
session.setAttribute("s_upw", upw);
application.setAttribute("a_uid", uid);
application.setAttribute("a_upw", upw);
req.setAttribute("msg", "로그인 성공");
req.setAttribute("img", "<img src='control/sound.png'>");
}else{
//로그인 실패
req.setAttribute("r_uid", "guest");
req.setAttribute("r_upw", "guest");
session.setAttribute("s_uid", "guest");
session.setAttribute("s_upw", "guest");
application.setAttribute("a_uid", "guest");
application.setAttribute("a_upw", "guest");
req.setAttribute("msg", "로그인 실패");
req.setAttribute("img", "<img src='control/fail.png'>");
}//if end
//뷰페이지 이동 (결과값을 result.jsp로 보낼 것)
String view="control/loginResult.jsp"; //uid와 upw를 loginResult.jsp에서 사용하게 될 것 → uid와 loginResult.jsp의 공유공간이 필요함 (전역변수필요)
RequestDispatcher rd=req.getRequestDispatcher(view);
rd.forward(req, resp);
}catch(Exception e){
System.out.println("요청실패 : "+ e);
}//try end
}//process() end
}//class end
loginResult.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>loginResult.jsp</title>
</head>
<body>
<h3>* 로그인 결과 *</h3>
1) JSP <br>
아이디 : <%=request.getAttribute("r_uid") %><br>
비밀번호 : <%=request.getAttribute("r_upw") %><br>
<hr>
아이디 : <%=session.getAttribute("s_uid") %><br>
비밀번호 : <%=session.getAttribute("s_upw") %><br>
<hr>
아이디 : <%=application.getAttribute("a_uid") %><br>
비밀번호 : <%=application.getAttribute("a_upw") %><br>
<hr>
메세지 : <%=request.getAttribute("msg") %><br>
이미지 : <%=request.getAttribute("img") %><br>
<hr>
</body>
</html>
- 실행 방법 : localhost:8090/mvcTest/login.do
- 이미지나 메세지를 적기 위해 request 추가후, loginResult.jsp에서도 불러 올 수 있게 함