html 파일 => jsp 변환 시 소스코드의 한글이 깨졌을때 인코딩 방식 변경방법
File > Properties (Alt+Enter) > Resource > Text file encoding > UTF-8


JSP로 바뀌었으면 브라우저에 출력 인코딩 정보도 넘겨주어야 하기 때문에 page 지시자로 다음 코드도 넣어준다
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>


JSP에서 java 모듈을 임포트 할때도 page 지시자를 쓴다. (hotkey - ctrl+spacebar)
ex) <%@page import="java.sql.DriverManager"%>


웹개발시 서버의 물리적 환경을 어떻게 구축할지 모르기 때문에 참조하는 라이브러리 파일의 path가 달라질 수 있다.
때문에 개발에 사용되는 ojdbc.jar, jstl.jar 또는 직접만든 재사용 라이브러리 등의 파일은 배포할때 함께 포함시켜서 상대 경로로 path를 등록해주어야 한다.

톰캣을 이용한 웹개발에서는 별개로 사용하는 라이브러리가 있을 경우 다음 경로에 포함시켜준다
Prj\src\main\webapp\WEB-INF\lib




< Model 데이터를 위한 클래스(Entity) 정의와 사용방법의 변화 >

 

MVC에서 모델로 사용할 데이터를 그대로 가져다 쓰면 비슷한 코드의 반복이 많아지거나 모델 변수명이 비슷한 의미로 중첩되어 스파게티스러워 진다. 데이터를 클레스로 구조화 시켜주면 유지보수나 개발 시에 직관적으로 파악할 수 있다.

예시)
request.setAttribute("title", title);
request.setAttribute("writerId", writerId);
request.setAttribute("regdate", regdate);
request.setAttribute("hit", hit);
request.setAttribute("files", files);
request.setAttribute("content", content);
== 구조화 ==> request.setAttribute("n", notice);
== JSP 사용시 ==> ${n.title}


EL 사용을 염두해 두고 model 데이터 클래스로 정의하기

 

public class Notice {
private int id;
private String title;
private String writer;
private Date regdate;
private String content;
private int hit;

public int getId() {
return id;
}
}

-멤버 변수들 세팅용 생성자를 오버로드 해주고, getter와 setter 그리고 확인용으로 toString 메소드도 추가해준다.


<td>${notice.id}</td>
<a href=detail.jsp?c=${notice.code}">${notice.title}</a>


-EL 표현식은 get이후 첫스펠링은 소문자로 그리고 get과 생성자함수() 표현은 생략한다.

(private 멤버변수를 꺼내올 수는 없는 거고, getter를 써서 끌어쓰기 때문에 EL에서는 표현식을 생략하고 있는 것을 확인할 수 있다)
-EL은 반복할 수 있는 기능이 없다. 그래서 게시판 등에서 전달받은 목록 배열을 뿌려줄때는 태그 라이브러리(JSTL) 기능 등을 사용하기도 한다.



<View 페이지 은닉>

MVC model2 방식으로 소스를 나눴다면 출력부분은 콘트롤러에 의해서만 불려지고
클라이언트에서 직접 요청해서는 안되는 부분이기 때문에 WEB-INF 폴더에 따로 빼서
사용자가 요청할 수 없는 페이지로 만들어준다.

'Development > Java' 카테고리의 다른 글

JDBC 제어 oracleDB SQL 게시판용 몇개 #9  (0) 2022.08.21
JSTL #8  (0) 2022.08.15
JSP EL(Expression Language) #6  (0) 2022.08.14
JSP MVC model #5  (0) 2022.08.14
Servlet & JSP (method) #4  (0) 2022.08.13

 

< EL (Expression Language) >


-저장 객체에서 값을 추출해서 출력하는 표현식

 

 

JSP에서 출력 부분(HTML)에 EL 표현식을 사용하면 쉽게 값을 추출해서 출력해줄 수 있다.

 

Controller View (java 사용 시) EL (표현식 사용 시)
request.setAttribute("cnt",30); request.getAttribute("cnt"); ${cnt}
List list = new ArrayList(){"1", "test"...};
request.setAttribute("list", list);
((List)request.getAttribute("list")).get(0) ${list[0]}
Map n = new HashMap("title", "제목");
request.setAttribute("n", n);
((Map)request.getAttribute("n")).get("title") ${n.title}



EL이 저장 객체에서 값을 추출하는 순서에는 우선 순위가 있다.

page > request > session > application


위 순서로 추출하며 상위 저장 객체에 저장된 값을 먼저 추출한다.
때문에 동일한 이름의 변수가 존재할 때는 정확하게 원하는 값을 출력하기 위해서 사용하는 내장 객체가 존재한다.

