(1) JSP 예제

<%@page import="java.util.Calendar"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<%
// 자바를 짜는 영역임
	Calendar now = Calendar.getInstance();
	String s = String.format("%tF %tA %tT", now, now, now);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h3>JSP 첫 번째 - 예제</h3>

<p>
	지금 시간은 <span style="color: tomato;"> <%= s %> </span> 입니다.
</p>

</body>
</html>

 

(2) Servlet 예제

<%@ 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>

<h3>서블릿 예제 - 파라미터 전달 예</h3>

<p>
	<a href="/study2/test?name=Lee&age=19">확인</a>
</p>
<hr>

<form action="/study2/test" method="post">
	<p> 이름 : <input type="text" name="name"></p>
	<p> 나이 : <input type="text" name="age"></p>
	<p>
		<button type="submit">확인</button>
	</p>
</form>

</body>
</html>
package com.test;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

// web.xml 이 선택사항인 이유는 annotation을 이용할 수 있기 때문이다.
@WebServlet("/test") // 클라이언트가 주소줄에 test라고 요청하면, 의 의미이다.
public class TestServlet extends HttpServlet {
	private static final long serialVersionUID = 1L;

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 클라이언트가 GET 방식으로 요청한 경우 실행
		// GET : 기본 요청방식으로 주소줄에 파라미터를 전달, 보안에 취약
		
		try {
			// 클라이언트가 보낸 파라미터를 받는다.
			String name = req.getParameter("name");
			int age = Integer.parseInt(req.getParameter("age"));
			
			// 처리
			String state = age >= 19 ? "성인" : "미성년자";

			// 처리 결과를 클라이언트에게 전송 한다.
			resp.setContentType("text/html; charset=utf-8");

			PrintWriter out = resp.getWriter();
			out.println("<html>");
			out.println("<head><title>servlet 예제</title></head>");
			out.println("<body>");
			out.println("<h3> GET방식으로 요청한 처리 결과 </h3>");
			out.println("<p>" + name + "님의 나이가 " + age + "이므로 <b>" + state + "</b>입니다.</p>");
			out.println("</body>");
			out.println("</html>");

		} catch (Exception e) {
			getServletContext().log("error!!", e);
		}
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// 클라이언트가 POST 방식으로 요청한 경우 실행
		// POST : <form method="post" action ... ></form> 을 통해서 요청
		// 		  body 부분에 정보를 보냄
		
		try {
			// 요청한 정보의 문자 인코딩 설정. 이 줄을 생략하면 한글이 깨짐.
			req.setCharacterEncoding("utf-8");
			
			// 클라이언트가 보낸 파라미터를 받는다.
			String name = req.getParameter("name");
			int age = Integer.parseInt(req.getParameter("age"));
			
			// 처리
			String state = age >= 19 ? "성인" : "미성년자";

			// 처리 결과를 클라이언트에게 전송 한다.
			resp.setContentType("text/html; charset=utf-8");

			PrintWriter out = resp.getWriter();
			out.println("<html>");
			out.println("<head><title>servlet 예제</title></head>");
			out.println("<body>");
			out.println("<h3> POST방식으로 요청한 처리 결과 </h3>");
			out.println("<p>" + name + "님의 나이가 " + age + "이므로 <b>" + state + "</b>입니다.</p>");
			out.println("</body>");
			out.println("</html>");

		} catch (Exception e) {
			getServletContext().log("error...", e);
		}
		
	}

}

 

서블릿 이란?

- 서버에서 웹 페이지 등을 동적으로 생성하거나 데이터 처리를 수행하기 위해 자바(Java)로 작성된 프로그램

- 자바 서블릿은 서버 측 기능을 확장시킨 자바 프로그램으로, 자바EE(JavaEE, Java Platform Enterprise Edition)의 한 기능이다.

- 서블릿은 javax.servlet.GenericServlet클래스를 상속받아 작성하거나, HTTP protocol 서비스를 지원하는 javax.servlet.http.HttpServlet 클래스를 상속받아 작성한다.

- 서블릿은 Servlet Container에 의해서 실행되고, 관리된다.

- 서블릿은 자바 코드 안에 HTML을 포함하고 있어서 그 효율성이 떨어진다. HTML 변경 시 서블릿을 재 컴파일해서 배포해야 한다.

 

Servlet Container

- HTTP 요청을 받아서 Servlet을 실행시키고, 그 결과를 사용자 브라우저에게 전달해주는 기능을 제공한다.

- Servlet을 실행하고 생명주기를 관리하는 역할을 한다.

