# [Java] JSP와 Servlet 학습 노트

> JSP와 Servlet 이 노트와 함께 보는 영상은 《【SiKi学院JavaEE视频教程】JavaWeb第一季基础》 《【SiKi学院JavaEE视频教程】JavaWeb第二季进阶》입니다. 머리말 개인적으로 알아본 바로는 JSP는 이미 은퇴에 가까운 추세이므로, 여러분은 깊이 파고들 필요 없이 맛만 볼 정도로 하면 됩니다. Servlet은 깊이 이해해야 하며, 이는…

- 게시일: 2019-11-16
- 태그: Java, Servlet
- HTML 버전 보기: https://bilibili.cat/ko/posts/java-jsp-servlet
- 中文에서 AI 번역: https://bilibili.cat/posts/java-jsp-servlet

---

# JSP와 Servlet

> #### 이 노트와 함께 보는 영상은
>
> > [《【SiKi学院JavaEE视频教程】JavaWeb第一季基础》](http://www.sikiedu.com/course/214)  
> > [《【SiKi学院JavaEE视频教程】JavaWeb第二季进阶》](http://www.sikiedu.com/course/218)

> #### 머리말
>
> > 개인적으로 알아본 바로는 JSP는 이미 은퇴에 가까운 추세이므로, 여러분은 깊이 파고들 필요 없이 맛만 볼 정도로 하면 됩니다.  
> > Servlet은 깊이 이해해야 하며, 이는 앞으로 많은 프레임워크의 기초가 됩니다.

## ***흐름도 코드가 포함되어 있으므로 전문 md 편집기로 확인하는 것을 권장합니다(印象笔记도 가능합니다).***

---

## JSP 기본 문법

#### 가져오기

```jsp
<%@page import=""%>
```

#### 주석

```jsp
<%-- code --%>
```

#### 작성

```jsp
<% code %>
```

#### 표현식 정의

```jsp
<%! 成员变量 %>
```

#### 태그 가져오기

> 일반적으로 여러 웹 페이지를 가져올 때 중복되는 부분에 사용할 수 있습니다.
>
> 또는

```xml
<jsp:include page="xxx.jsp"></jsp:include>
```

## 내부 클래스와 자주 쓰는 메서드

> #### out (== sou)
>
> > println()  
> > println()은 출력에 사용하며, “=”로 대체할 수도 있습니다.
>
> #### request（생명 주기는 한 번의 HTTP 내에서만）
>
> > 1.  getParameter()  
> >     매개변수 가져오기
> > 2.  getRequestDispatcher(url).forward(request, response)  
> >     요청 포워딩 request\_do->login->client (경로 문제에 주의해야 합니다)
> > 3.  setAttribute(key, content)/getAttribute(key)  
> >     값 전달
> > 4.  getSession()  
> >     session 객체 가져오기
> > 5.  getContextPath()  
> >     프로젝트 경로 가져오기, 상대 경로에 사용
>
> #### response
>
> > 1.  getWriter().println()  
> >     html head에 작성
> > 2.  getWriter().append()  
> >     추가
> > 3.  sendRedirect(url)  
> >     리다이렉트 request\_do->client->login
>
> #### session
>
> > setAttribute(key, content)/getAttribute(key)  
> > 값 전달
>
> #### application（유일한 객체）
>
> > setAttribute(key, content)/getAttribute(key)  
> > 값 전달
>
> #### page
>
> > \== this 키워드
>
> #### pageContext （컨테이너）
>
> > 1.  getOut()  
> >     out 객체 가져오기
> > 2.  getRequest()  
> >     req
> > 3.  getResponse()  
> >     resp
> > 4.  getServletContext()  
> >     app
> > 5.  getSession()  
> >     session

## Servlet

> 흐름 처리만 담당하며 jsp와 분리합니다.  
> extend HttpServlet throw ~Exception  
> doGet(req, resp) and doPost(req, resp)를 재정의하여 사용합니다.
>
> @WebServlet(“url”) 애노테이션으로 위치를 지정합니다.  
> web.xml로 위치를 지정할 수도 있습니다(프로젝트 생성 시 next에서 체크하면 자동 생성 가능).

```xml
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>
com.sikiedu.servlet.LoginServlet
</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/login_ do</url-pattern><!-- 访问路径-->
</servlet-mapping>
</servlet>
```

---

> #### 생명 주기

![흐름도 1](https://cos2.endcloud.cn/legacy/halo/java-jsp-servlet/mermaid-1.svg)

## EL 표현식

> jsp 작성 방식을 간소화하고 코드량을 줄이며 가독성을 최적화하는 데 사용합니다.

#### 변수 가져오기

> 1.  $
> 2.  $
>
> （~는 req, session, application）  
> （scope 우선순위는 req, session, application）
>
> ***일반적으로 첫 번째 형식만 사용하면 됩니다***

#### 클래스 변수 가져오기

> $

#### map과 컬렉션 가져오기

> ${map.key} and $

#### 연산

> ${±\*/}  
> ${> \< == || !}  
> $

#### 내부 클래스

> $

## JSTL 태그

> jsp 작성 방식을 더욱 간소화하고 코드 가독성을 최적화합니다.  
> 현대적인 데이터 주도형 프런트엔드 프레임워크 문법의 초기 형태를 갖추고 있습니다.  
> 예: Vue.js, Angular.js.

#### jar 패키지 다운로드

> [다운로드 링크 -> mvnrepository](https://mvnrepository.com/artifact/javax.servlet/jstl/1.2)

#### 가져오기

```xml
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
```

#### 값 정의

```xml
<c:set var="" value="" scope=""></c:set>
```

#### 값 제거

```xml
<c:remove var=""/>
```

#### 값 출력

```xml
<c:out value=""/>
```

#### 조건 판단

```xml
<c:choose>
<c:when test="${condition}">code</c:when>
<c:otherwise>code</c:otherwise>
</c:choose>
```

#### 반복

```xml
<c:foreach var="i" begin="index1" end="index2">
code
</c:foreach>
<c:foreach items="${list}" var="x">${x.var}</c:foreach>
```

## json

> 전체 이름은 "JavaScript Object Notation"이며,  
> 경량 데이터 교환 형식이고, 원형은 JavaScript의 데이터 객체입니다.  
> [자세히 알아보기](https://www.json.org/json-zh.html)

## fastjson

> Alibaba에서 출시한 오픈소스 Java용 json 조작 라이브러리입니다.  
> [fastjson의 공식 GitHub](https://github.com/alibaba/fastjson)

#### jar 패키지 다운로드

> [다운로드 링크->mvnrepository](https://mvnrepository.com/artifact/com.alibaba/fastjson/1.2.62)

#### 가져오기

```java
import com.alibaba.fastjson.JSON
```

#### 직렬화

```java
JSON.toJSONString(object);
```

#### 역직렬화

```java
JSON.parseObject(String, object.class);
```

#### 배열 직렬화

```java
JSON.parseArray(String, object.class);
```

## ajax

> 전체 이름은 "Asynchronous Javascript And XML"이며,  
> 비동기 요청을 통해 웹 페이지를 새로 고치지 않고 데이터를 갱신하는 기술입니다.  
> ***이는 JavaScript의 기술이며 Java의 기술이 아닙니다.***

#### JQuery 구현

```JavaScript
setInterval("callAjax()", 2000);//定时调用方法，参数单位为毫秒
function callAjax() {
    $.ajax({
        url: "${pageContext.request.contextPath }/ajaxrequest" ,
        type:"get",
        success: function(msg){
            }
});
$("input").blur(callAjax); //失焦响应方法
```

#### 네이티브 JS 구현

```JavaScript
function callAjaxByJS(){
    var xmlhttp = new XMLHttpRequest();
    xmlhttpopen("GET", endcodeURI("${pageContext.request.contextPath}/ajaxRequest?data=我是数据&"+Math.random()), true)
    xmlhttp.send();
    xmlhttp.onreadystatechange = function(){
    if( xmlhttp.readyState==4 && xmlhttp.status==200 ){
     //得到了服务器端的响应，4代表ajax响应已完成，200是http正常状态码
            $("#msg").append(xmlhttp.responseText);
        }
    }
}
```

## Filter

> class implement Filter

#### 생명 주기

> 생성자->init()->doFilter()->destory()

#### doFilter()

> chain.doFilter()는 필터 체인을 시작합니다.

```java
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
    // TODO Auto-generated method stub
    // place your code here
    System.out.println("test1 filter before");
    // pass the request along the filter chain
    chain.doFilter(request, response);
    System.out.println("test1 filter after");
}
```

> web.xml을 통해 필터 조건과 순서를 설정하며,  
> @WebFilter(“/\*”)를 사용하여 조건을 설정할 수도 있습니다.

```xml
<filter>
<filter-name>Test1Filter</filter-name><!-- 名称 -->
<filter-class>com.sikiedu.filter.Test1Filter</filter-class><!-- 类名 -->
</filter>
<filter>
<filter-name>Test2Filter</filter-name>
<filter-class>com. sikiedu.filter.Test2Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>Test2Filter</filter-name>
<url-pattern>/*</url-pattern><!-- 过滤目录 -->
</filter-mapping>
<filter-mapping>
<filter-name>Test1Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
```

> web.xml에 설정된 순서는 response 시 역순이 되며,  
> 즉 chain.doFilter() 뒤에 작성된 코드가 실행됩니다.  
> 일반적으로 사용할 필요는 없습니다.

#### 권한 관리 필터링

```xml
<filter>
<filter-name>AdminFilter</filter -name>
<filter-class>com.sikiedu.filter.AdminFilter</filter-class>
<!-- 继承自Filter的类-->
</filter>
<filter-mapping>
<filter-name>AdminFilter</filter-name>
<url-pattern>/admin/*</url-pattern>
<!-- 此处为路径，*是通配符，代表所有 -->
</filter-mapping>
```

#### 요청 필터링

> client가 jsp에 보낸 요청 유형을 필터링합니다.  
> ***이 요청은 get과 post를 뜻하는 것이 아니라 jsp에서 정의한 요청 유형을 뜻합니다.***

```xml
<filter>
<filter-name>DispatcherFilter</filter-name>
<filter-class>com.sikiedu.filter.DispatcherFilter</filter-class><!-- 继承自Filter的类-->
</filter>
<filter-mapping>
<filter-name>DispatcherFilter</filter-name>
<url-pattern>/dispatcher1. jsp</url-pattern>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
```

> dispatcher 유형은 모두 다섯 가지이며, 자주 사용하는 것은 앞의 네 가지입니다.
>
> > 1.  REQUEST 일반 요청
> > 2.  FORWARD 요청 포워딩
> > 3.  INCLUDE \<jsp:include>
> > 4.  ERROR 오류 요청
> > 5.  ASYNC 비동기 요청???
> >
> > #### 오류 페이지 설정

```xml
<error-page>
<error-code>404</error-code>
<location>/dispatcher1.jsp</location>
</error-page>
```

## 리스너

> 1.  리스너는 클래스이며, 클래스를 생성합니다
> 2.  리스너 인터페이스를 구현합니다
>
> > 생성 및 소멸 상태 리스닝  
> > ~initialized() ~Destroyed()
> >
> > > javax.servlet.ServletContextListener  
> > > HttpSessionListener  
> > > ServletRequestListener
> >
> > 속성 리스닝  
> > ~Added() ~Replaced() ~Removed()
> >
> > > ServletContextAttributeListener  
> > > HttpSessionAttributeListener  
> > > ServletRequestAttributeListener
> >
> > Session 바인딩 리스닝
> >
> > > 1.  model이 HttpSessionBindingListener를 implements하도록 합니다
> > > 2.  valueBound()와 valueunbound() 메서드를 재정의합니다

> 3.  설정

```xml
<listener>
<listener-class>package.Listen-name.class</listener-class>
</listener>
```

> 4.  session 타임아웃 시간 설정

```xml
<session-contig>
<session-timeout>1</session-timeout><!-- 单位为分钟-->
</session-config>
```

# 특수 지식 포인트

## MVC 아키텍처

![흐름도 2](https://cos2.endcloud.cn/legacy/halo/java-jsp-servlet/mermaid-2.svg)

## J2EE 계층형 아키텍처

![흐름도 3](https://cos2.endcloud.cn/legacy/halo/java-jsp-servlet/mermaid-3.svg)

## 싱글턴 패턴

> 생성자를 private으로 만들고 instance를 생성합니다.  
> 자주 쓰는 객체를 여러 번 new하는 것을 피합니다.

```java
public static JDBCUtil instance = new JDBCUtil();
private JDBCUtil() {

}
```

## 상대 경로와 절대 경로

#### 클라이언트 경로

> 클라이언트 주소 표시줄이나 소스 코드에 표시되며 요청할 수 있습니다.  
> 예: [및 접속 URL.](URL)

> 상대 경로
>
> > 현재 URL 디렉터리가 있는 경로를 기준으로 결정됩니다.
>
> 절대 경로
>
> > 호스트(도메인) 루트 경로를 기준으로 결정됩니다.  
> > ***일반적으로 contextPath를 붙여 경로를 올바르게 유지합니다.***  
> > <u>&lt;%=request.getContextPath()%&gt;</u>  
> > 또는<u>${pageContext.request.contextPath}</u>

#### 서버 측 경로

> jsp 내부에서만 실행됩니다.  
> 예: \<jsp:include page=“xxx.jsp”> 또는 요청 포워딩.

> 상대 경로
>
> > 현재 jsp 파일이 있는 경로를 기준으로 결정되며, "xxx.jsp"와 같은 형식입니다.
>
> 절대 경로
>
> > 프로젝트 경로를 기준으로 결정되며, "/folder/xxx.jsp"와 같은 형식입니다.  
> > ***프로젝트 이름을 붙일 필요가 없습니다.***

#### ***실제 사용 시에는 모두 <u>절대 경로</u>를 사용하여 오류를 피하는 것을 권장합니다.***

## 중국어 매개변수 깨짐 해결

> String 인코딩 설정

```java
System.out.println(new String(sex.getBytes("iso-8859-1"), "utf-8"));
```

> request 인코딩 설정

```java
request.setCharacterEncoding("utf-8");
```

> response 인코딩 설정

```java
resp.setContentType("text/html; charset=utf-8");
```

> ***궁극의 해결책, doFilter에서 전역 인코딩 설정***

```java
encoding = fConfig.getInitParameter("Encoding");
```

```xml
<!-- 在web.xml配置Encoding参数和filter-->
<filter>
<filter-name>EncodeFilter</filter-name>
<filter-class>com.sikiedu.filter.EncodeFilter</filter-class>
<init-param>
<param-name>Encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>EncodeFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
```

## 싱글 사인온

> 1.  sessionManager 클래스를 생성하고 session의 집합을 만듭니다(hashmap 구현).
> 2.  session-attribute의 added 리스너를 통해 제어합니다.

```java
if(arg0.getName().equals("user")) {
    User u = (User) arg0.getValue();
    //判断是否有其他客户端已经登录
    if(Sess ionManager . sess ionMppE containsKey(u. getUsername())) {
        //获得另外一一个客户端的session
        HttpSession session = SessionManager.sess ionMap. get(u.getUsername());
        //把登录信息从这个客户端抹除
        session. removeAttribute("user");
    }
    SessionManager.sessionMap.put(u.getUsername(), arg0.getSession());
}
```

## 맺음말

#### 다음 학습 단계

> 개인적으로는 SSM 프레임워크를 학습 방향으로 삼는 것을 권장하며, siki 학원에도 같은 과정이 있습니다.  
> SSH 프레임워크는 일부 측면에서 다소 뒤처져 있으므로 상황에 따라 고려하시기 바랍니다.

#### 취업을 원한다면

> 개인적으로는 SSM 프레임워크를 이해한 뒤 돌아가서 Java 기초를 다시 복습하는 것을 권장합니다.  
> 주로 《Java核心技术》 1권, 2권을 참고서로 삼습니다.  
> 동시에 자료구조와 알고리즘 관련 기초 지식도 학습해야 합니다.

## 연락처

#### GitHub

이 노트가 조금이나마 도움이 되었다면 Star를 눌러 주시면 감사하겠습니다.  
이 노트의 프로젝트 주소는 다음과 같습니다: [GitHub](https://github.com/endcloud/JavaWeb_learn_siki)  
앞으로도 이곳에 관련 코드와 노트를 계속 업데이트하겠습니다.

제가 배운 것이 아직 부족하므로, 이곳에 pr을 제출하여 제 오류를 바로잡아 주셔도 됩니다. 감사하겠습니다.

#### e-mail

또한 이메일로도 저와 연락하실 수 있습니다.  
제 이메일은 endcloud@qq.com입니다.