내장 객체 설명
pageScope Page 영역의 생명 주기에서 사용되는 저장소
requestScope Request 영역의 생명 주기에서 사용되는 저장소
sessionScope Session 영역의 생명 주기에서 사용되는 저장소
applicationScope Application 영역의 생명 주기에서 사용되는 저장소
param 파라미터 값을 저장하고 있는 저장소 (?cnt=3 << 3 param)
paramValues 파라미터 값을 배열로 저장하고 있는 저장소
header Header 정보를 저장하고 있는 저장소
headerValues Header 정보를 저장하고 있는 저장소
cookie 쿠키 정보를 저장하고 있는 저장소
initParam 컨텍스트의 초기화 파라미터를 저장하고 있는 저장소
pageContext 페이지 범위의 컨텍스트 저장소

사용법 ex)
${requestScope.cnt}
-request 저장소에서 저장 중인 cnt 변수를 사용


pageContext는 page 내에서 사용할 수 있는 servlet 객체들(request,session,application 등등)을 모아놓았다.
자체적으로 저장소 기능도 갖추고 있어 setAttribute, getAttribute 또한 가능하다

EL에서는 함수를 호출하는 방식은 사용할 수 없고, 속성을 사용하는 것처럼 써야하나 pageContext의 getter는 사용할 수 있다. 다만 사용할 때는 get 명령어와 생성자호출()은 제외하고 작성해야 한다.

사용법 ex)
${pageContext.request.method}

위는 아래의 JSP를 사용한 java 코드와 같은 기능을 한다.
<%=pageContext.getRequest().getMethod()%> 
 


< EL 연산자 >


[] .
()
not ! empty
* / div % mod
+ -
< > <= >= lt gt le ge
== != eq ne
&& and
|| or
? :

 

굳이 < > 대신 lt gt (less then, greater then) 등 문자형 비교연산자를 사용하는 이유


EL은 JSP에서 쓰이는데 HTML이 꺽음쇠를 무조건 사용해서 직관성이 떨어진다.
또한 XHTML 기반의 문서나 HTML을 엄격한 구문으로 파악하는 구조로 만들면 기호형 연산자는 허용하지 않고
오류를 일으킬 가능성이 있다.
(그래도 오류가 없다면 편한 기호형을 쓰자)

 

 

empty 연산자는 자주쓰임


ex) 

EL Java Browser return
empty param.n param.n == null || param.n == "") (url || url?n=) true
not empty param.n !(param.n == null || param.n == "") (url?n=3) true


ex2 삼항연산)
${empty param.n?'값이 비어 있습니다.':param.n} 

 

결과 값 예제
EL Expression Result
${1 > (4/2)} false
${4.0 >= 3} true
${100.0 == 100} true
${(10*10) ne 100} false
${'a' < 'b'} true
${'hip' gt 'hit'} false
${4 > 3} true
${1.2E4 + 1.4} 12001.4
${3 div 4} 0.75
${10 mod 4} 2

 

'Development > Java' 카테고리의 다른 글

JSTL #8  (0) 2022.08.15
JSP, EL 보충 #7  (0) 2022.08.15
JSP MVC model #5  (0) 2022.08.14
Servlet & JSP (method) #4  (0) 2022.08.13
Servlet (service, doGet, doPost) #3  (0) 2022.08.13


<JSP MVC model (model, view, controller)>


Java 코드와 HTML 코드를 Mode(출력데이터)을 사용해 Controller(Java)와 View(Html)로 나누는 코드 작성 방식


JSP MVC model1
-컨트롤러와 뷰가 물리적으로 분리되지 않은 방식

출력 코드(View)에 단순하게 출력할 값을 저장한 변수(Model)만을 넣고
나머지 코드는 모두 입력 코드 부분(controller)으로 집중화


JSP MVC model2
-컨트롤러와 뷰가 물리적으로 분리된 방식

model1의 상태에서 Controller, Model 부분과 View를 다른 파일로 분리 
Dispatcher와 foward 기능을 사용해 view 호출

ex)
RequestDispatcher dispatcher = request.getRequestDispatcher("spag.jsp");
dispatcher.forward(request, response);
(서블렛의 업무를 이어갈 때는 foward, 새로 요청할 때는 redirect 사용)

-실행은 무조건 Controller에서 한다

'Development > Java' 카테고리의 다른 글

JSP, EL 보충 #7  (0) 2022.08.15
JSP EL(Expression Language) #6  (0) 2022.08.14
Servlet & JSP (method) #4  (0) 2022.08.13
Servlet (service, doGet, doPost) #3  (0) 2022.08.13
Servlet (Application, Session, Cookie) #2  (0) 2022.08.12



<JSP (Jasper)>


-html을 java servlet을 사용해 동적 페이지로 편하게 출력해 줄 수 있게 해주는 프로그램
(html 속에 java servlet이 직관적으로 보기 편하게 공존하는 뭐 그런 느낌이다)

