2023. 10. 13 (금) / Day 90
동적: 정해지지 않고 그때 그때 만들 수 있는것
보통 클래스는 메소드들을 실행시키고 객체를 관리함
Bean 클래스는 정해진 필드들을 위한 정리한 클래스이다. 옛날에는 VO라고 했는 데 요즘에는 DTO라고 함
DTO( Data Transfer Object) -> 전달인자를 클래스로 묶어서 클래스로 보내는 것 옮겨가는 것
VO (Value Object) -> 변수들 체계적으로 관리하기 위한 것 필드만 보면된다.
DTO와 VO는 구분하지 않음.
javaBean이라고도 함
(java - servlet)
package com.saeyan.javabeans;
public class MemberBean {
private String name;
private String UserId;
private String nickname;// private String nickname = null; 이렇게 하는 사람도 있다.
private String pwd;
private String email;
private String phone;
//
public MemberBean() {
System.out.println("MemberBean 생성자 실행");
}
// (자동완성: 빈곳에 마우스오른쪽버튼 → souce → getter/setter)
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUserId() {
return UserId;
}
public void setUserId(String userId) {
UserId = userId;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this.nickname = nickname;
}
public String getPwd() {
return pwd;
}
public void setPwd(String pwd) {
this.pwd = pwd;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
// getter만들기
// String getName() {
// return this.name;
// }
//
// setter만들기
// void setName(String name) {
// this.name = name;
// }
}
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
//<%--id에 선언한 이름으로 java 변수와 scope의 키값을 생성한다.--%>
<jsp:useBean id = "member" class="com.saeyan.javabeans.MemberBean"/>
<%String name = member.getName();// 밑에 <%=member.getName() 이것과 같은 것이다.
String param_name = request.getParameter("name");
%>
<%=member.getName() %>
<hr>
<%-- <jsp:setProperty name="member" property="name" value="아메리카노"/>--%>
<jsp:setProperty name="member" property="*"/>
<jsp:getProperty name="member" property="name" />
<jsp:getProperty name="member" property="nickname" />
</body>
</html>
jsp
<%@page import="java.util.ArrayList"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<div>
\${5+2 } : ${5+2 }<br><%= 5+2 %>
\${"안녕?" } : ${"안녕?" }<br>
\${"10" + 1 } : ${"10" + 1 }<br>
<%-- +연산은 숫자로 변형해서 한다 --%>
<%-- \${"안녕" + 1 } : ${"안녕" + 1 }<br> --%>
<%-- ${"안녕" + "하세요" }<br> --%> <%= "안녕" + "하세요" %><br>
\${ 100/9 } : ${ 100/9 }<br>
\${ 100 div 9 } : ${ 100 div 9 }<br>
\${ 100 % 9 } : ${ 100 % 9 }<br>
\${ 100 mod 9 } : ${ 100 mod 9 }<br>
<hr>
\${10 == 10 } : ${10 == 10 }<br>
\${10 eq 10 } : ${10 eq 10 }<br>
\${"a" eq "b" } : ${"a" eq "b" }<br>
<br>
\${10 != 10 } : ${10 != 10 }<br>
\${10 ne 10 } : ${10 ne 10 }<br>
<br>
\${10 < 10 } : ${10 < 10 }<br>
\${10 lt 10 } : ${10 lt 10 }<br>
<br>
\${10 <= 10 } : ${10 <= 10 }<br>
\${10 le 10 } : ${10 le 10 }<br>
<br>
\${10 > 10 } : ${10 > 10 }<br>
\${10 gt 10 } : ${10 gt 10 }<br>
<br>
\${10 >= 10 } : ${10 >= 10 }<br>
\${10 ge 10 } : ${10 ge 10 }<br>
<br>
\${ (10 > 10) eq "false" } : ${(10 > 10) eq "false" }<br>
<br>
\${ !(20 == 10) } : ${ !(20 == 10) }<br>
\${ not(20 eq 10) } : ${ not(20 eq 10) }<br>
</div>
<br>
<%
String a = null;
String b = "";
String c = "c";
request.setAttribute("a1", a);
request.setAttribute("b1", b);
request.setAttribute("c1",c);
%>
c: [${c }] 그냥 java 변수는 el로 출력할 수 없다 <br>
c1: [${c1 }] el태그는 scope영역의 값을 바로 출력가능 <br><br>
\${empty al } : ${empty al } >> true<br>
\${empty bl } : ${empty bl } >> true<br>
\${empty cl } : ${empty cl } >> false<br><br>
<%
//List list = new ArrayList();
%>
<jsp:useBean id="list2" class="java.util.ArrayList" scope="page" />
\${empty list2 } : ${empty list2 }
</body>
</html>
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String id = request.getParameter("id");
//out.print("request.getParameter id : " + id + "<br>");
%>
<!-- 이것을 축약해서-->
request.getParmater id : <%= id %><br>
request.getParmater id : <%= request.getParameter("id") %><br>
request.getParmater id : <%= request.getParameterValues("id") %><br>
<!-- 이렇게 사용할 수 있다.-->
<hr>
el parm id : ${param.id } <br>
el parm ["id"] : ${param["id"] } <br>
<hr>
el parma.id : ${paramValues.id }<br>
el parma.id : ${paramValues.id[0] }<br>
el parma.id : ${paramValues.id[1] }<br>
el parma.id : ${paramValues["id"] [1]}<br>
</body>
</html>
결과 ↑
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%
pageContext.setAttribute("name","page name");
request.setAttribute("name","request name");
session.setAttribute("name", "session name");
application.setAttribute("name","application name");
%>
name : ${ name} <hr>
page 속성 : ${ pageScope.name} <br>
request 속성 : ${requestScope.name} <br>
session 속성 : ${session.name} <br>
application 속성 : ${application.name} <br>
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<jsp:useBean id = "member" class="com.saeyan.javabeans.MemberBean"/>
<%
member.setName("이름");
%>
member.getName(): <%=member.getName() %> <br>
member.name : ${member.name }
</body>
</html>
CSR (Client Side Rendering)
: 일단 껍데기라도 보여줄 수 있다.
렌더링이 클라이언트 쪽에서 일어납니다. 즉, 서버는 요청을 받으면 클라이언트에 HTML과 JS를 보내주고, 클라이언트는 그것을 받아 렌더링을 시작합니다. 서버가 HTML 파일을 줄 때, 렌더가 준비가 된 파일이 아니기 때문입니다. 즉, HTML 파일 안에는 아무런 내용이 없다는 것입니다. 그 내용은 JS 파일을 받아 실행을 시켜야 그제서야 만들어지는 것입니다.
출처: The Benefits of Server Side Rendering Over Client Side Rendering
CSR(Client Side Rendering)은 위의 그림과 같이 2단계에서 바로 볼 수 없습니다. 마지막 4단계에서 볼 수 있으며, 상호작용 할 수 있는 것입니다.
그 이유는 서버가 HTML 파일을 줄 때, 렌더가 준비가 된 파일이 아니기 때문입니다. 즉, HTML 파일 안에는 아무런 내용이 없다는 것입니다. 그 내용은 JS 파일을 받아 실행을 시켜야 그제서야 만들어지는 것입니다.
React를 써보신 분은 알겠지만, React.createElement라는 메서드를 사용해보셨을 거라 생각합니다. 이는document.createElement와 마찬가지로 JS에서 HTML 태그를 생성하는 것입니다. 이 때에 태그가 렌더링 될 수 있기 때문에 SSR과의 뚜렷한 차이를 보이는 것입니다.
그리고 특히, index.html 파일의 바디 태그 안에 <div id="root"></div>와 같이 div 태그 하나만 덩그러니 있고 아무런 내용이 없는 것을 많이 보셨을 거라 생각합니다. 이렇게 아무것도 없는 상태로 전달되므로 유저는 아무것도 볼 수 없습니다.
ReactDOM.render(<App />, document.getElementById('root'));
그러나 이후, 브라우저가 추가적으로 JS 파일을 다운받고 실행하면 그때 되어 index.js에서 위와 같이 root 태그를 화면에 렌더링, 그려주게 되는 것입니다.
반면에 SSR은 index.html 파일 내에 화면에 그려내는 코드들이 이미 작성되어 있기 때문에 CSR과 달리 페이지가 2단계에서 Viewable할 수 있는 것입니다.
SSR(Server Side Reafering)
: 한번에 모든 데이터를 표시할 수 있다. 초기에 시간이 걸릴 수 있다.
서버쪽에서 렌더링을 한다라는 뜻입니다. 그렇다면 여기서 '렌더링'을 한다는 것은 무슨 의미일까요? 서버에서 렌더 될 준비를 끝마친 상태로 HTML 응답을 브라우저(클라이언트)에 보내는 것입니다. 그 의미가 바로 렌더링이라는 의미
여기서 짚고 넘어가야할 부분은 브라우저의 렌더링입니다. 브라우저에서 말하는 렌더링의 의미는 HTML, CSS, JavaScript 파일을 받아와 이를 읽고 파싱해서 실행한 결과물로 화면에 그려내는 과정입니다. 그러나 서버 사이드 렌더링에 있는 렌더링의 뜻은 이와 좀 다릅니다.
서버 사이드 렌더링에서 의미를 따지자면, HTML 파일 내에 내용이 있느냐 없느냐입니다. 내용이 있다면, 렌더링이 된 것입니다.
이렇게 HTML 파일 내에 내용이 모두 있으므로 브라우저는 바로 페이지를 렌더링합니다. 그리고 사용자에게 바로 보여지는 것입니다. 이후 브라우저는 자바스크립트 파일을 다운 받습니다. 이렇게 브라우저가 해당 파일을 실행시키면, 페이지의 상호작용이 가능해집니다.
우리가 기억해야할 부분은 페이지가 보여지는 것은 2단계에서 가능했다는 것입니다. 이 점이 바로 설명하게 될 CSR과의 가장 큰 차이점입니다.
물론, JS 파일은 읽히기 전이므로 이를 다운로드 받아오면서 유저는 컨텐츠를 볼 수 잇지만, 사이트를 조작할 수는 없습니다. 이 때의 사용자 조작을 기억하고 있게 됩니다. JS까지 성공적으로 컴파일 되었다면, 기억하고 있던 사용자 조작이 실행되고, 이제 웹페이지는 상호작용이 가능해집니다.
1. SSR(Server Side Rendering)
사실 전통적인 SSR 방식의 이해는 크게 어렵지가 않다. SPA가 등장하기 전엔 대부분의 웹 사이트는 MPA 방식으로 운영되었고, (나이대에 따라 다르겠지만) 우리는 기본적으로 이러한 방식의 웹 사이트들을 어렸을 적 경험해 보았기 때문이다. SSR의 기본적인 사이클은 아래 사진을 참고하자. 서버에서 요청한 HTML파일을 렌더링을 마친 상태로 응답하기에 로딩시간이 상대적으로 짧다는 것을 볼 수 있다. (위 사례는 전통적인 SSR, 즉 고전방식의 SSR 방식에서 그러하다. 여기서 전통적인 SSR이라 함은 정적페이지만 서버측에서 렌더링해주는 것으로 이해할 수 있을 듯 하다.)
따라서 SSR 방식의 장점은 다음과 같은 것이 있다.
- 첫 페이지 로딩 시간이 CSR 방식과 비교해 매우 짧다. (하지만 그림에서 보듯이 별도의 JS 파일 등을 다운받아 적용하기까지는 시간이 좀 더 소요되어 사용자의 인터랙션에 정상적인 반응을 보일때까지 기다리는 시간이 어느정도 발생할 수 있다)
- 이미 렌더링 된 HTML 문서가 전달되므로 SEO(Search Engine Optimazation)이 CSR 방식에 비해 적용하기 더 우수하다.
- 사용자 정보를 서버측 세션으로 관리하기 용이하므로 CSR 방식에 비해 보안이 우수하다.
반면 단점으로는 각 페이지별로 매번 로딩시간 및 새로고침 현상이 발생한다는 점은 UX및 UI에 심각한 영향을 초래할 수 있다. 또한 서버에서 렌더링을 마친다는 것은 서버가 담당하는 일이 더욱 많아지는 것이므로 부하에 걸릴 위험도 존재한다고 한다.
2. CSR(Client Side Rendering)
그렇다면 SPA 개념과 등장한 CSR 방식의 작동원리를 보자. 하나의 페이지에서 여러 페이지를 보여준다는 것은 결국엔 자바스크립트를 이용해서 페이지의 일부분이나 전체를 갈아치우는 것으로 생각해볼 수 있다. 리액트 라이브러리를 이용해 링크 이동과 같은 기능울 내부적으로 구현 시 Router를 설치하여 사용하지만 결국 이러한 파일(jsx 및 js)들은 (CRA 환경 이라면) Webpack과 같은 번들링 도구를 거쳐 하나의 (또는 여러개의 chunk파일로) 거대한 js파일로 번들링되게 될 것이다. SPA에서는 이처럼 번들링 된 js를 전달받아 Single Page Application을 구축하게 되는 것이다.
즉 이 말은 CSR 방식에서는 이 번들링이 완료된 js 파일을 모두 로드하기 전에는 첫 페이지를 로드할 수가 없다. 엄연히 말해서 첫 페이지는 이미 로드가 되었지만, 로드된 페이지는 빈 HTML 파일이다. 실제로 npx create-react-app ... 실행 후 public/index.html 파일을 확인해보면 다음과 같이 구성되어 있다.
...
<div id='app'></div>
...
즉 유저는 로딩이 완료되기까지 그저 빈 화면을 보고 있을 수 밖에 없다. 또한 첫 페이지가 위와 같은 빈 화면이라는 말은 검색 엔진이 해당 문서를 바라볼 때 기입된 내용이 없기 때문에 SEO 최적화에도 많은 어려움이 따른다. (또한 CSR에서는 meta tag 수정 등의 어려움 등도 존재하기에 더욱 어렵다) 물론 Code Splitting 등의 기법으로 로딩 시간을 줄일 수 있는 기법들이 있지만 이번 포스팅에서는 생략하고 본론에 다시 집중하도록 하자.
그럼에도 CSR 방식은 다음과 같은 장점이 있다.
- 초기 로딩 속도를 제외하면 나머지 부분은 매우 빠른 사용자 인터랙션 속도를 보여준다. 이미 다운받은 번들링 된 js 파일에 렌더링에 필요한 모든 로직이 들어있기 때문.
- 따라서 새로고침이나 화면 깜빡임등이 (개발자가 의도한 상황이 아닌 이상) 발생하지 않는다. 이는 UX에 엄청난 이점을 가져다 준다.
- 서버가 클라이언트 뷰(View)단에서 처리할 일을 더이상 신경쓰지 않아도 된다.
태그 라이브러리
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:out value="<h1>Hello World</h1>"/>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
String m ="abc123";
request.setAttribute("m", m);
%>
m : ${ m} <br>
<c:set var="msg" value="abcd" />
msg : ${msg }
<c:set var="msg2" value="<%= m %>" />
<c:set var="msg3" value="${ m } " />
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<br>
<h1>c:if</h1>
<c:if test="${param.color != -1 }">
<c:if test="${param.color == 1 }">
<div style="height:100px; background: red; color: white;">
빨강
</div>
</c:if>
<c:if test="${param.color == 2 }">
<div style="height:100px; background: #00ff00; color: black;">
초록
</div>
</c:if>
<c:if test="${param.color == 3 }">
<div style="height:100px; background: #00f; color: white;">
파랑
</div>
</c:if>
</c:if>
<c:if test="${ !(param.color != -1) }">
색을 선택하세요<br>
</c:if>
<hr>
<h1>c:choose</h1>
<c:choose>
<c:when test="${ param.color eq 1 or param.color eq 3 }">
<div style="height:100px; background: #f0f; color: white;">
빨강 또는 파랑
</div>
</c:when>
<c:otherwise>
<div style="height:100px; background: #00ff00; color: black;">
초록
</div>
</c:otherwise>
</c:choose>
<a href="12_colorSelectFrom.jsp">이동 : 12_colorSelectFrom.jsp </a>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<c:if test="${param.color == 1 }">
<div style="height:100px; background: red; color: white;">빨강</div>
</c:if>
<c:if test="${param.color == 2 }">
<div style="height:100px; background: #00ff00; color: black;">초록</div>
</c:if>
<c:if test="${param.color == 3 }">
<div style="height:100px; background: #00f; color: white;">파랑</div>
</c:if>
</body>
</html>