- 멀티 스레딩을 지원하여 클라이언트의 다중 요청을 스레드를 이용하여 처리한다. 서블릿 컨테이너는 해당 서블릿의 요청이 들어오면 스레드를 생성해서 작업을 수행한다.

 

Servlet의 Life Cycle

- Servlet은 init(), service(), destroy()의 세 개의 메소드에 의한 생명주기를 갖는다.

- 클라이언트가 Servlet을 요청하는 경우 다음의 단계를 실행한다.

1) 해당 서블릿의 인스턴스가 존재하지 않는 경우

(1) Servlet 클래스를 로드하여 서블릿 클래스의 인스턴스를 생성한다.

(2) init() 메소드를 호출하여 서블릿 인스턴스를 초기화한다.

(3) 해당 서블릿의 인스턴스가 존재하는 경우에는 (1), (2)번의 과정은 실행하지 않는다.

2) request와 response 객체를 인수로 전달하여 service() 메소드를 호출, 클라이언트의 요청을 처리하여 처리 결과를 전송한다.

- service() 메소드는 클라이언트의 요청이 있을 때마다 반복적으로 호출하여 클라이언트 요청을 처리한다.

- 클라이언트가 서블릿을 요청하면 컨테이너는 스레드를 생성하여 병행적으로 service() 메소드를 호출된다.

- 서블릿을 javax.servlet.HttpServlet 클래스를 상속 받아 작성했다면 service() 메소드는 클라이언트의 요청방식에 따라 GET 방식이면 doGet()메소드를, POST 방식이면 doPost() 를 호출한다.

3) 서블릿을 제거해야 하는 경우 컨테이너는 서블릿의 destroy()메소드를 실행하고, 서블릿을 종료한다. 일반적으로 데이터베이스 연결 해제, 백그라운드 스레드 중지 등 사용한 자원을 종료한다.

웹 어플리케이션 ?

웹 브라우저의 요청에 대하여 처리해서 결과를 보여주는 프로그램을 의미한다.

 

웹 어플리케이션 구성요소

1) 웹 브라우저 : 사용자에게 화면(User Interface)을 제공한다.

2) 웹 서버 : HTTP를 통해 웹 브라우저와 같은 클라이언트에서 요청하는 HTML 문서나 CSS, JavaScript, 오브젝트(image 등) 등의 웹 페이지를 전송해주는 서비스 프로그램

3) WAS ( Web Application Server) : 인터넷 상에서 HTTP를 통해 사용자 컴퓨터나 장치에 애플리케이션을 수행해 주는 미들웨어(소프트웨어 엔진)로, Server 단에서 Application을 동작할 수 있도록 지원한다.

4) 데이터베이스 : 웹 어플리케이션이 필요로 하는 데이터를 저장한다.

 

웹 어플리케이션 종류

1) CGI(Common Gateway Interface) 

2) ASP (Active Server Page)와 ASP.NET

3) PHP (Hypertext Preprocessor)

4) Servlet

- 서버에서 웹 페이지 등을 동적으로 생성하거나 데이터 처리를 수행하기 위해 자바(Java)로 작성된 프로그램

- 자바 서블릿은 서버 측 기능을 확장시킨 자바 프로그램으로, 자바 EE(JavaEE, Java Platform Enterprise Edition)의 한 기능이다.

- 서블릿은 자바 코드 안에 HTML을 포함하고 있어서 그 효율성이 떨어진다.

5) JSP(Java Server Pages)

- JSP는 HTML내에 자바 코드를 삽입하여 웹 서버에서 동적으로 웹 페이지를 생성하여 웹 브라우저에 돌려주는 언어이다.

- JavaEE 스펙 중 일부로 웹 애플리케이션 서버에서 동작한다.

 

HTTP(HyperText Transfer Protocol)

1) 개요

- 인터넷에서 하이퍼텍스트(hypertext) 문서를 교환하기 위해 사용되는 통신규약.

- HTTP는 TCP/IP 위에서 작동하며, 서버/클라이언트 모델을 따른다. 클라이언트에서 요청(request)를 보내면 서버는 요청을 처리해서 응답(response)한다.

- HTTP는 connection less방식(stateless)이다. 클라이언트의 요청에 서버가 응답한 후 클라이언트와 연결을 끊는 구조로 network 속도가 느린 단점을 가지고 있다. 이를 개선하기 위해 HTTP 1.1 부터는 Keep Alive 기능을 지원한다. Keep Alive 기능은 일정한 시간(timeout)동안 접속을 유지하는 기능이다.