-요청할 때마다 달라진 게 있다면 jasper는 다시 만들어주기 때문에 서버를 재시작할 필요가 없다.
(servlet 순수 개발은 재컴파일 과정이 필요하기에 ide 개발을 하더라도 서버를 재시작해줄 필요가 있었다)

-톰캣 프로젝트 명이 Catalina라 경로 폴더에 해당 프로젝트 명이 있다
(톰캣설치폴더\work\Catalina\localhost\ROOT\org\apache\jsp)

-.jsp 확장자를 사용하여 작성하며 파일명_jsp.java (컴파일시 파일명_jsp.class 추가) 로 생성된다
(.jsp 파일명 자체가 url로 맵핑된다)

-html 확장자를 jsp로 만들어 위 파일을 실제로 열어보면 무수한 out.write로 처리된 html 구문을 볼 수 있다
(옛날엔 실제로 일일히 out.write를 쳐줬다고 한다...ㅋ)



<Jasper를 이용한 코드 작성>


출력 코드(html,css)
-그대로 작성

<%! java code %>
-jsp 멤버함수, 멤버변수가 있는 클레스에 java code 사용
-jsp 메소드 밖, jsp 서비스 메소드가 속한 클래스에서의 코드 사용(일반 클래스에서 하는 작업이 모두 가능)

<% java code %> 
-jspService 메소드 내에서 사용하는 java code
-지역변수 알고리즘이 있는 함수 속이라 멤버변수 정의, 함수정의 등이 불가능

<%= 출력변수 %>
-<% out.print(출력변수) %>와 같은 의미

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8" %>
-page 지시자
-jsp에서는 인코딩 설정시 출력코드가 입력 지시보다 먼저 이루어지는 경우가 있기에 illegalStateException을 내뱉는다.
-그래서 page 인코딩 등의 설정에 우선 순위를 주기 위해 사용한다



<JSP 내장 객체>


-jasper에는 보이지 않을 뿐 jsp servlet와 내부 service 메소드에는 미리 정의해놓은 변수와 함수들이 존재한다.
-이 내장 객체들과 동일한 이름을 사용하면 오류가 발생한다.


<Servlet, JSP 내장 객체 환기>

 

Request

                                          메서드                                              설명
getParameterNames() 사용자가 전달한 키들을 Enumration 객체로 반환
getParameter(name) 사용자가 전달한 name과 일치하는 값을 반환
getParameterValues(name) 사용자가 전달한 name과 일치하는 값을 배열형식으로 반환
getCookies() 클라이언트에서 전달한 쿠키를 배열 형식으로 반환
getMethod() 현재 요청방식이 GET인지 POST인지를 문자열로 반환
getSession() 현재 세션 객체를 반환
getRemoteaddr() 클라이언트의 IP 주소를 반환
getProtocol() 현재 서버의 프로토콜을 문자열로 반환
setCharacterEncoding() 현재 JSP로 전달되는 내용을 지정한 문자셋으로 변환해준다.
getHeaderNames() 현재 요청이 가지는 헤더의 이름들을 반환
getHeaders(name) 현재 요청한 헤더에서 지정한 이름의 모든 값들을 반환
getQueryString() 현재 요청에 포함된 쿼리문자열을 반환
내장 객체 request : HttpServletRequest

 

Response

                                          메서드                                            설명
setContentType(type) 컨텐트 형식을 설정("test/html; charset=UTF-8")
setHeader(name, value) 클라이언트에게 헤더로 전달할 값을 설정
setDateHeader(name, date) 클라이언트에게 헤더로 전달할 날짜를 설정
sendError(status, msg) 클라이언트에게 에러코드와 메시지를 전달
sendRedirect(url) 클라이언트 요청을 다른 페이지로 전달
addCookie(cookie) 클라이언트에게 전달할 쿠키를 설정
encodeURL(url) URL로 유효하지 않은 문자를 인코딩
setStatus(sc) 상태 코드를 설정
내장 객체 response : HttpServletResponse

 

Out

                                          메서드                                             설명
getBufferSize() output buffer의 크기를 byte로 알려준다
getRemaining() 남아있는 버퍼의 크기중 사용가능한 비율을 알려준다
cleaBuffer() 버퍼에 있는 콘텐츠를 모두 지운다
flush() 버퍼를 비우고 output stream도 비운다
close() output stream을 닫고 버퍼를 비운다
println(content) content의 내용을 newline과 함께 출력한다
print(content) content의 내용을 출력한다
내장 객체 out : javax.servlet.jsp.JspWriter

 

Session

                                         메서드                                             설명
