HTTP는 stateless이다! 즉 연결이 끊기기 때문에 클라이언트가 바로 다음 것을 요청해도 서버는 그 이전의 클라이언트인지 아닌지 알 수 없다. Stateless가 아니라면 보통 최대 ~개의 클라이언트까지만 동시에 접속할 수 있다. Stateless기 때문에 훨씬 많은 요청과 응답 처리가 가능하다
기본 포맷은 헤더, 빈줄, 바디이다
GET 방식은 body가 비어있고 파라미터가 헤더에 붙어있는 것이 포인트이다.
render할 때 css들을 합치게 된다
head에는 부가적인 정보가 들어간다.
자바스크립트 코드는 일반적으로 바디 태그의 가장 밑에 있다. 방해가 될 수 있기 때문이다.
nginx가 성장하고 있는 것을 뚜렷이 볼 수 있다.
클라이언트의 로직이 많아지고 크기가 커진다는 단점이 있었다. 또한 보안도 좋지 않았다. 그래서 미들 웨어가 나왔다.
WAS의 중요한 기능
- WAS는 프로그램 실행환경과 데이터베이스 접속 기능 제공
- 여러 개의 트랜잭션 관리
- 비즈니스 로직 실행
이번 과정을 진행할 때 웹서버와 WAS 따로 두지 않는 이유는 톰캣이라는 WAS만으로 충분한 기능을 하기 때문이다.
웹서버 없이 동적 컨텐츠, 정적 컨텐츠 모두 제공이 가능하다. 그럼에도 불구하고 웹서버가 WAS 앞에 있으면 좋은 점이 있다. WAS에 오류가 생겨서 재시작할 때 웹 서버가 해당 WAS를 사용하짐 못하게하면 된다. 이를 장애 극복 기능이라 한다.
html layout tag
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<header>
<h1>Company Name</h1>
<img src="...." alt="logo">
</header>
<section>
<nav>
<li>Home</li>
<li>Home</li>
<li>About</li>
<li>Map</li>
</nav>
<section>
<button></button>
<div><img src="" alt=""></div>
<div><img src="" alt=""></div>
<div><img src="" alt=""></div>
<button></button>
</section>
<section>
<ul>
<li>
<h3>About us</h3></li>
<div>Bla blabla</div>
<li>
<h3>What we do</h3></li>
<div>Bla blabla</div>
<li>
<h3>What we do</h3></li>
<div>Bla blabla</div>
</ul>
</section>
</section>
<footer><span>Copyright @codesquad</span></footer>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<header>
<h1>Company Name</h1>
<img src="...." alt="logo">
</header>
<section id = "nav-section">
<nav>
<li>Home</li>
<li>Home</li>
<li>About</li>
<li>Map</li>
</nav>
<section id="roll-section">
<button></button>
<div><img src="" alt=""></div>
<div><img src="" alt=""></div>
<div><img src="" alt=""></div>
<button></button>
</section>
<section>
<ul>
<li class="our_description">
<h3>About us</h3></li>
<div>Bla blabla</div>
<li class="our_description">
<h3>What we do</h3></li>
<div>Bla blabla</div>
<li class="our_description">
<h3>What we do</h3></li>
<div>Bla blabla</div>
</ul>
</section>
</section>
<footer><span>Copyright @codesquad</span></footer>
</body>
inline
최우선권을 가진다. 구조와 선언이 섞여있으므로 유지보수가 어렵다.
internal
external
외부의 파일 하나만 관라히면 되므로 효율적이다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
body > div {
color: red;
font-size : 30px;
border:2px solid slategray;
padding: 30px;
}
div ul li div p {
color: green;
}
</style>
</head>
<body>
<div>
<span>my text is upper</span>
<ul>
<li>
<span>my text is dummy</span>
<div>
<p>Lorem ipsum ~~~ssdsdsaasasdf</p>
</div>
</li>
<li></li>
</ul>
</div>
</body>
</html>
구체적인것을 우선으로 적용한다
HTML의 요소를 tag, id, class, html 태그 속성등을 통해 쉽게 찾아주는 방법
같은 아이디가 여러개 있을 때, 자바스크립트에서는 제일 위 하나만 찾아지지만 css는 다 찾아서 적용한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
<style>
body > div {
font-size: 32px;
background-color: #ff0;
font-family: monospace;
}
.myspan {
color: #f00;
font-size: 2em;
}
</style>
</head>
<body>
<div>
<span class="myspan">My text is upper</span>
</div>
</body>
</html>
em은 상속받은 기본 값의 몇배를 의미한다. 여기에서는 div의 기본 값이 32px이므로 2em을 하면 64px가 된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div>div1</div>
<div>div2</div>
<div>div3</div>
</body>
</html>
div {
width: 100px;
height: 100px;
border: 1px solid gray;
}
div {
width: 100px;
height: 100px;
border: 1px solid gray;
display: inline;
}
inline 속성을 주면 오른쪽으로 배치가 된다.
오른쪽으로 흐르다가 꽉차만 아래로 내려간다.
<div>
<span>나는 어떻게 배치되나요?</span>
<span>좌우로 배치되는군요</span>
<a>링크는요?</a>
<strong>링크도 강조도 모두 좌우로 흐르는군요</strong>
모두다 display속성이 inline인 엘리먼트이기 때문입니다.
</div>
span, a, strong 모두 inline 태그다.
상위 엘리먼트 중 static이 아닌 것이 기준점이다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="wrap">
<div class="static">static(default)</div>
<div class="relative">relative(left:10px)</div>
<div class="absolute">absolute(left:130px;top:30px)</div>
<div class="fixed">fixed(top:250px)</div>
</div>
</body>
</html>
css
.wrap {
position: relative;
}
.wrap > div {
width: 150px;
height: 100px;
border:1px solid gray;
font-size: 0.7em;
text-align:center;
line-height:100px;
}
.relative {
position:relative;
left:10px;
}
.absolute {
position:absolute;
left:130px;
top:30px;
}
.fixed {
position: fixed;
top: 250px;
}
absolute는 top과 left를 0이라도 꼭 주는 것이 좋다.
absolute의 위치가 저기인 이유는 absolute의 기준점은 상위 엘리먼트의 static이 아닌 것이다. 현재 absolute의 상위는 "wrap"클래스인데 그 클래스는 static이 아닌 relative이므로 기준점이 된다.
relative는 원래 자기가 있을 자리를 기준으로 이동한다.
fixed는 바디를 기준으로 변경되는 것이다. 스크롤을 내려고 그대로 된다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div>left</div>
<div class="bottom">bottom</div>
</body>
</html>
css
* {
border:1px solid gray;
}
.bottom {
margin-top : 10px;
margin-left: 20px;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<div class="blue"></div>
<div class="green"></div>
<div class="red"></div>
</body>
</html>
css
div {
width: 100px; height: 100px;
border:1px solid gray;
font-size: 0.7em;
}
.blue {
background-color:blue;
}
.green {
float:left;
background-color:green;
margin-left:40px;
}
.red {
background-color:red;
}
green은 float가 되어 떠다니게되고, 그 자리를 red가 밑에서 올라와서 채운다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<header>부스트코스는 정말 유익합니다</header>
<div id="wrap">
<nav class="left">
<ul>
<li>menu</li>
<li>home</li>
<li>name</li>
</ul>
</nav>
<div class="right"><h2>반가워요!</h2>
<ul>
<li>crong</li>
<li>jk</li>
<li>honux</li>
<li>pobi</li>
</ul>
</div>
</div>
<footer>코드스쿼드(주)</footer>
</body>
</html>
css
header {
background-color: #eee;
}
#wrap {
background-color: #ccc;
}
.left, .right {
float:left;
}
footer {
background-color: #eee;
}
left와 right가 float이니 footer가 밀고 올라와버렸다. float에게 위의 float을 밀지 않게 css를 변경해주자
footer {
background-color: #eee;
clear: left;
}
상위 박스의 float을 인지하고 올라가지 않는다.
css
header {
background-color: #eee;
}
#wrap {
background-color: #ccc;
}
.left, .right {
float:left;
}
.left {
width: 20%;
}
.right {
width: 80%;
text-align: center;
}
footer {
background-color: #eee;
clear: left;
}
li {
list-style: none;
}
css를 고쳐줬지만, 배경 색깔이 없어졌다.
자식이 float인 경우에는 떠있기 때문에 자식으로 생각하지 않는다.
css
#wrap {
background-color: #ccc;
overflow: auto;
}
자식을 overflow줘서 인지하므로 색깔이 나온다.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>JS Bin</title>
</head>
<body>
<header>부스트코스는 정말 유익합니다</header>
<div id="wrap">
<nav class="left">
<ul>
<li>menu</li>
<li>home</li>
<li>name</li>
</ul>
</nav>
<div class="right">
<h2>
<span>반가워요!</span>
<div class="emoticon">:-)</div>
</h2>
<ul>
<li>crong</li>
<li>jk</li>
<li>honux</li>
<li>pobi</li>
</ul>
</div>
<div class="realright">
oh~ right
</div>
</div>
<footer>코드스쿼드(주)</footer>
</body>
</html>
css
li {
list-style:none;
}
header {
background-color : #eee;
}
#wrap {
overflow:auto;
margin:20px 0px;
}
.left, .right, .realright {
float:left;
height: 200px;
}
.left {
width:17%;
margin-right:3%;
background-color : #47c;
}
.right {
width : 60%;
text-align:center;
background-color : #47c;
}
.realright {
width: 17%;
margin-left:3%;
background-color : #67c;
}
.right > h2 {
position:relative;
}
.right .emoticon {
position:absolute;
top:0px;
right:5%;
color:#fff;
}
footer {
background-color : #eee;
}
new -> project -> web -> Dynamic Web Project
project name: firstweb
Target runtime: Tomcat v8.5 (next후 tomcat 설치된 경로 설정해주기)
new -> servlet
java package: examples
class Name: HelloServlet
http://localhost:8080/{프로젝트이름}/{URL Mapping값}
HelloServlet
@WebServlet("/HelloServlet")
public class HelloServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public HelloServlet() {
super();
// TODO Auto-generated constructor stub
}
/**
* @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
*/
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<h1>Hello World</h1>");
}
}
dynamic web module version이 서블릿 버전이다.
TenServlet
package exam;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Servlet implementation class TenServlet
*/
@WebServlet("/ten")
public class TenServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
/**
* @see HttpServlet#HttpServlet()
*/
public TenServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("<h1>1-10까지 출력!!<h1>");
for (int i = 1; i <= 10; i++) {
out.print(i + "<br>");
}
out.close();
}
}
doGet에서 함수 파라미터로 request 와 response가 있다. 클라이언트는 요청을 받아내는 객체와 응답을 위한 객체를 자동으로 생성해서 가지고 있다.
out.println()이든 out.print()이든 상관없다. 어짜피 html이므로 <br> 태그를 넣어주지 않으면 줄바꿈은 되지 않는다.
위의 애노테이션에 값을 바꾸면 url이 바뀌는 것이다.
<?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_2_5.xsd" id="WebApp_ID" version="2.5">
...
<servlet>
<description></description>
<display-name>TenServlet</display-name>
<servlet-name>TenServlet</servlet-name>
<servlet-class>exam.TenServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>TenServlet</servlet-name>
<url-pattern>/ten</url-pattern>
</servlet-mapping>
</web-app>
url로 요청이오면 servlet-mapping에 해당 url-pattern을 찾고, 그 servlt-name을 찾는다. servlet-name으로 위의 등록된 servlet들에서 클래스를 찾는다.
LifecycleServlet
package examples;
import java.io.IOException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/LifecycleServlet")
public class LifecycleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LifecycleServlet() {
System.out.println("LifecycleServlet 생성!!");
}
public void init(ServletConfig config) throws ServletException {
System.out.println("init 호출!!");
}
public void destroy() {
System.out.println("destroy 호출!!");
}
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println("service 호출!!");
}
}
URL로 요청이오면 해당 서블릿이 메모리에 있는지 확인한다. 만약 메모리에 없으면 생성한다. 한번 생성된 이후에는 다른 창에서 요청을 해도 생성하지 않고 service만 호출하는 것을 알 수 있다. 만약 코드에 변경을 하고 서버를 재시작하면 다시 생성자부터 호출된다.
7월 13, 2021 8:02:18 오후 org.apache.coyote.AbstractProtocol start
정보: 프로토콜 핸들러 ["http-nio-8080"]을(를) 시작합니다.
7월 13, 2021 8:02:18 오후 org.apache.catalina.startup.Catalina start
정보: Server startup in 642 ms
LifecycleServlet 생성!!
init 호출!!
service 호출!!
service 호출!!
LifecycleServlet
package examples;
import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/LifecycleServlet")
public class LifecycleServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public LifecycleServlet() {
System.out.println("LifecycleServlet 생성!!");
}
public void init(ServletConfig config) throws ServletException {
System.out.println("init 호출!!");
}
public void destroy() {
System.out.println("destroy 호출!!");
}
// protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// System.out.println("service 호출!!");
//}
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>form</title></head>");
out.println("<body>");
out.println("<form method='post' action='/firstweb/LifecycleServlet'>");
out.println("name : <input type='text' name='name'><br>");
out.println("<input type='submit' value='ok'><br>");
out.println("</form>");
out.println("</body>");
out.println("</html>");
out.close();
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
String name = request.getParameter("name");
out.println("<h1> hello " + name + "</h1>");
out.close();
}
}
URL을 직접 입력하거나 링크를 클릭하는 것은 GET 방식으로 요청하는 것이다. 그래서 doGet() 메서드가 실행되어서 아래 페이지가 보여진다.
HTML을 뜯어보면 post 방식으로 마찬가지 URL에 요청을 보내는 것을 알 수 있다. 그러면 doPost()가 반응을 한다. doPost()에서는 넘어온 인자를 받아서 출력한다.
HeaderServlet
@WebServlet("/header")
public class HeaderServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public HeaderServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>form</title></head>");
out.println("<body>");
Enumeration<String> headerNames = request.getHeaderNames();
while(headerNames.hasMoreElements()) {
String headerName = headerNames.nextElement();
String headerValue = request.getHeader(headerName);
out.println(headerName + " : " + headerValue + " <br> ");
}
out.println("</body>");
out.println("</html>");
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doGet(request, response);
}
}
Get메소드에서 request에 담긴 정보들을 다 출력해보고있다.
ParameterServlet
@WebServlet("/param")
public class ParameterServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public ParameterServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>form</title></head>");
out.println("<body>");
String name = request.getParameter("name");
String age = request.getParameter("age");
out.println("name: " + name);
out.println("age: " + age);
out.println("</body>");
out.println("</html>");
}
}
InfoServlet
@WebServlet("/info")
public class InfoServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
public InfoServlet() {
super();
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.setContentType("text/html");
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<head><title>info</title></head>");
out.println("<body>");
String uri = request.getRequestURI();
StringBuffer url = request.getRequestURL();
String contentPath = request.getContextPath();
String remoteAddr = request.getRemoteAddr();
out.println("uri : " + uri + "<br>");
out.println("url : " + url + "<br>");
out.println("contentPath : " + contentPath + "<br>");
out.println("remoteAddr : " + remoteAddr + "<br>");
out.println("</body>");
out.println("</html>");
}
}
URL은 인터네에서 자원의 주소이고 uri는 해당 서버에서 자원의 주소다.
WAS내에 어플리케이션 서버가 여러 개일 수 있는데 그 서버를 찾아가는데 contentPath가 사용된다.