- 클라이언트가 서버에 접속하여 어떠한 요청을 하면, 서버는 세 자리 수로 된 응답 코드와 함께 응답한다.

- 응답코드는 응답헤더의 첫 번째 줄에 위치하여, 주요 응답 코드는 다음과 같다.

HTTP/1.1 200 : OK, HTTP/1.1 404 : Not Found, HTTP/1.1 500 : Internal error

- HTTP URL은 "http://"로 시작하며, 기본 포트번호는 80이다.

 

2) HTTP요청(request)과 응답(response)주요 구성 요소

(1) HTTP 요청(request) 주요 구성 요소

- HTTP 메소드

- 접근하고자 하는 URL

- 폼 파라미터

(2) HTTP 응답(response) 주요 구성 요소

- 상태 코드(요청 처리에 대한 성공 여부)

- 컨텐츠 타입(text/html, text/css, text/xml 등)

- 컨텐츠(HTML 소스, 이미지 등)

(3) HTTP 메소드

- HTTP 프로토콜을 사용하여 서버로 요청을 보내는 방법을 Method라 한다.

- 종류 

GET : 정보를 요청하기 위하여 사용한다. (SELECT)

POST : 클라이언트가 웹 서버에 데이터를 전달할 때 사용한다. (INSERT)

PUT : 정보를 업뎅트하기 위해서 사용한다. HTML 5는 지원하지 않음(UPDATE)

DELETE : 정보를 삭제하기 위해서 사용한다. HTML 5는 지원하지 않음(DELETE)

HEAD : (HTTP) 헤더 정보만 요청한다. 해당 자원이 존재하는지 혹은 서버에 문제가 없는지를 확인하기 위해서 사용한다.

OPTIONS : 웹 서버가 지원하는 메소드의 종류를 요청한다.

TRACE : 클라이언트의 요청을 그대로 반환한다. echo 서비스로 서버 상태를 확인하기 위한 목적으로 주로 사용한다.

- 보통 웹 서비스들은 GET과 POST만을 이용해서 개발한다.

 

HTTPS(HyperText Transfer Protocol over Secure Socket Layer)

- HTTP는 기본적으로 평문 데이터 전송을 원칙으로 하기 때문에 개인의 프라이버시가 오가는 서비스들(전자상거래, 전자메일, 사내문서)에 사용하기 힘들다.

- HTTP는 SSL 레이어 위에 HTTP를 통과 시키는 방식이다. 즉 평문의 HTTP 문서는 SSL 레이어를 통과하면서 암호화 돼서 목적지에 도착하고, 목적지에서는 SSL 레이어를 통과하면서 복호화돼서 웹 브라우저에 전달된다.

- SSL은 전자상거래에서의 데이터 보안을 위해서 개발한 통신 레이어다. SSL은 표현계층의 프로토콜로 응용 계층 아래에 있기 때문에, 어떤 응용 계층의 데이터라도 암호화해서 보낼 수 있다.

- HTTPS는 인증서를 이용해서, 접속 사이트를 신뢰할 수 있는지 평가할 수 있다.

- 일반적으로 HTPS는 HTTP에 비해서 느리다. 많은 양의 데이터를 처리할 경우 성능의 차이를 체감할 수 있다.

- HTTPS URL은 "https://"로 시작한다.

- 기본 포트번호는 443이다.

 

URL과 URI

URL(Uniform Resource Locator)

- 네트워크 상에서 자원이 어디 있는지를 알려주기 위한 규약이다.

- URL은 웹 사이트 주소뿐만 아니라 컴퓨터 네트워크상의 자원을 모두 나타낼 수 있으며, 해당 URL에 맞는 프로토콜을 이용하여 접속한다.

- URL은 인터넷 도메인 이름이나 IP주소, 이메일, 파일 전송과 같이 컴퓨터 네트워크 정보자원을 이용하는 모든 형태에 적용된다.

- 하위 개념으로 URL(Uniform Resource Locator), URN(Uniform Resource Name)이 있다.

 

웹 컨테이너(Web Container) ?

- JSP와 서블릿을 실행할 수 있는 소프트웨어를 웹 컨테이너(Web Container) 또는 서블릿 컨테이너(Servlet Container)라고 한다.

- 순수 서블릿을 처리하는 경우 서블릿 컨테이너라 부르는데, 서블릿 컨테이너를 포함한 JSP, HTTP 서버로서의 기능을 포함하기 때문에 웹 컨테이너라고 부르기도 한다.