getID() 각 접속에 대한 세션 고유의 id를 문자열 형태로 반환
getCreationTime() 세션이 생성된 시간을 밀리세컨드 값으로 반환
getLastAccessedTime() 현재 세션으로 마지막 작업한 시간을 밀리세컨드 값으로 반환
getMaxInactiveInterval() 세션 유지 시간을 초로 반환
setMaxInactiveInterval(t) 세션 유효시간을 t에 설정된 초 값으로 설정
invalidate() 현재 세션을 종료. 세션과 관련한 값을 모두 지움
getAttribute(attr) 문자열 attr로 설정된 세션값을 object 형태로 반환
setAttribute(name,attr) 문자열 name으로 attr을 설정
removeAttribute(name) 세션에 설정한 속성 값을 삭제
내장 객체 session : javax.servlet.http.HttpSession

 

Application

                                          메서드                                             설명
setAttribute(name, value) application 범위의 값 설정
getAttribute(name) application 범위 값 얻기
getRealPath(path) 실제 물리 경로를 반환
getResource(path) path 경로의 리소스를 가리키는 URL을 반환
getServerInfo() 현재 요청 방식이 GET인지 POST인지를 문자열로 반환
getSession() 현재 세션 객체를 반환
getRemoteAddt() 클라이언트의 IP 주소를 반환
getProtocol() 현재 서버의 프로토콜을 문자열로 반환
setCharacterEncoding() 현재 JSP로 전달되는 내용을 지정한 문자셋으로 변환해준다
내장 객체 application : javax.servlet.ServletContext

 

 

'Development > Java' 카테고리의 다른 글

JSP EL(Expression Language) #6  (0) 2022.08.14
JSP MVC model #5  (0) 2022.08.14
Servlet (service, doGet, doPost) #3  (0) 2022.08.13
Servlet (Application, Session, Cookie) #2  (0) 2022.08.12
Servlet #1  (0) 2022.08.11



서버에서 페이지 전환 Redirection
response.sendRedirect("calc2");


쿠키 삭제하기
if(operator != null && operator.equals("C"))
expCookie.setMaxAge(0);


Java에서 자바스크립트 엔진 사용하여 구문 분석하기
ScriptEngine engine = new ScriptEngineManager().getEngineByName("nashorn");
try {
exp = String.valueOf(engine.eval(exp));
} catch (ScriptException e) {
e.printStackTrace();
}
-jdk11 이후부터는 nashorn 엔진은 지원되지 않는다. 
-자바에서 자바스크립트를 사용하고 싶다면 GraalVM 엔진을 사용하자.

 

엔진 변경 방법
1. 프로젝트 우클릭 -> configure -> convert to maven project 클릭
2. 생성된 pom.xml 파일에 
  <dependencies>
  <dependency>
    <groupId>org.graalvm.js</groupId>
    <artifactId>js</artifactId>
    <version>19.2.0.1</version>
</dependency>  
<dependency>
    <groupId>org.graalvm.js</groupId>
    <artifactId>js-scriptengine</artifactId>
    <version>19.2.0.1</version>
</dependency>
  </dependencies>
삽입 ( <build> 바로 위 )
ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js"); 

graal.js 삽입



                         service                            doGet                             doPost


HttpServlet을 상속받은 서블렛 클래스는 클라이언트에서 요청받은 메소드 방식에 따라 doGet, doPost 등 기타 다른 서비스 메소드를 자동으로 호출한다.
이때 해당 서비스 메소드가 오버라이드 되어있지 않으면 405 에러를 출력한다.
(URL을 찾을 수 없으면 404 에러)

동일한 서블렛 조각에서 GET 방식과 POST 방식을 한꺼번에 처리하는 방식을 원하면 service 메소드를 오버라이드 해서 super.service(req, resp);는 지우고 조건문 if(request.getMethod().equals("GET")){}등을 통해 원하는 서비스를 오버라이드 하도록 하고.

GET과 POST 요청을 따로 처리하길 원한다면 service 메소드를 오버라이드 하지 않고 doGet, doPost 메소드를 오버라이드 하여 사용한다.

또는 service 메소드 오버라이드에 super.service(req, resp); 호출을 통해 선택적으로 메소드 오버로드처럼 사용할 수도 있긴 하다.


Servlet 계산기 (JSP의 필요성)

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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@WebServlet("/calculator")
public class Calculator extends HttpServlet {
    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        
        Cookie[] cookies = request.getCookies();
        
        String exp = "0";
        if(cookies != null)
            for(Cookie c : cookies)
                if(c.getName().equals("exp")) {
                    exp = c.getValue();
                    break;
                }
        
        response.setCharacterEncoding("UTF-8");
        response.setContentType("text/html; charset=UTF-8");
        PrintWriter out = response.getWriter();
        
