※ servlet, jsp
1. servlet괴 jsp의 개념
- 기능의 차이는 없고 역할의 차이만 있다 (하는일은 같음)
1-1) servlet
- servlet은 java이다.
- 웹 기반의 요청에 대한 동적인 처리가 가능한 server side에서 돌아가는 자바 프로그램
- 웹개발을 위해 만든 자바기반의 표준
- 쉽게말해서 Java 코드를 작성하는곳
1-2) jsp
- Java 언어를 기반으로 하는 Server side 스크립트 언어
- Servlet을 보완하기위해 만든 추가적인 기능
- Servlet의 기능에 몇가지 기능을 더 추가한것
- 자바코드를 jsp에서 쓰는것이 좋지못하여 servlet과 같이 사용함
- 쉽게말해서 html코드를 작성하는곳
1-3) Web Sevice의 기본적인 동작 과정
* 요청과 응답
- 사용자에서 자바프로그램으로 가는게 요청
- 자바프로그램에서 사용자한테 가는게 응답
* get방식, post방식
2. servlet과 jsp의 관계
2-1) jsp만을 이용하는 모델
- jsp가 사용자의 요청을 받아 java bean(dto, dao)을 호출하여 적절한 동적인 페이지를 생성할 수 있다.
- 모든 변수는 private이다
2-1-1) 동작과정
- jsp로 작성된 프로그램은 내부적으로 was에서 servlet파일로 변환 (jsp는 본질적으로 자바임)
- jsp태그를 분해하고 추출하여 다시 순수한 html웹페이지로 변환
- 클라이언트로 응답
2-1-2) 특징
- 개발속도가 빠름
- 배우기 쉬움
- 프레젠테이션 로직과 비즈니스 로직이 혼재함
- jsp코드가 복잡해져 유지보수가 어려움
- jsp에 대한 직접적인 노출은 위험함
2-2) jsp와 servlet을 모두 이용하는 모델 (MVC Architecture)
- MVC (model (Java Beans), view(JSP), controller(Servlet))
- jsp,와 servlet을 모두 사용하여 프레젠테이션 로직(view)과 비즈니스 로직(controller)을 분리
- 클라이언트 > 컨트롤러 > 서비스 > dao > db > dao > 서비스 > 컨트롤러 > view
*mvc architecture
model, view, controller를 분리한 상태
2-2-1) 동작과정
* _jsp.java 구성원리
/*
* Generated by the Jasper component of Apache Tomcat
* Version: Apache Tomcat/9.0.46
* Generated at: 2023-03-06 01:38:15 UTC
* Note: The last modified time of this file was set to
* the last modified time of the source file after
* generation to assist with modification tracking.
*/
package org.apache.jsp;
import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;
public final class login_jsp extends org.apache.jasper.runtime.HttpJspBase
implements org.apache.jasper.runtime.JspSourceDependent,
org.apache.jasper.runtime.JspSourceImports {
private static final javax.servlet.jsp.JspFactory _jspxFactory =
javax.servlet.jsp.JspFactory.getDefaultFactory();
private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;
private static final java.util.Set<java.lang.String> _jspx_imports_packages;
private static final java.util.Set<java.lang.String> _jspx_imports_classes;
static {
_jspx_imports_packages = new java.util.HashSet<>();
_jspx_imports_packages.add("javax.servlet");
_jspx_imports_packages.add("javax.servlet.http");
_jspx_imports_packages.add("javax.servlet.jsp");
_jspx_imports_classes = null;
}
private volatile javax.el.ExpressionFactory _el_expressionfactory;
private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;
public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
return _jspx_dependants;
}
public java.util.Set<java.lang.String> getPackageImports() {
return _jspx_imports_packages;
}
public java.util.Set<java.lang.String> getClassImports() {
return _jspx_imports_classes;
}
public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
if (_el_expressionfactory == null) {
synchronized (this) {
if (_el_expressionfactory == null) {
_el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
}
}
}
return _el_expressionfactory;
}
public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
if (_jsp_instancemanager == null) {
synchronized (this) {
if (_jsp_instancemanager == null) {
_jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
}
}
}
return _jsp_instancemanager;
}
public void _jspInit() { // 중요메서드
}
public void _jspDestroy() { // 중요메서드
}
// 가장 중요한 메서드 (본문)
public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
throws java.io.IOException, javax.servlet.ServletException {
if (!javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
final java.lang.String _jspx_method = request.getMethod();
if ("OPTIONS".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
return;
}
if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method)) {
response.setHeader("Allow","GET, HEAD, POST, OPTIONS");
response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP들은 오직 GET, POST 또는 HEAD 메소드만을 허용합니다. Jasper는 OPTIONS 메소드 또한 허용합니다.");
return;
}
}
// 지역변수 선언
final javax.servlet.jsp.PageContext pageContext;
javax.servlet.http.HttpSession session = null;
final javax.servlet.ServletContext application;
final javax.servlet.ServletConfig config;
javax.servlet.jsp.JspWriter out = null;
final java.lang.Object page = this;
// 위는 사용가능 변수 아래 2개는 사용을 안함
javax.servlet.jsp.JspWriter _jspx_out = null;
javax.servlet.jsp.PageContext _jspx_page_context = null;
try {
response.setContentType("text/html; charset=UTF-8"); // 응답 타입 지정
pageContext = _jspxFactory.getPageContext(this, request, response,
null, true, 8192, true);
_jspx_page_context = pageContext;
application = pageContext.getServletContext();
config = pageContext.getServletConfig();
session = pageContext.getSession();
out = pageContext.getOut();
_jspx_out = out;
out.write("\r\n");
out.write("<!DOCTYPE html>\r\n");
out.write("<html>\r\n");
out.write("<head>\r\n");
out.write("<meta charset=\"UTF-8\">\r\n");
out.write("<title>Insert title here</title>\r\n");
out.write("</head>\r\n");
out.write("<body>\r\n");
out.write("<form method=\"post\">\r\n");
out.write(" <input type=\"text\" name=\"id\" placeholder=\"id입력\">\r\n");
out.write(" <input type=\"password\" name=\"pw\" placeholder=\"pw입력\">\r\n");
out.write(" <button>로그인</button>\r\n");
out.write("</form>\r\n");
out.write("<p>");
out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${member}", java.lang.String.class, (javax.servlet.jsp.PageContext)_jspx_page_context, null));
out.write("</p>\r\n");
for(int i=2; i<=9; i++) {
for(int j=1; j <=9; j++) {
out.println("<p>" + i + " * " + j + " = " + i * j + "</p>");
}
}
out.write("\r\n");
out.write("</body>\r\n");
out.write("</html>");
} catch (java.lang.Throwable t) {
if (!(t instanceof javax.servlet.jsp.SkipPageException)){
out = _jspx_out;
if (out != null && out.getBufferSize() != 0)
try {
if (response.isCommitted()) {
out.flush();
} else {
out.clearBuffer();
}
} catch (java.io.IOException e) {}
if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
else throw new ServletException(t);
}
} finally {
_jspxFactory.releasePageContext(_jspx_page_context);
}
}
}
login.jsp파일 수정후 실행하면 login_jsp.java파일에서 메세지 출력
변경된 파일을을 변경해주세요 / 무시하세요
* jsp의 탄생배경
- sevlet의 불편함을 해소하기 위해 탄생
3. jsp와 servlet의 차이, 공통점
-
3-1) tomcat의 구조
-
3-2) dynamic web project 구조
*tomcat 수동설치
https://tomcat.apache.org/download-90.cgi
Apache Tomcat® - Apache Tomcat 9 Software Downloads
Welcome to the Apache Tomcat® 9.x software download page. This page provides download links for obtaining the latest version of Tomcat 9.0.x software, as well as links to the archives of older releases. Unsure which version you need? Specification version
tomcat.apache.org
윈도우즈 서비스 인스톨러 다운
8080 포트는 사용중이니 8090으로 변경한다. (제일 중요)
나머지는 건드릴것 없고 인스톨 ㄱㄱ
우측하단 톰캣이 켜져있으면 톰캣서버가 현재 구동중이라는것 이다.
인터넷 창에 localhost:8090 하면 톰캣이 실행중인지 아닌지 확인 할 수 있다.
** 나중에 aws에선 톰캣을 4개정도 키게 될것...
- 예를들어 사용자가 8080의 포트를 가진 톰캣 서버를 사용하고 있을시 변경사항을 반영해야할때 8080의 서버를 재구동 시키고 사용자한테는 8090의 톰캣 서버를 보여주는것 이것을 서버 분산작업이라고 함
* 배포작업
jsp는 루트에 노출되어 있다.
web-inf 폴더 classes에는 class파일에 있다.
아까 톰캣을 깔았던 폴더로 들어가면
conf는 콘피그 파일들,
lib는 톰캣을 구동하기 위한 여러 자료들이 있고
logs는 서버를 구동했을때 로깅파일들이 텍스트형태로 있고, 제일 많이 보게될것은 catalina
제일 중요한 webapps는 와르파일을 입력하는곳이다.
ROOT폴더가 서버 구동시 처음 본 고양이가 있던 파일이다.
이곳에 아까 따로 만들었던 WAR파일을 붙여넣기하면 자동으로 압축 해제가 된다.
이제 인터넷 검색창에 아래 url을 입력한다.
http://localhost:8090/test/login
이후 톰캣을 설치했던 폴더에 log폴더에 들어가서 stuout.log파일을 메모장으로 열어보면
사용했떤 로그가 기록되어있는걸 볼 수 있다.
server.xml을 켜서 connect에 포트를 80으로 바꿔서 login에서 다시 실행하면 url에 포트가 사라져있는걸 볼 수 있다.
다시 xml파일로 가서 context파일의 path를 "/"로 변경하고 다시 login에 가서 서버를 다시 재구동하면
no를 누르면 url이 좀 더 줄어든걸 볼 수 있다.
* web.xml
servers의 web.xml과 아래 web-inf의 web.xml를 확인하려고 한다. (하자마자 x뜰텐데 일단 내비두자)
severs의 web.xml은
web.xml은 프로젝트의 설정파일이다. (파일이 없어도 수행이 가능하긴함 없으면 servers의 xml을 사용)
* mime-mapping : 파일들은 대부분의 mime-type을 가지고 있다. / 파일 다운로드 할 때 사용
자주사용 하는 mime-type : html, xml, json, image, octet-stram
* web-xml의 구조
확장자가 없는것은 요청이름 이라 하고
맨 위에 welcome-file(webServlet)의 이름을 바꾸면 localhost접속시 가장 처음에 뜨는 화면이 바뀐다.
리퀘스트가 주소고 주소가 곧 리퀘스트다
요청이름(url패턴) 이 같을경우 나오는 오류로그
주소를 해석하는것이 가장 중요한 요청과 동작의 대한 시작
※ 새로운 다이나믹 웹 프로젝트 생성
넥스트 2번 눌러 web-xml을 꼭 만들어주자
클래스 생성
extends HttpServlet을 꼭 해줘야 된다.
override
총 3개 오버라이딩 (총 3개는 서블릿 라이프사이클이다. )
package controller;
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 HelloWorld extends HttpServlet {
private static int count;
@Override
public void init() throws ServletException { // 초기화 시점에 딱 한번함
count++;
System.out.println(count);
}
@Override
protected void service(HttpServletRequest arg0, HttpServletResponse arg1) throws ServletException, IOException { // 요청이 있을때 마다 할일,
count++;
System.out.println(count);
}
@Override
public void destroy() { // 없어지는 시점에 딱 한번함, 해당 서블릿이 종료될 때 자원에 대한 반납
count++;
System.out.println(count);
}
}
*
xml조건
1. root 태그가 있어야함.
* web-xml 수정
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1">
<servlet>
<servlet-name>hi</servlet-name> 변수명 기입
<servlet-class>controller.HelloWorld</servlet-class> 클래스명 기입 (정확하게 있는 클래스인지 꼭 확인해야함)
</servlet>
<servlet-mapping>
<servlet-name>hi</servlet-name> 바라봐야할 변수명 기입 (변수명과 같아야함)
<url-pattern>/hello</url-pattern> 사용시 바라봐야할 url
</servlet-mapping>
<display-name>1_servlet</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
실행시
새로고침시 숫자가 점점 증가
풀이)
시점을 알아야 한다.
톰캣 실행시 해당 url 패턴을 찾아 이름을 탐색하는데, web.xml의 클래스를 찾고 없으면 404 있으면 컴파일 하여 로드한다.
init가 구동되고 딱 한번만 로드되고 1이 출력
service가 실행되어 2가 출력된다. (서버는 계속 구동중)
init은 딱 한번만 로드되므로 새로고침 혹은 다시 url을 타고 접속할 시 service가 계속 실행되어 숫자가 점점 올라가게 된다.
distroy는 언제 실행될지 예측되기 힘듬.
정리하자면 init은 클래스가 로드될시 1번 실행, service는 해당 페이지에 접근 혹은 새로고침될때마다 실행
* 스레드, 프로세스는 5단계의 라이프사이클이 존재
*
동일한 파일명인데 대소문자 때문에 파일명을 변경하게 되면 운영체제는 대소문자를 구분하지 못하여
class not found exception이 발생한다.
*
webservlet에 ()을 하고 괄호에 자동완성을 하면 위 사진처럼 나온다
1. value (기본값)
문자열을 사용시 value값을 사용한다고 보면 된다.
value는 String배열타입이며 @WebServlet(value = {"/java", "/servlet"}) 이런식으로 사용이 가능하다.
2. initParams는 init시 해야할일을 적어놓을 수 있다. (자주 사용안함)
예시) @WebServlet(value = {"/java", "/servlet"}, initParams = @WebInitParam(name = "version", value = "17.0"))
3.urlPatterns
@WebServlet(urlPatterns = "/java" )
사실 위에 세개는 다 똑같음 가장 편한걸로 사용
※ Filter
https://jun-itworld.tistory.com/28 표 참고
- filter는 클라이언트, 자원 두쪽에 모두 다 보낼수 있음.
취미가 하나밖에 안나오는 이유는 문자열은 맨앞에 있는 한쌍만 받기때문에 하나만 출력된다.
예제) 회원가입 예제
1. lombok.jar , mariadb-java lib에 복사
2. join.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>
<!-- 방법 1
method를 post로 바꾸면 한글이 깨진다.
post 방식은 header(meta data)로 보내는데 header에는 인코딩방식이 뭔지 모르기 때문에
받는쪽에서 어떤방식으로 인코딩될지 모른다. 그럼 java파일에서
req.setCharacterEncoding("utf-8");를 입력해주면 utf-8로 받으라고 요청하게되며 한글깨짐이 사라진다.
방법 2
필터를 쓰자....
-->
<form action="joinProcess" method="post">
<!-- 파라미터가 다르면 무조건 null값이 들어감 -->
<input type="text" name="id" placeholder="id입력"><br>
<input type="password" name="pw" placeholder="pw입력"><br>
<input type="password" name="pw_chk" placeholder="pw확인"><br>
<input type="text" name="name" placeholder="이름"><br>
<hr>
성별
<label><input type="radio" name="gender" value="male">남</label>
<label><input type="radio" name="gender" value="female">여</label>
<hr>
취미
<label><input type="checkbox" name="hobby" value="read">독서</label>
<label><input type="checkbox" name="hobby" value="movie">영화감상</label>
<label><input type="checkbox" name="hobby" value="fishing">낚시</label>
<label><input type="checkbox" name="hobby" value="climbing">등산</label>
<hr>
<button>회원가입</button>
</form>
</body>
</html>
2. join.java 생성
package controller;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Map;
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 lombok.AllArgsConstructor;
import lombok.Data;
@WebServlet("/joinProcess")
public class Join extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// parameter 처리 메서드
// getParameter(문자열 : name) => name에 해당하는 value 반환
// getParameterValues(문자열:name) => name에 해당하는 values 반환 (String[]) 여러개를 반환해야할 시 사용하면 좋음
// getParameterNames() => 모든 파라미터들의 이름을 Enumeration 타입으로 반환
// getParameterMap() =>
// method가 post방식으로 변경 후 한글 깨짐 발생시사용
// 인코딩방식 변경방법1
// req.setCharacterEncoding("utf-8");
String id =req.getParameter("id");
String pw =req.getParameter("pw");
String name =req.getParameter("name");
String gender =req.getParameter("gender");
String[] hobby =req.getParameterValues("hobby");
@Data
@AllArgsConstructor
class MyVo {
String id;
String pw;
String name;
String gender;
String[] hobby;
}
MyVo vo = new MyVo(id, pw, name, gender, hobby);
System.out.println(vo);
System.out.println("==================");
Enumeration<String> paramNames = req.getParameterNames(); // 순환가능 대상자
while(paramNames.hasMoreElements()) {
String key = paramNames.nextElement();
if(key.equals("hobby")) {
System.out.println(key + ":" + Arrays.toString(req.getParameterValues(key)));
}
else {
System.out.println(key + ":" + req.getParameter(key));
// System.out.println(paramNames.nextElement()); // 이름들만 나옴
}
}
// Map으로 순환하는법
System.out.println("==================");
Map<String, String[]> map = req.getParameterMap();
// System.out.println(map); //ketSet, entrySet 둘중 하나로 해야함
for(String key : map.keySet()) {
System.out.println(key + ":" + Arrays.toString(map.get(key)));
// System.out.println(paramNames.nextElement()); // 이름들만 나옴
}
}
}
3. filter 생성
3-1) 인코딩 필터
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
//인코딩 방법 2 Filter 사용
@WebFilter("/*") // *는 모든 요청에 이 필터를 모두 씌우겠다는 의미 따로 추가작업을 해줄 필요가 없음
public class EncodingFilter implements Filter {
// doFilter(필수)는 있어야함.
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) // service역할과 같음
throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
chain.doFilter(request, response);
}
}
3-2) 로깅필터
package filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
@WebFilter("/*")
public class LoggingFilter implements Filter{
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest hsr = (HttpServletRequest) request;
String uri = hsr.getRequestURI();
long start = System.currentTimeMillis(); // 전에 할일
chain.doFilter(request, response); // 실제 service 수행
long end = System.currentTimeMillis(); // 후에 할일
System.out.println(end - start + "ms........... in" + uri); // 응답 보내기전에 실행
}
}
주의할점
취미가 하나밖에 안나오는 이유는 문자열은 맨앞에 있는 한쌍만 받기때문에 하나만 출력된다.
이때 getParameterValues
※ JSP
1. 선언
- directive, scriptlet, expression
2. 내장객체
-request, response, page, pageContext, session(cookie), application, config, out, exception
3. 영역객체
page, request, session, application
4. EL
5. JSTL
6. DB-connection, 파일업로드, Ajax, Restful
'Servlet, JSP > Servlet, JSP' 카테고리의 다른 글
23-03-15 Servlet, JSP (0) | 2023.03.15 |
---|---|
23-03-13 Servlet, JSP (0) | 2023.03.13 |
23-03-09 (1) Servlet, JSP (0) | 2023.03.09 |
23-03-07(1) Servlet, JSP (0) | 2023.03.07 |