- Apache Tomcat, IBM Web Sphere 어플리케이션 서버, Resin, 티맥스의 JEUS, 이클립스 재단의 jetty 등이 있다.

 

웹 컨테이너(Web Container)의 역할 및 특징

- 서블릿의 생명주기를 관리하고, URL과 특정 서블릿을 맵핑하며 URL 요청이 올바른 접근 권한을 갖도록 보장한다.

- 서블릿, JSP 등에 대한 요청을 다룬다.

- 서블릿 객체의 생성 및 초기화, 요청과 응답 객체 생성 및 관리 등의 작업을 수행한다.

- 웹 응용 프로그램의 보안, 병행성, 생명주기 관리 등의 서비스를 제공한다.

 

Apache Tomcat

- 아파치 소프트웨어 재단에서 개발한 서블릿 컨테이너만 있는 웹 애플리케이션 서버(WAS)

- 톰캣은 웹 서버와 연동하여 실행할 수 있는 자바 환경을 제공하여 자바 서버 페이지(JSP)와 자바 서블릿이 실행될 수 있는 환경을 제공한다.

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>image preview</title>
<style>
.container {
	margin: 30px auto;
	width: 500px;
}

#image_zone {
  width: 660px;
  min-height: 150px;
  padding: 10px;
  border: 1px dotted #00f;
  margin-top: 5px;
}

#image_zone:empty:before {
  content: attr(data-placeholder);
  color: #999;
  font-size: .9em;
}

.image-box {
	display: inline-block;
	position: relative;
	width: 150px; height: 120px;
	margin: 5px;
	border: 1px solid #00f;
	z-index: 1;
}

.image {
	width: 100%; height: 100%;
	z-index: none;
}

.image-btn {
	/* width:30px; height:30px; */
	position: absolute;
	font-size: 15px;
	right: 0px;
	bottom: 0px;
	z-index: 999;
	background-color:rgba(255,255,255,0.1);
	color: #f00;
	border: 1px solid #333;
	cursor: pointer;
	padding: 2px 5px;
}
</style>
</head>
<body>

<div class='container'>
	<h3>이미지 미리보기</h3>
	<form name="frm">
		<input type='file' name='selectFile' id='selectFile' multiple='multiple'>
		<div id='image_zone'
			data-placeholder='파일을 첨부 하려면 파일 선택 버튼을 클릭하거나 파일을 드래그앤드롭 하세요'></div>
	</form>
</div>

<script type="text/javascript">
( /* vid : 이미지들이 들어갈 위치 id, fid : file 태그 id */
	imageView = function imageView(vid, fid) {
		var imageZone = document.getElementById(vid);
		var selectFile = document.getElementById(fid);
		var sel_files = [];
    
		selectFile.onchange = function(e){
			var files = e.target.files;
			var fileArr = Array.prototype.slice.call(files) 
            // begin부터 end-1 인덱스 까지 요소를 얕은 복사하여 새로운 배열 객체로 반환
			for(f of fileArr) {
				imageLoader(f);
			}
		}; 
  
		// 탐색기에서 드래그앤 드롭 사용
		
		// 드래그로 넣었을 때 
		imageZone.addEventListener('dragenter', function(e) {
			e.preventDefault();
			e.stopPropagation();
		}, false);
		
		
    	// 드롭대상위로 지나갈 때
		imageZone.addEventListener('dragover', function(e) {
			e.preventDefault();
			e.stopPropagation();
		}, false);
  
    	// 드래그 할 때
		imageZone.addEventListener('drop', function(e) {
			var files = {};
			e.preventDefault();
			e.stopPropagation();
			var dt = e.dataTransfer;
			files = dt.files;
			for(f of files) {
				imageLoader(f);
			}
		}, false);
    
	    // 첨부된 이미지를 배열에 넣고 미리보기
		var imageLoader = function(file){
			sel_files.push(file);
			var reader = new FileReader();
			reader.onload = function(e) {
				let img = document.createElement('img')
				img.classList.add("image"); // class 추가
				img.src = e.target.result;
				imageZone.appendChild(makeDiv(img, file));
			};
	      
			var dt = new DataTransfer();
			for(f in sel_files) {
				var file = sel_files[f];
				dt.items.add(file);
			}
			selectFile.files = dt.files;
			
			reader.readAsDataURL(file);
		};
    
		// 첨부된 파일이 있는 경우 button과 함께 imageZone에 추가할 div를 만들어 반환
		var makeDiv = function(img, file) {
			var div = document.createElement('div');
			div.classList.add("image-box");
      
			var btn = document.createElement('input');
			btn.setAttribute('type', 'button');
			btn.setAttribute('value', 'x');
			btn.setAttribute('delFile', file.name);
			btn.classList.add("image-btn");
			btn.onclick = function(ev){
				var ele = ev.srcElement;
				var delFile = ele.getAttribute('delFile');
				for(var i=0 ;i<sel_files.length; i++){
					if(delFile === sel_files[i].name){
						sel_files.splice(i, 1);      
					}
				}
        
				var dt = new DataTransfer();
				for(f in sel_files) {
					var file = sel_files[f];
					dt.items.add(file);
				}
				selectFile.files = dt.files;
				
				var p = ele.parentNode;
				imageZone.removeChild(p);
			};
			div.appendChild(img);
			div.appendChild(btn);
			return div;
		};
	}
)('image_zone', 'selectFile'); // 바로 실행 함수
</script>
</body>
</html>

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<script type="text/javascript">
var $videoId = "";