        out.write("<!DOCTYPE html>");
        out.write("<html>");
        out.write("<head>");
        out.write("<meta charset=\"UTF-8\">");
        out.write("<title>Insert title here</title>");
        out.write("<style>");
        out.write("input{");
        out.write("    width:50px;");
        out.write("    height:50px;");
        out.write("}");
        out.write(".output{");
        out.write("    height:50px;");
        out.write("    background: #e9e9e9;");
        out.write("    font-size:24px;");
        out.write("    font-weight: bold;");
        out.write("    text-align: right;");
        out.write("    padding:0px 5px;");
        out.write("}");
        out.write("</style>");
        out.write("</head>");
        out.write("<body>");
        out.write("    <form method=\"post\">");
        // POST를 폼에서 요청하고 있기 때문에 input 버튼을 누르면 doPost 메소드를 호출
        // 자기 자신의 페이지를 요청하기에 action 속성은 필요없다
        out.write("        <table>");
        out.write("            <tr>");
        out.printf("                <td class=\"output\" colspan=\"4\">%s</td>", exp);
        out.write("            </tr>");
        out.write("            <tr>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"CE\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"C\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"BS\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"/\" /></td>");
        out.write("            </tr>");
        out.write("            <tr>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"7\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"8\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"9\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"*\" /></td>");
        out.write("            </tr>");
        out.write("            <tr>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"4\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"5\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"6\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"-\" /></td>");
        out.write("            </tr>");
        out.write("            <tr>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"1\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"2\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"3\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"+\" /></td>");
        out.write("            </tr>");
        out.write("            <tr>");
        out.write("                <td></td>");
        out.write("                <td><input type=\"submit\" name=\"value\" value=\"0\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"dot\" value=\".\" /></td>");
        out.write("                <td><input type=\"submit\" name=\"operator\" value=\"=\" /></td>");
        out.write("            </tr>");
        out.write("        </table>");
        out.write("    </form>");
        out.write("</body>");
        out.write("</html>");
    
    }
    
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
 
        Cookie[] cookies = request.getCookies();
 
        String value = request.getParameter("value");
        String operator = request.getParameter("operator");
        String dot = request.getParameter("dot");
        
        String exp = "";
        if(cookies != null)
            for(Cookie c : cookies)
                if(c.getName().equals("exp")) {
                    exp = c.getValue();
                    break;
                }
        
        if(operator != null && operator.equals("=")) {
            ScriptEngine engine = new ScriptEngineManager().getEngineByName("graal.js");
            try {
                exp = String.valueOf(engine.eval(exp));
            } catch (ScriptException e) {
                e.printStackTrace();
            }
        }
        else if(operator != null && operator.equals("C")) {
            exp = "";
        }
        else {
            exp += (value == null)?"":value;
            exp += (operator == null)?"":operator;
            exp += (dot == null)?"":dot;
        }
        
        Cookie expCookie = new Cookie("exp", exp);
        if(operator != null && operator.equals("C"))
            expCookie.setMaxAge(0);
        
        expCookie.setPath("/calculator");
        // 다른 url에는 쿠키가 전달되지 않음
        response.addCookie(expCookie);
        response.sendRedirect("calculator");
        //response.sendRedirect("./"); 자기자신 호출
        //sendRedirect 함수 자체가 GET을 요청하기 때문에 doGet 메소드를 호출
        
    }
 
}
 
cs

 

out.write 노가다를 대신해 줄 JSP가 필요하게 됨 

'Development > Java' 카테고리의 다른 글

JSP MVC model #5  (0) 2022.08.14
Servlet & JSP (method) #4  (0) 2022.08.13
Servlet (Application, Session, Cookie) #2  (0) 2022.08.12
Servlet #1  (0) 2022.08.11
Tomcat  (0) 2022.08.11


<상태 유지의 필요성>

웹 서버 프로그램의 경우 일반 애플리케이션과 다르게 조각나 있는 상태와 같기 때문에
클라이언트로부터 데이터를 요청받고 응답한 뒤 서블렛 조각 프로그램은 종료되어버린다.
그러한 이유로 서블렛 간의 작업을 이어가기 위해서는 전역 변수와 같은 개념이 필요한데, 그러한 것을 위해 사용되는 객체들이 있다.



= Application, Session, Cookie  (기타_Hidden input, Querystring) =



Application 저장소 : 서블릿 컨텍스트(Context)
-어플리케이션(모든 서블릿) 전역에서 사용 가능


ServletContext application = request.getServletContext();
-서블릿 컨텍스트 생성

application.setAttribute("value", v);
application.setAttribute("operator", op);
-서블릿 컨텍스트에 객체 저장하기 (컬렉션의 Map과 같은 방식으로 저장된다)

application.getAttribute("value");
application.getAttribute("operator");
-서블릿 컨텍스트에 저장된 객체 가져오기 (말그대로 객체로 가져오므로 연산을 하려면 형변환이 필요하다)



Session 객체로 상태 값 저장하기
-세션(현재 접속한 사용자) 별로 사용 가능
(동일 브라우저 창은 다중 스레드로 구성되어 동일 세션을 사용하나, 다른 브라우저 끼린 다른 세션을 사용한다)
(세션의 사용자는 첫 response에 SID를 서버로부터 받아 이후의 요청에 사용한다)
(브라우저 개발자 도구의 network > cookie 에서 SID를 확인할 수 있다)


HttpSession session = request.getSession();
-세션 생성

session.setAttribute("value", v);
session.setAttribute("operator", op);
session.getAttribute("value");
session.getAttribute("operator");
-사용법은 서블릿 컨텍스트와 같다.

void setAttribute(String name, Object value)
-지정된 이름으로 객체를 설정

Object getAttribute(String name)
-지정한 이름의 객체를 반환

void invalidate()
-세션에서 사용되는 객체들을 바로 해제

void setMaxInactiveInterval(int interval)
-세션 타임아웃을 정수(초)로 설정

boolean isNew()
-세션이 새로 생성되었는지를 확인

Long getCreationTime()
-세션이 시작된 시간을 반환, 1970년 1월 1일을 시작으로 하는 밀리초

long getLastAccessedTime()
-마지막 요청 시간, 1970년 1월 1일을 시작으로 하는 밀리초

(세션 사용자들의 데이터를 항상 서버에서 저장하고 있을 수는 없기 때문에 위와 같은 추가 메소드를 사용한다)



Cookie를 이용해 상태 값 유지하기
-Application, Session이 서버 측에서 만들어지는 저장소라면 쿠키는 사용자(클라이언트) 브라우저에서 저장한다


Cookie(브라우저) === TCP/IP 정보, 헤더정보(브라우저가보냄), 사용자데이터 ===> 서버
서버 === 헤더정보 ===> Cookie

request.getHeader("remote-host")
-헤더 정보 가져오기
request.getParameter("x")
-사용자데이터 가져오기


Cookie cookie = new Cookie("c", String.valueOf(result));
response.addCookie(cookie);
-쿠키 저장하기(저장시키기 혹은 저장요청하기...)(쿠키는 문자열 형태로만 저장할 수 있기에 형변환 시켜준다)

Cookie[] cookies = request.getCookies();
String _c = "";
if (cookies != null)
  for (Cookie cookie : cookies)
    if("c".equals(cookie.getName()))
      _c = cookie.getValue();
-쿠키 읽기

cookie.setPath("/");
-쿠키 적용 url 설정하기
( "/" 모든 서블렛, "/abc" abc 주소가 요청할때만, "/abc/" abc가 포함된 모든 하위 서블렛 )

cookie.setMaxAge(int second);
-쿠키 수명 설정하기 

(0으로 설정시 즉시 삭제된다)
(기본값 : 브라우저의 생존주기와 같음)
(설정시 브라우저가 닫혀도 외부파일로 남아 설정한 시간동안 유지된다)

ex)
Cookie[] cookies = request.getCookies();
Cookie valueCookie = new Cookie("value", String.valueOf(v));
Cookie opCookie = new Cookie("op", op);
valueCookie.setPath("/");
valueCookie.setMaxAge(24*60*60);
opCookie.setPath("/");
response.addCookie(valueCookie);
response.addCookie(opCookie);



Application, Session, Cookie의 차이점 정리

  사용범위 생명주기 저장위치
               Application 전역 범위 에서 사용하는 저장 공간 WAS가 시작해서 종료할 때까지 WAS 서버의 메모리
                 Session 세션 범위에서 사용하는 저장 공간 세션이 시작해서 종료할 때까지 WAS 서버의 메모리
                  Cookie Web Browser별 지정한 path 범주 공간 Browser에 전달한 시간부터 만료시간까지 Web Browser의 메모리 또는 파일



오랜시간 저장해야하는 데이터라면 무조건 Cookie로 저장한다.
특정범위, 특정URL에서만 사용하는 데이터 또한 Cookie로 저장한다.

'Development > Java' 카테고리의 다른 글

Servlet & JSP (method) #4  (0) 2022.08.13
Servlet (service, doGet, doPost) #3  (0) 2022.08.13
Servlet #1  (0) 2022.08.11
Tomcat  (0) 2022.08.11
JDBC  (0) 2022.08.07

Servlet



<Eclipse IDE EE 버전으로 웹개발 환경 구축>
(WAS로는 tomcat 9 버전 사용)

Dynamic Web project로 프로젝트 생성
Target runtime에 사용할 tomcat 등록
Java Resources\src -여기에 java 패키지와 소스코드 작성
src\main\webapp  -여기에 html 작성
(버전에 따라 폴더 이름 또는 구성은 달라질 수 있다)