function play() {
	var url = document.getElementById("youtube-url").value.trim();
	if(! url) {
		document.getElementById("youtube-url").focus();
		return;
	} // 입력한 주소 가져오기
	
	$videoId = url.substring(url.lastIndexOf('/') +1); 
	if(url.indexOf("=") > 0) {
		$videoId = url.substring(url.indexOf("=") + 1);
	}
	
	// youtube 실행
	var tag = document.createElement('script');
	tag.src = "https://www.youtube.com/iframe_api";	

	var firstScriptTag = document.getElementsByTagName('script')[0];
	firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);	
}

var player;
function onYouTubeIframeAPIReady() {
  player = new YT.Player('player', {
    height: '360',
    width: '640',
    videoId: $videoId,
    events: {
      'onReady': onPlayerReady,
      'onStateChange': onPlayerStateChange
    }
  });
}

function onPlayerReady(event) {
  event.target.playVideo();
}

var done = false;
function onPlayerStateChange(event) {
  if (event.data == YT.PlayerState.PLAYING && !done) {
    //setTimeout(stopVideo, 6000);
    done = true;
  }
}
function stopVideo() {
  player.stopVideo();
}

</script>
</head>
<body>

<div style="width: 800px; margin: 30px auto; text-align: center;">
	<div style="margin: 10px; ">
		<input type="text" id="youtube-url">
		<button type="button" onclick="play();">확인</button>
	</div>
	<div id="player"></div>
</div>

</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- // 반응형 웹을 만들기 위해서 위의 줄이 꼭 필요 -->
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">

<style type="text/css">
.box {
	width: 300px;
	height: 300px;
	margin: 30px auto;
	border: 3px dotted #333;
	padding: 10px;
	background: green;
}
/* 브라우저의 너비가 0~600 인 경우는 박스를 사라지게 하고 싶음.*/
@media (max-width:600px) {
	.box {
		display: none;
	}
}
</style>

</head>
<body>

<h3>반응형 웹</h3>

<p> 미디어 쿼리 : 각 미디어 메체에 따라 다른 스타일을 적용할 수 있게 만드는 것</p>

<div class="box"></div>
</body>
</html>


- max-width : 데스크탑의 가장 큰 화면 사이즈의 레이아웃을 기본으로 하고, 점차 축소하는 형태로 css 작성

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- // 반응형 웹을 만들기 위해서 위의 줄이 꼭 필요 -->
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">

<style type="text/css">
* {
	padding: 0; margin: 0; box-sizing: border-box;
}

body {
	font-size: 14px;
	font-family: '맑은 고딕', 나눔고딕, 돋움, sans-serif;
}

.container {
	width: 1200px; margin: 20px auto 10px;
	border: 3px solid black;
}

.header {
	width: 100%; background: #e4f7ba;
	padding: 20px;
	text-align: center;
}

.body-main:after {
	content: ""; clear: both; display: block;
}

.article {
	float: left; width: 75%; height: 500px; background: #eee;
	padding: 15px;
}

.side {
	float: left; width: 25%; height: 500px; background: #faf4c0;
}

.footer {
	width: 100%;
	background: #9575cd;
	padding: 20px;
	text-align: center;
}

/*
  - max-width : 데스크탑의 가장 큰 화면 사이즈의 레이아웃은 기본으로 하고, 점차 축소하는 형태로 css 작성
*/

/* 화면 너비 : 0~1200 - 데스크탑 */
@media (max-width:1200px) {
	.container { width: 95%; border: 3px solid red; }
}