가동되는 브라우저를 변경하고 싶다면 window > web browser 변경
프로젝트 명이 url에 드러나지 않게 하려면 file > Properties > web project settings > Context root를 / 로 변경

 

웹 브라우저에서 실행되는 실제 파일은 위와 같은 이클립스 개발 디렉토리나 톰캣 폴더가 아닌
배포시 workspace\.metadata\.plugins\org.eclipse.wst.server.core 에서 복제되어 생성된다.



<Annotaion을 이용한 URL 맵핑>


@WebServlet("/hello")
public class Nana extends HttpServlet {}

-위처럼 어노테이션을 클래스 위에 붙여주면 web.xml 등 외부파일에서 설정할 필요없이 적용된다.
(Servlet 어노테이션 임포트 해야함)
-어노테이션을 사용해 url을 맵핑할 시 web.xml의 metadata-complete은 false로 바꿔주어야 한다.
(true로 되어 있으면 web.xml 의 설정이 우선된다)



<한글과 콘텐츠 형식>


브라우저에 response 하는 콘텐츠의 형식을 알려주지 않을 경우 브라우저는 자의적으로 해석한다.

ex) 익스플로러는 response한 문자열의 "<br>"을 html로 해석해 한줄을 내리지만 크롬은 text로 해석해 그대로 출력한다.
(tomcat 기본 인코딩은 ISO-8859-1)


=서버에서 한글을 지원하지 않는 문자코드로 인코딩 될 경우= 
(ex) ISO-8859-1 문자코드
한국어 출력 : ??:???????

해결법)
response.setCharacterEncoding("UTF-8");


=서버에서는 한국어를 지원하는 UTF-8로 인코딩해서 보냈지만 브라우저가 다른 코드로 잘못 해석한 경우=
(ex) EUC_KR 문자코드
한국어 출력 : 뒹귥◆땗뺎◆

해결법)
response.setContentType("text/html; charset=UTF-8");


이클립스에서 소스 파일 생성시 인코딩 방식 미리 설정하기
window > preference > web > files... > encoding 변경



<GET 요청과 쿼리스트링>


=쿼리스트링에 따른 request.getParameter("cnt");  반환 값=

http://localhost/hello?cnt=3   =GET=>

hello?cnt=3 =>   "3"
hello?cnt= =>   ""
hello? =>   null
hello =>   null

테스트용 html)
<body>
환영합니다.<br >
<a href="hi">인사하기</a><br >
<a href="hi?cnt=3">인사하기</a><br >
</body>



<POST 요청>


<form action="notice-reg" method = "post">
-url에 쿼리가 표시되지 않고 요청바디를 통해 요청됨

post 요청 시 title=abc&content=abcdefg 이러한 형태로 전달된다

=한글 포스트 시 깨짐 문제=
한국어 출력 : dsad ì•ˆë…•하세요

해결법)
request.setCharacterEncoding("UTF-8");

(tocat\conf\server.xml 외부 설정 파일에서 기본 인코딩 설정을 UTF-8로 가능하지만 권장되지 않는다)
(톰캣으로 운영하는 모든 서버가 UTF-8 이 되기 때문)



<Servlet Filter>


서블릿 request, respond가 실행되기 전 먼저 선행되어
인코딩 설정, 유효성 검사, 다른 url로 우회시키는 등의 일을 시킬 수 있는 필터 인터페이스.

public class CharacterEncodingFilter implements Filter {
@Override
  public void doFilter(ServletRequest request
    , ServletResponse response
    , FilterChain chain)
    throws IOException, ServletException {
      request.setCharacterEncoding("UTF-8");
      chain.doFilter(request, response);
    }
}

FilterChain 객체
필터가 언제 실행될 지, 어떻게 실행될지 흐름을 제어하는 용도
chain.doFilter(request, response);
다음 url로 진행시킨다



=Annotaion을 이용한 Filter URL 맵핑=

import javax.servlet.annotation.WebFilter;

@WebFilter("/*")
public class CharacterEncodingFilter implements Filter {}