/* 화면 너비 : 0~768 - 태블릿 */ 
@media (max-width:768px) {
	.container { width: 100%; border: 3px solid green; }
}

/* 화면 너비 : 0~480 - 스마트폰 옆으로 늘일 때 */
@media (max-width:480px) {
	.container { width: 100%; border: 3px solid blue; }
	.header { height: 300px }
	.article { float: none; width: 100%; height: 300px };
	.side { float: none; width: 100%; height: 300px; }
}

/* 화면 너비 : 0~320 - 스마트폰 기본 */
@media (max-width:320px) {
	.container { width: 100%; border: 3px solid gray; }
}
</style>

</head>
<body>

<div class="container">
	<div class="header">
		<h1>헤더입니다.</h1>
	</div>
	<div class="body-main">
		<div class="article">
			메인입니다.
		</div>
		<div class="side">
			사이드입니다.
		</div>
	</div>
	<div class="footer">
		<h3>푸터입니다.</h3>
	</div>
	
</div>

</body>
</html>

화면을 축소 함에 따라 테투리의 색이 변하는 것을 확인할 수 있다.


- min-width : 스마트폰 등 가장 작은 사이즈에서의 레이아웃을 기본으로 하고, 점차 확대되어가는 형태의 css

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- // 반응형 웹을 만들기 위해서 위의 줄이 꼭 필요 -->
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">

<style type="text/css">
* {
	padding: 0; margin: 0; box-sizing: border-box;
}

body {
	font-size: 14px;
	font-family: '맑은 고딕', 나눔고딕, 돋움, sans-serif;
}

.container {
	width: 1200px; margin: 20px auto 10px;
	border: 3px solid black;
}

.header {
	width: 100%; background: #e4f7ba;
	padding: 20px;
	text-align: center;
}

.body-main:after {
	content: ""; clear: both; display: block;
}

.article {
	float: left; width: 75%; height: 500px; background: #eee;
	padding: 15px;
}

.side {
	float: left; width: 25%; height: 500px; background: #faf4c0;
}

.footer {
	width: 100%;
	background: #9575cd;
	padding: 20px;
	text-align: center;
}

/*
  - min-width : 스마트폰 등 가장 작은 사이즈에서의 레이아웃을 기본으로 하고, 점차 확대되어가는 형태의 css
*/

/* 화면 너비 : 320px 이상 */
@media (min-width:320px) {
	.container { width: 100%; border: 3px solid gray; }
	.header { height: 300px }
	.article { float: none; width: 100%; height: 300px };
	.side { float: none; width: 100%; height: 300px; }
}

/* 화면 너비 : 480px 이상 */
@media (min-width:480px) {
	.container { width: 100%; border: 3px solid blue; }
	.header { height: 100% }
	.article { float: left; width: 75%; height: 500px };
	.side { float: left; width: 25%; height: 500px; }
}

/* 화면 너비 : 768px 이상 */
@media (min-width:768px) {
	.container { width: 100%; border: 3px solid green; }
}

/* 화면 너비 : 1024px 이상 */
@media (min-width:1024px) {
	.container { width: 100%; border: 3px solid red; }
}

</style>

</head>
<body>

<div class="container">
	<div class="header">
		<h1>헤더입니다.</h1>
	</div>
	<div class="body-main">
		<div class="article">
			메인입니다.
		</div>
		<div class="side">
			사이드입니다.
		</div>
	</div>
	<div class="footer">
		<h3>푸터입니다.</h3>
	</div>
	
</div>

</body>
</html>

CSS파일을 따로 뺐을 때

@charset "UTF-8";

* {
	padding: 0; margin: 0; box-sizing: border-box;
}

body {
	font-size: 14px;
	font-family: '맑은 고딕', 나눔고딕, 돋움, sans-serif;
}

header {
	padding: 15px; text-align: center;
}

nav {
	overflow: hidden; background: #b70202;
}

nav>a {
	float: left; color: #fff; text-align: center; padding: 15px 12px; text-decoration: none;
	display: block;
}

nav>a:hover {
	font-weight: 600;
}

nav:after {
	content: ""; clear: both; display: block;
}

main .left {
	float: left; width: 75%; background: #eee; min-height: 500px; padding: 15px;
}

main .right {
	float: left; width: 25%; background: #faf4c0; min-height: 500px; padding: 15px;
}

main:after {
	content: ""; clear: both; display: block;
}

footer {
	padding: 20px; text-align: center; background: #e4f7ba;
}
@charset "UTF-8";

nav>a {
	float: none;
}

main .left, main .right {
	width: 100%; padding: 0;
}

CSS파일을 연결해주는 link 태그 안에 media 속성을 이용한다.

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">

<link rel="stylesheet" href="desktop.css" type="text/css">
<link rel="stylesheet" href="mobile.css" media="(max-width:480px)" type="text/css">

</head>
<body>

<header>
	<h1>반응형 웹</h1>
</header>
<nav>
	<a href="#">홈</a>
	<a href="#">스터디</a>
	<a href="#">공지사항</a>
</nav>
<main>
	<article class="left">
		<h3>메인 화면</h3>
	</article>
	<article class="right">
		<h3>사이드</h3>
	</article>
</main>
<footer>
	<h3>footer 영역</h3>
</footer>
</body>
</html>


반응형 그리드 레이아웃 

- grid-template-columns: repeat(auto-fill, minmax(~)) 이용

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<style type="text/css">
* {
	margin: 0; padding: 0;
	box-sizing: border-box;
}

header {
	padding: 15px; text-align: center;
}

main {
	padding: 15px;
}

footer {
	padding: 15px;
	text-align: center;
}

.box {
	margin: 0 auto;
	padding: 0;
	list-style: none;
}

.box>li {
	background: #eee;
	height: 200px;
}

.grid {
	display: grid;
	grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
	grid-column-gap: 8px;
	grid-row-gap: 8px;
}

	
</style>
</head>
<body>

<header>
	<h1>Grid Layout</h1>
</header>

<main>
	<ul class="box grid">
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
		<li></li>
	</ul>
</main>

<footer>
	<h3>footer</h3>
</footer>
</body>
</html>

웹 스토리지 ?

- 웹 스토리지 API는 웹 브라우저가 직접 데이터를 저장한다.

- HTML5 이전에는 응용 프로그램이 데이터를 서버에게 요청할 때마다 매번 쿠키(cookie)에 정보를 저장했지만, 웹 스토리지는 사용자 측에서 좀 더 많은 양의 정보를 안전하게 저장할 수 있다.

- 데이터는 모든 서버 요청에 포함되어 있지 않지만, 요구하는 경우에만 사용된다. 이는 웹사이트의 성능에 영향을 주지 않고 대량의 데이터를 저장할 수도 있다.

- 데이터는 key/value 쌍을 저장하고 웹페이지는 자체적으로 저장된 데이터에 액세스할 수 있다.

- 웹 스토리지는 오리진(origin)마다 단 하나씩만 존재한다.

오리진 - 도메인(domain)과 프로토콜(protocol)의 한쌍으로 이루어진 식별자.

 

웹 스토리지를 활용한 대표적인 기능

- sesstionStorage를 활용해서 사용자가 '입력폼'을 입력하다가 페이지에서 벗어난 경우 백업/복구

- 글쓰기를 하다가 사용자가 창을 벗어난 경우 관련 작성하던 내용 백업/복구

- 웹페이지의 개인화 설정들에 대한 저장과 제공(캐쉬로 활용)

- 현재 읽은 글의 히스토리 저장(카운팅, 읽은 글 표시 등으로 활용)

- Canvas나 이미지에 대한 임시 저장 기능(base64로 변환)

- 웹페이지간 정보 전달(웹서버를 경유하지 않고 정보를 로컬에 유지)

 

웹 스토리지 객체

- sesstionStorage : 하나의 세션(sesstion)만을 위한 데이터를 저장하는 객체

- localStorage : 보관 기한이 없는 데이터를 저장할 수 있는 객체

 

 

예제 - localStorage

더보기
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body>

<h3>localStorage</h3>
<p>
 - 데이터 보존기간에 제한 없음<br>
 - 도메인당 하나가 생성<br>
 - 쿠키를 이용한 설정을 대신하기 적당
</p>

<p>
	<button type="button" onclick="clickCount()">카운트증가</button>
	<button type="button" onclick="deleteCount()">삭제</button>
</p>
<hr>

<div id="log"></div>

<script type="text/javascript">
viewCount();

function clickCount() {
	// Storage를 지원하지 않으면
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	// 웹 스토리지 값 가져오기
	var cnt = localStorage.count; // count는 내가 웹 스토리지에 저장할 때 사용한 이름
	// var cnt = localStorage.getItem('count');
	
	if(cnt) {
		cnt = Number(cnt) + 1;
	} else {
		cnt = 1;
	}
	
	// 웹 스토리지에 count라는 이름으로 저장
	localStorage.count = cnt;
	localStorage.setItem("count", cnt);
	
	viewCount();
}