=web.xml 설정을 통한 url맵핑=

  <filter>
   <filter-name>characterEncodingFilter</filter-name>
   <filter-class>패키지.CharacterEncodingFilter</filter-class>
  </filter>
  <filter-mapping>
   <filter-name>characterEncodingFilter</filter-name>
   <url-pattern>/*</url-pattern>
  </filter-mapping>

->   /* 모든 url에 대해 필터를 적용시킬 경우

 

 

 

<입력 데이터 배열로 받기>

[html]

<body>
<form action="add2" method="post">
<div>
<input type="text" name="num" />
<input type="text" name="num" />
<input type="text" name="num" />
<input type="text" name="num" />
</div>
<div>
<input type="submit" value="덧셈" />
</div>
<div>
결과 : 0
</div>
</form>
</body>


[servlet]
String[] num_ = request.getParameterValues("num");
int result = 0;
for (int i = 0; i < num_.length; i++) {
  int num = Integer.parseInt(num_[i]);
  result += num;
}
response.getWriter().printf("result is : %d\n", result);



'Development > Java' 카테고리의 다른 글

Servlet (service, doGet, doPost) #3  (0) 2022.08.13
Servlet (Application, Session, Cookie) #2  (0) 2022.08.12
Tomcat  (0) 2022.08.11
JDBC  (0) 2022.08.07
Java Thread & Sync  (0) 2022.08.04

 

 

 

<톰캣>
https://tomcat.apache.org

-톰캣9 다운로드
서비스 목적이면 인스톨 버전 설치 (부팅 시 서비스목록에 추가)
개발, 공부 목적이면 집파일 설치

-JAVA_HOME  jdk 환경변수 등록이 안되어 있으면 등록

-톰캣 폴더 내 bin 폴더 startup.bat 실행
(안될 경우 jdk 환경변수 또는 이미 설치된 톰캣이 포트를 점거하고 있을 수 있다)

-localhost:8080포트를 사용. 브라우저로 접속이 되는지 확인한다.



<Tomcat (Java Web Application Server) - WAS>

java에서 자주 쓰이는 WAS 중 하나.
WAS와 웹 서버 기능이 포함되어있다.

WEB SERVER 
- 웹 브라우저 클라이언트로부터 HTTP 요청을 받고, 정적인 컨텐츠(html, css 등)를 제공하는 컴퓨터 프로그램

Web Application Server (WAS) 
- DB 조회 및 다양한 로직 처리 요구시 동적인 컨텐츠를 제공하기 위해 만들어진 애플리케이션 서버

클라이언트(사용자) - 웹서버(웹문서제공자) - WAS(동적콘텐츠제공) - DB서버

퍼포먼스를 위해 위처럼 하드웨어적으로 나누어져 있는 게 기본이지만 서비스 규모에 따라 달라진다.

톰캣폴더\webapps\ROOT 폴더에 txt 등의 문서 파일을 넣으면 브라우저의 ip:8080/문서명.확장자 주소에서 확인할 수 있다.



<context 사이트>

-https://locahos:8080/분리사이트
-분리사이트의 폴더가 실제 톰캣 루트 폴더에 위치하지 않아도 conf 서버의 server.xml 수정을 통해 context 해줄 수 있다
(권장되지 않는 방법이다)

<Host name="localhost" appBase="webapps ">
<Context path = "컨텍스트할폴더" docBase="컨텍스트할폴더가있는경로" privileged="true"/>
</Host>


tomcat\webapps\ROOT\WEB-INF\classes 
-작성하여 WAS에서 실행 할 Java 패키지 및 클레스 파일들은 해당 폴더 내에 위치
-해당 폴더는 url을 통한 요청이 불가능하며 비공개 상태
-WEB_INF 내의 web.xml 문서의 수정을 통해 컴파일된 java 클래스를 url 주소로 맵핑 시켜줄 수 있다.

(하지만 web.xml 은 공용 설정 파일이므로 어노테이션 맵핑 방식을 주로 사용한다)

  <servlet>
  <servlet-name>na</servlet-name>
  <servlet-class>package.Nana</servlet-class>
  </servlet>
  <servlet-mapping>
  <servlet-name>na</servlet-name>
  <url-pattern>/hello</url-pattern>
  </servlet-mapping>

  <display-name>Welcome to Tomcat</display-name>

-package 패키지 안에 있는 Nana 클래스 파일을 localhost:8080/hello 로 맵핑



Servlet 기본 코드

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.*;

public class ??? extends HttpServlet
{
  public void service(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
    PrintWriter out = resp.getWriter();
    out.println("web page output")
  }
}

HttpServlet 추상 클래스를 상속받아 service() 를 구현한다.

개발환경을 사용하지 않을 경우 import되는 servlet은 tomcat\lib\servlet-api.jar 을 필요로 한다.

web.xml 빨간색 줄 에러 문제가 생길 경우
xml을 정의하는 xsd 스키마 파일의 주소가 http에서 https로 바뀌면서 에러 발생
주소를 https로 바꿔주면 해결된다

 


○ 위의 과정들은 번거로우므로 이클립스 등에서 웹 개발환경을 사용하여 컴파일, xml 편집, 서버 재시작 등을 할 필요 없이 편하게 개발할 수 있다.

'Development > Java' 카테고리의 다른 글

Servlet (Application, Session, Cookie) #2  (0) 2022.08.12
Servlet #1  (0) 2022.08.11
JDBC  (0) 2022.08.07
Java Thread & Sync  (0) 2022.08.04
JAVA Collection & Generic  (0) 2022.08.04

+ Recent posts