function deleteCount() {
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	delete localStorage.count;
	
	viewCount();
}

function viewCount() {
	// Storage를 지원하지 않으면
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	var cnt = localStorage.count;
	cnt = cnt ? cnt : "";
	document.getElementById("log").innerHTML = "카운터의 현재 횟수 : " + cnt;
}
</script>
</body>
</html>

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body>

<h3>localStorage</h3>

<p>
	<input type="text" id="subject" placeholder="좋아하는 과목">
	<button type="button" onclick="addLog()">추가</button>
	<button type="button" onclick="deleteLog()">삭제</button>
</p>
<div id="log"></div>

<script type="text/javascript">

viewLog();

function viewLog() {
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	var ss = JSON.parse(localStorage.getItem("subject")) || [];
	var s = ss.join();
	
	document.getElementById("log").innerHTML = "좋아하는 과목 : " + s;
}

function addLog() {
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	var s = document.getElementById("subject").value.trim();
	if(! s) {
		return;
	}
	
	var ss = JSON.parse(localStorage.getItem("subject")) || [];
	// 처음 실행 시, 아무 것도 없어서 undefined.
	// 따라서 첫 실행시에는 var ss = []; 가 된다.
	
	ss.push(s);
	localStorage.setItem("subject", JSON.stringify(ss));
	
	viewLog();
	
	document.getElementById("subject").value = "";
	
}

function deleteLog() {
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	delete localStorage.removeItem("subject");
	viewLog();
}

</script>

</body>
</html>

 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">


<style type="text/css">
.list li {
	cursor: pointer;
}

.list li:hover:after, .list li.chk:after {
	content: '\2605';
	color: tomato;
}

.list li.chk:hover:after {
	content: '\2605';
}
</style>

</head>
<body>

<h3>localStorage 예제</h3>

<ul class="list">
	<li id="java">자바</li>
	<li id="oracle">Oracle</li>
	<li id="html">HTML</li>
	<li id="javascript">자바스크립트</li>
	<li id="spring">스프링</li>
	<li id="css">css</li>
</ul>

<script type="text/javascript">
	var progs = JSON.parse(localStorage.getItem("progs")) || [];
	
	progs.forEach(function(data) {
		document.getElementById(data).className = "chk";
	});
	
	document.querySelector(".list").addEventListener("click", function(e) {
		var id = e.target.id;
		var item = e.target;
		var index = progs.indexOf(id);
		
		if(index == -1) {
			progs.push(id);
			item.className = "chk";
		} else {
			progs.splice(index, 1);
			item.className = "";
		}
		
		localStorage.setItem("progs", JSON.stringify(progs));
		
		
	})
	
</script>

</body>
</html>

 

예제 - sesstionStorage 

더보기
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
</head>
<body>

<h3>sessionStorage</h3>
<p>
 - 한번의 세션 동안만 유지<br>
 - 유효범위와 보존기간이 있다.<br>
 - 같은 브라우저도 새로 생성되는 창에서는 세션이 다르므로 다른 스트로지를 가진다.<br>
 - 도메인마다 따로 생성된다.<br>
</p>

<p>
	<button type="button" onclick="clickCount()">카운트증가</button>
	<button type="button" onclick="deleteCount()">삭제</button>
</p>
<hr>

<div id="log"></div>

<script type="text/javascript">
viewCount();

function clickCount() {
	// Storage를 지원하지 않으면
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	// 웹 스토리지 값 가져오기
	var cnt = sessionStorage.count; // count는 내가 웹 스토리지에 저장할 때 사용한 이름
	// var cnt = sessionStorage.getItem('count');
	
	if(cnt) {
		cnt = Number(cnt) + 1;
	} else {
		cnt = 1;
	}
	
	// 웹 스토리지에 count라는 이름으로 저장
	sessionStorage.count = cnt;
	sessionStorage.setItem("count", cnt);
	
	viewCount();
}

function deleteCount() {
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	delete sessionStorage.count;
	
	viewCount();
}

function viewCount() {
	// Storage를 지원하지 않으면
	if(typeof(Storage) === "undefined") {
		return;
	}
	
	var cnt = sessionStorage.count;
	cnt = cnt ? cnt : "";
	document.getElementById("log").innerHTML = "카운터의 현재 횟수 : " + cnt;
}
</script>
</body>
</html>

 

+ Recent posts