반응형
반응형

📝Tiles

웹 페이지의 상단, 하단, 사이드바, ajax, 공통css 등과 같이 반복적으로 사용되는 부분에 정보를 모듈화해서 관리해줍니다.

즉 모듈관리 프로그램입니다.

 

JSP의 include같은 걸로 쓸수도 있지만 Tiles가 훨씬 우수합니다.
JSP Include 방식의 문제점은 매 JSP 페이지마다 모두 동일한 페이지들을 include 한다고 표시를 해야합니다.

만약 include 하는 페이지의 이름이 바뀌기라도 한다면 그에 해당하는 모든 페이지를 다 수정해야만 합니다.

 

 

<!-- spring 버전은 3.0.8 이상 필요 및 자바버전도 유의-->
<properties>
    <java-version>11</java-version>
    <org.springframework-version>5.2.7.RELEASE</org.springframework-version>
    <org.aspectj-version>1.6.10</org.aspectj-version>
    <org.slf4j-version>1.6.6</org.slf4j-version>
</properties>

<!-- Tiles -->
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-extras</artifactId>
    <version>3.0.8</version>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-servlet</artifactId>
    <version>3.0.8</version>
</dependency>
<dependency>
    <groupId>org.apache.tiles</groupId>
    <artifactId>tiles-jsp</artifactId>
    <version>3.0.8</version>
</dependency>

pom.xml

 

<!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory -->
<beans:bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <beans:property name="prefix" value="/WEB-INF/views/" />
    <beans:property name="suffix" value=".jsp" />
    <beans:property name="order" value="2" />
</beans:bean>
<!-- load 순서 2번째 -->

<beans:bean
    class="org.springframework.web.servlet.view.UrlBasedViewResolver">
    <beans:property name="viewClass"
        value="org.springframework.web.servlet.view.tiles3.TilesView" />
    <beans:property name="order" value="1" />
</beans:bean>
<!-- load 순서 1번째 (tiles 설정파일) -->

<beans:bean
    class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
    <beans:property name="definitions"
        value="/WEB-INF/tiles.xml" />
</beans:bean>

<!-- load 순서 1번째에 쓰이는 tiles 설정파일 -->

servlet-context.xml

 

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>

  <definition name="*/*" template="/WEB-INF/views/include/layout.jsp">
    <put-attribute name="title" value="{2} - OCR" />
    <put-attribute name="header" value="/WEB-INF/views/include/top.jsp" />
    <put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="aside" value="/WEB-INF/views/include/side.jsp" />
  </definition>
  <!-- definition name은 Controller의 */*형태의 return값을 받으면 해당 definition으로 분기시키겠다는 의미입니다.-->
  <!-- 예를 들어 Controller에서 페이지 리턴하려면 login/login_page 이런 형식으로 return할 때 {1} 에는 login이 들어가고 {2}에는 login_page가 들어가게 됩니다.
  <!-- 그리고 분기 페이지(template)는 layout.jsp 이라는 것입니다.--> 
  <!-- layout.jsp에서 각각 모듈로 된 걸 injection 하게 됩니다.-->
  <!-- put-attribute 은 layout에 넣을 요소 -->
  <!-- 위와 같은 방법으로 body는 동적으로 바뀌게 된다. -->
 
</tiles-definitions>

tiles.xml

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport"
	content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />

<!-- tiles.xml에서 선언한 name으로 각 모듈을 호출합니다. -->
<title><tiles:insertAttribute name="title" /></title>


<tiles:insertAttribute name="static" />
</head>

<body>

	<!-- header -->
	<tiles:insertAttribute name="header" />

	<div class="row">

		<!-- side -->
		<div class="col-1" id="layoutSide">
			<div id="layoutSidenav">
				<tiles:insertAttribute name="aside" />
			</div>
		</div>

		<!-- body -->
		<div class="col-9 mt-5" style="position: relative; left: 100px;">
			<tiles:insertAttribute name="body" />

		</div>
	</div>
	
</body>
</html>

layout.jsp (전체 구조)

 

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


<link href="<%=request.getContextPath()%>/resources/css/side_style.css"
	rel="stylesheet"><tiles:insertAttribute name="aside" />

<div class="sidebody">

	<div class="sidenavigation">
		<ul>
			<li class="sidelist active"><a href="test"> <span
					class="icon ps-4"><ion-icon name="albums-outline"></ion-icon></span>
					<span class="title ms-3">대시보드</span>
			</a></li>

			<li class="sidelist"><a href="listOcr"> <span
					class="icon ps-4"><ion-icon name="person-outline"></ion-icon></span>
					<span class="title ms-3">주민등록증</span>
			</a></li>

			<li class="sidelist"><a href="#"> <span class="icon ps-4"><ion-icon
							name="car-outline"></ion-icon></span> <span class="title ms-3">운전면허증</span>
			</a></li>

			<li class="sidelist"><a href="#"> <span class="icon ps-4"><ion-icon
							name="language-outline"></ion-icon></span> <span class="title ms-3">외국인등록증</span>
			</a></li>

			<li class="sidelist"><a href="#"> <span class="icon ps-4"><ion-icon
							name="airplane-outline"></ion-icon></span> <span class="title ms-3">여권</span>
			</a></li>
		</ul>
	</div>
</div>


<script type="module"
	src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.esm.js"></script>
<script nomodule
	src="https://unpkg.com/ionicons@5.5.2/dist/ionicons/ionicons.js"></script>
<script src="<%=request.getContextPath()%>/resources/js/script.js"></script>

side.jsp (사이드바)

 

<style>
@import
	url('https://fonts.googleapis.com/css2?family=Gowun+Dodum&display=swap')
	;
</style>


<!-- CSS -->
<link
	href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css"
	rel="stylesheet"
	integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3"
	crossorigin="anonymous">
<link href="<%=request.getContextPath()%>/resources/css/styles.css"
	rel="stylesheet">
<link href="<%=request.getContextPath()%>/resources/css/custom.css"
	rel="stylesheet">
<link href="<%=request.getContextPath()%>/resources/css/common.css"
	rel="stylesheet">
<link href="<%=request.getContextPath()%>/resources/css/bootstrap.css"
	rel="stylesheet" />
<link
	href="<%=request.getContextPath()%>/resources/css/search_result.css"
	rel="stylesheet" />
<link rel="icon" type="image/x-icon"
	href="<%=request.getContextPath()%>/resources/assets/img/favicon.png" />
	

<!-- JS -->
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<script
	src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/3.7.1/chart.min.js"></script>
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>
<script src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>

static.jsp (정적 소스)

 

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

<style>
background: linear-gradient(137deg, #fff6b7, #f77c99, #6578f2, #c2ffd8); background-size: 800% 800%; -webkit-animation: AnimationName 16s ease infinite; -moz-animation: AnimationName 16s ease infinite; -o-animation: AnimationName 16s ease infinite; animation: AnimationName 16s ease infinite; @-webkit-keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } @-moz-keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } @-o-keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} } @keyframes AnimationName { 0%{background-position:0% 50%} 50%{background-position:100% 50%} 100%{background-position:0% 50%} }
</style>

<nav
   class="topnav navbar navbar-expand shadow justify-content-between justify-content-sm-start navbar-light m-0 p-0"
   id="sidenavAccordion" style="height:70px">
   <!-- Sidenav Toggle Button
   <button class="btn btn-icon btn-transparent-dark" id="sidebarToggle">
      <i data-feather="menu"></i>
   </button> -->
   <!-- Navbar Brand-->
   <!-- * * Tip * * You can use text or an image for your navbar brand.-->
   <!-- * * * * * * When using an image, we recommend the SVG format.-->
   <!-- * * * * * * Dimensions: Maximum height: 32px, maximum width: 240px-->
   <a href="test" class="ms-5 me-2"> <img
      src="<%=request.getContextPath()%>/resources/image/logo.png"
      ; style="width: 113px;">
   </a>
   
   <a href="doLogout" style="right: 0; color: #FFFFFF;" onclick="if(confirm('로그아웃 하시겠습니까?') == false)return false;"> 로그아웃 </a>
</nav>

top.jsp (상단)

 

 

footer.jsp는 저는 안 써가지고 따로 만들진 않았습니다.

 

 

 

 

 

- 참고용(여러가지의  - tiles 활용 방식)

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
       "-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
       "http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>

  <definition name="*/*" template="/WEB-INF/views/include/layout.jsp">
    <put-attribute name="title" value="{2} - Search" />
    <put-attribute name="header" value="/WEB-INF/views/include/top.jsp" />
    <put-attribute name="body" value="/WEB-INF/views/{1}/{2}.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="aside" value="/WEB-INF/views/include/side.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/include/footer.jsp" />
  </definition>
  
  <definition name="*/*/*" template="/WEB-INF/views/include/none_layout.jsp">
    <put-attribute name="title" value="{3} - Search" />
    <put-attribute name="body" value="/WEB-INF/views/{1}/{2}/{3}.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/include/footer.jsp" />
  </definition>
  
  <definition name="login" template="/WEB-INF/views/include/login_layout.jsp">
    <put-attribute name="title" value="login - Search" />
    <put-attribute name="body" value="/WEB-INF/views/login/login.jsp" />
    <put-attribute name="static" value="/WEB-INF/views/include/static.jsp" />
    <put-attribute name="footer" value="/WEB-INF/views/include/footer.jsp" />
  </definition>

</tiles-definitions>

 

 

반응형
반응형

📝xmlns

xmlns="http://www.springframework.org/schema/beans"

xmlns:aop="http://www.springframework.org/schema/aop"

 

spring에 xml에 보시면 이렇게 적혀 있는 것들이 있습니다 이거에 대해서 설명하도록 하겠습니다.

위에는 http:www.springframework.org에 들어가면 보이는 화면입니다.

 

여기에서 보시면 aop도 있고  beans도 있고 합니다. 즉 springframework가 이러한 기능들을 지원해주는 것입니다.

 

xmlns은 import라고 생각하면 된다. 스프링에서 지원해주는 클래스 같은 느낌으로 사진에서 보는 거 같이 들어가면 각자 폴더가 있고 각자에 해당하는 기능들이 있습니다.

대부분 쓰는건 bean같은게 있는데 그걸 쓰기 위해서는  xmlns="http://www.springframework.org/schema/beans" 이런식으로 선언이 필요합니다.

 

그리고 xmlns:aop 이렇게 선언한 이유import한 aop에 있는 필드부분이 bean에 있는 필드부분하고 겹치면 뭐가 aop에 관한 것인지 bean에 관한 것인지 잘 모르기 때문에 그렇게 한다 그래서 <aop:config> 이런식으로 사용됩니다.

 

즉 이렇게 하는 걸 namespace라고 하는데 각 요소간 충돌을 방지하기 위해서 입니다

 

* 여담으로 인터넷 안 되는 환경(폐쇄망)에서는 xsd를 못 읽을 수 있지만 한번이라도 실행시킨 프로젝트를 가져올 경우 jar안에 xsd가 다 내장되어있기 때문에 해당 경로를 잘 읽어서 가져온다 만약 못 가져오는 경우 root-context.xml(가장 먼저 읽는 부분)에서 클래스패스 경로 지정이 필요

 

📝 root-context.xml

View와 밀접하지 않은 정보를 기술하는 xml 파일입니다.

외부 jar파일등으로 사용하는 클래스는 bean 태그를 이용해 작성합니다.

root-context에 등록되는 빈들은 모든 컨텍스트에서 사용 가능합니다.

ex) DB는 View(JSP)와는 관련이 없으므로, DB에 접속하기 위한 설정은 root-context.xml 에 설정

 

 

📝 servlet-context.xml

servlet-context에 등록되는 빈들은 해당 컨테스트에서만 사용 가능합니다.

url과 관련된 controller나, @(어노테이션), ViewResolver, Interceptor, MultipartResolver 등의 설정을 해줍니다.

 

 

 

 

반응형
반응형

JSP 스크립트의 문제점을 보완 가독성을 향상시키고 스크립트에서 자바의 사용을 최소화 할 수 있습니다.

 

먼저 jar파일을 다운로드후 프로젝트 라이브러리에 추가시켜 사용합니다.

 

http://tomcat.apache.org/

 

Apache Tomcat® - Welcome!

The Apache Tomcat® software is an open source implementation of the Jakarta Servlet, Jakarta Server Pages, Jakarta Expression Language, Jakarta WebSocket, Jakarta Annotations and Jakarta Authentication specifications. These specifications are part of the

tomcat.apache.org

 

 

 

JSTL도 크게 5개로 나뉩니다. 우리는 주로 기본적인 c에 대해서 알아보도록 하겠습니다.

필요한 게 있으시면 찾아서 쓰시면 됩니다.

 

 

코어 : 자바 변수 지원 , 흐름 제어 , URL처리

XML : xml 처리 , xml 흐름제어

국제화 : 국제화처리, 메시지 관리

SQL : 데이터베이스 접근 및 처리

함수(function) : 문자열 처리, 컬렉션 처리

 

 

라이브러리 접두어 URI
코어(Core) c http://java.sun.com/jsp/jstl/core
XML x http://java.sun.com/jsp/jstl/xml
국제화 fmt http://java.sun.com/jsp/jstl/fmt
SQL sql http://java.sun.com/jsp/jstl/sql
함수(functions) fn http://java.sun.com/jsp/jstl/functions

 

<%@ 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 = "x" uri="http://java.sun.com/jsp/jstl/xml"%>
<%@ taglib prefix = "fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix = "sql" uri="http://java.sun.com/jsp/jstl/sql"%>
<%@ 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:set var="jum" value="99"/> <!-- 변수를 선언합니다. -->
	<c:remove var="jum"/> <!-- 변수를 지웁니다. -->
	
	<c:set var="jum" value="0"/>
	<c:if test="${jum <= 100}">
		jum = ${jum}<br>
	</c:if>
	
	<c:catch var="errmsg">
		<%= 99 / 0 %>
	</c:catch>
	<c:out value="${errmsg}"/><br>	

	<c:choose>
		<c:when test="${jum>=90}">
			<c:set var="grd" value="A"/>
			<c:out value="${grd}"/><br>
		</c:when>
		<c:when test="${jum>=80}">
			<c:set var="grd" value="B"/>
			<c:out value="${grd}"/><br>
		</c:when>
		<c:otherwise>
			<c:set var="grd" value="씨뿌리기!!"/>
			<c:out value="${grd}"/><br>
		</c:otherwise>
	</c:choose>
	
	<c:forEach var="i" begin="1" end="10" step="${i = i + 1}">
		<c:set var="sum" value="${sum = sum + i}"/>
	</c:forEach>
	
	<c:forTokens var="msg" items="JSTL program test!" delims=" ">
		${msg} <br>
	</c:forTokens>

	<c:redirect url="./EL_form_request.jsp">
		<c:param name="para" value="massage"/>
	</c:redirect>
</body>
</html>

 

<%@ taglib prefix = "c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix = "x" uri="http://java.sun.com/jsp/jstl/xml"%>
<%@ taglib prefix = "fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix = "sql" uri="http://java.sun.com/jsp/jstl/sql"%>
<%@ taglib prefix = "fn" uri="http://java.sun.com/jsp/jstl/functions"%>

이런식으로 선언해주면 사용이 가능합니다. 왜 다 적었냐면 그냥 어떻게 쓰는지 알려주려고 그랬습니다.

 

 

<c:set 변수타입 = "변수명" value = "변수값">

<c:set var="jum" value="99"/>

 

변수를 선언합니다.

 

<c:remove 변수타입 =" 변수명"/>

<c:remove var="jum"/>

 

변수를 제거합니다.

 

<c:if test="${조건문}"> 

<c:if test="${jum <= 100}">

 

if문입니다.

 

<c:catch 변수타입="변수명">

<c:catch var="errmsg">

 

예외 메세지를 받아주는 변수타입과 변수명을 설정해주고 try catch처럼 예외를 잡아줍니다.

 

<cout: value="출력할 것">

<c:out value="${errmsg}"/>

 

출력문입니다. 

 

<c:choose> 

 

switch문입니다.

 

<c:when test="${조건문}">

<c:when test="${jum>=90}">

 

case문입니다.

 

<c:otherwise>

default문 입니다. 

 

- 형태 1 -

<c:forEach 반복자변수타입="반복자변수명" begin="반복자초기값" end="반복자끝값" step="${증가값"}

<c:forEach var="ibegin="1end="10step="${i = i + 1}">

 

for문입니다. 이걸 자바의 for문으로 바꾸면 이와 같다

for(var i = 1 ; i <= 10 ; i++)

 

- 형태 2 -

 

<c:forEach items="${books}" var="book" varStatus="status">

    ${status.current} 

    ${status.index} 

    ${status.count} 

    ${status.begin}

    ${status.end} 

    ${status.step} 

</c:forEach>

 

items : 배열명

begin : 반복문의 시작값을 설정

end : 반복문의 종료값을 설정

step : 반복문의 증가값을 설정

var : 배열의 인덱스

varStatus : 변수의 상태를 담을 변수를 설정

 

${status.current} : 현재 인덱스

${status.index} : 0부터의 순서

${status.count} : 1부터의 순서

${status.begin} : 시작값

${status.end} : 끝값

${status.step} : 증가값

 

<c:forTokens 토큰내용이들어갈 변수타입=변수명 items="내용" delims="구분자">

<c:forTokens var="msgitems="JSTL program test!delims=" ">

 

내용을 구분자로 나눠서 변수명(msg)에 들어가게 됩니다.

 

<c:redirect url="연결 할 곳">

<c:redirect url="./EL_form_request.jsp">

 

redirect와 동일합니다.

 

<c:param name="속성명" value="속성값">

<c:param name="para" value="massage"/>

 

jsp:param과 동일합니다.

반응형
반응형
<%@ 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>
	<!-- \$은 EL을 텍스트상으로 그냥 표현하기 위해서 쓰입니다. -->
	\${ 1 + 5 } = ${1 + 5} <br> <!-- 더하기 연산 -->
	\${ 6 - 5 } = ${6 - 5} <br> <!-- 빼기 연산 -->
	\${ 8 * 5 } = ${8 * 5} <br> <!-- 곱하기 연산 -->
	\${ 1 / 5 } = ${1 / 5} <br> <!-- 나누기 연산 -->
	\${ 11 % 5 } = ${11 % 5} <br> <!-- 나머지 연산 -->
	-----------------------------<br>
	\${ 5 = 5 } = ${5 == 5} <br> <!-- 같다 관계연산 -->
	\${ 1 < 5 } = ${1 < 5} <br> <!-- < 관계연산 -->
	\${ 1 > 5 } = ${1 > 5} <br> <!-- > 관계연산 -->
 	\${ 1 => 5 } = ${1 >= 5} <br> <!-- => 관계연산 -->
	\${ 1 <= 5 } = ${1 <= 5} <br> <!-- <= 관계연산 -->
	-----------------------------<br>
	\${ 5 >= 5 && 5 <= 5 } = ${5 >= 5 && 5 <= 5} <br> <!-- and 논리연산 -->
	\${ 5 >= 5 || 5 <= 2 } = ${5 >= 5 || 5 <= 2} <br> <!-- or 논리연산 -->
	\${ !(5 > 5) } = ${!(5 > 5)} <br> <!-- not 논리연산 -->

	\${empty "abc"} = ${empty "abc"} <!-- .empty -->
</body>
</html>

JSP 스크립트의 구성요소와 HTML 태그를 혼합해서 코딩하다보면 복잡하고 이해하기 어려운 경우가 발생합니다.

표현 언어 표준 태그 라이브러리를 사용하면 이러한 문제를 쉽게 해결 할 수 있습니다.


먼저 EL에 대해서 알아보도록 하겠습니다.  JSP의 <%= =>표현식을 대신합니다.

 

📝표현 언어 (EL)

 

JSP 스크립트 구성요소중 표현식(<%= =>)을 대신해 줍니다.

기본 문법 ${표현 할 내용} 또는 #{표현 할 내용} 입니다.

 

 

$와 #의 차이는 저도 잘 모르겠습니다.

제가 알아본 바로는 $ ${4} , ${3 + 2} 는 되는데 ##{3 + 2}는 되고 #{4}는 안 됩니다.

 

우리가 지금까지 사용해 왔던 연산들을 쓰시고 변수가 있으면 변수로도 계산 가능한 말 그대로 표현식입니다.

 

 

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

<%
	session.setAttribute("cust_id","admin");
	session.setAttribute("cust_name","관리자");
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
	<form name = "login_form" method = "POST" action = "./EL_form_request.jsp">
		<table>
			<tr>
				<th> 아 이 디 </th>
				<th>
					<input type = "text" name = "cust_id" size = "10" maxlength = "10">
				</th>
			</tr>
			<tr>
				<th> 이 름 </th>
				<th>
					<input type = "text" name = "cust_name" size = "10" maxlength = "10">
				</th>
			</tr>
			<tr>
				<td colspan="2" style="text-align:center">
					<input type = "submit" value = "전송">
				</td>
			</tr>
		</table>
	</form>
</body>
</html>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    
<%
	request.setCharacterEncoding("UTF-8");
%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

${cust_id}<br>
${cust_name}<br>

내장객체 sessionScope(cust_id) : ${sessionScope.cust_id}<br>
내장객체 sessionScope(cust_name) : ${sessionScope.cust_name}<br>

내장객체 param(cust_id) : ${param.cust_id}<br>
내장객체 param(cust_name) : ${param.cust_name}

</body>
</html>

 

request.getParameter를 안 해도 ${cust_id}를 통해 바로 가져올 수가 있습니다. (여기에선 session영역)

또한 pageScope, requestScope, sessionScope, applicationScope도 사용이 가능합니다.

param과 paramaValues로 값과 값들을 가져올 수 있습니다. 

param의 경우 넘어온 값들이 저장 되어 있습니다.

반응형
반응형
package multi_thread.daemon_thread;

public class AutoSaveThread extends Thread {
	
	public void save() {
		System.out.println("작업 내용을 저장함");
	}
	
	@Override
	public void run() {
		while(true){
			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				break;
			}
			save();
		}
		
	}

}
package multi_thread.daemon_thread;

public class DaemonExample {

	public static void main(String[] args) {
		
		AutoSaveThread autoSaveThread = new AutoSaveThread();
		autoSaveThread.setDaemon(true);
		autoSaveThread.start();
		
		try {
			Thread.sleep(3000);
		} catch (InterruptedException e) {}

		System.out.println("메인 스레드 종료");
	}

}

데몬 스레드 주 스레드의 작업을 돕는 보조적인 역할을 수행하는 스레드입니다.

주 스레드 (메인 스레드) 가 종료되면 데몬 스레드는 강제적으로 자동 종료됩니다.

 

setDaemon(true)을 이용해 일반 스레드를 데몬 스레드로 만듭니다.

시작 하는 방법은 기본 스레드와 동일합니다.

 

 

 

 

반응형
반응형
package multi_thread.thread_stop_interrupt;

public class PrintThread1 extends Thread{
	private boolean stop;
	
	public void setStop(boolean stop) {
		this.stop = stop;
	}
	
	public void run() {
		while(!stop) {
			System.out.println("실행 중");
		}
		System.out.println("자원 정리");
		System.out.println("실행 종료");
	}
}
package multi_thread.thread_stop_interrupt;

public class StopFlagExample {

	public static void main(String[] args) {
		
		PrintThread1 printThread = new PrintThread1();
		printThread.start();
		
		try { Thread.sleep(1000);} catch (InterruptedException e ) {}

		printThread.setStop(true);
	}

}

스레드를 종료시키는 법에는 2가지 방법이 있다. 하나는 stop()과 interrupt() 메소드를 이용하는 방법

 

하지만 stop()메소드는 스레드가 갑자기 종료되면 스레드가 사용 중이던 자원이 불안정 상태로 남겨지기 때문에

안 쓰이게 됩니다. 그래서 stop플래그를 이용한 방법이 있습니다.

 

stop플래그란 무한 반복문을 돌고 있을 때 boolean을 이용해 안정적으로 run()을 종료로 이끌게 하는 역할입니다.

 

package runnable_jar;

public class PrintThread extends Thread {

	@Override
	public void run() {
		// 방법 1
//		try {
//			while (true) {
//				System.out.println("실행 중");
//				Thread.sleep(1); // sleep 있어야 main Thread에서 interrupt() 사용시 인식 함
//			}
//		} catch (InterruptedException e) {
//			e.printStackTrace();
//		}
		
		// 방법 2
		while(true) {
			System.out.println("실행중");
			if(Thread.interrupted()) { // sleep 없어도 사용 가능한 부분
				break;
			}
		}
		
		
		System.out.println("자원 정리");
		System.out.println("실행 종료");
	}

}
package runnable_jar;

public class InterruptExample {

	public static void main(String[] args) {

		Thread thread = new PrintThread();
		thread.start();

		try {
			Thread.sleep(1000);
		}catch(Exception e) {
			e.printStackTrace();
		}
		
		// 일시 정지 상태일 때 InterruptedException을 발생 시킴
		// 실행 대기 또는 실행 상태에서는 발생하지 않는다.
		thread.interrupt();
	}

}

interrupt 메소드는 스레드가 일시 정지일 때 InterruptedException 예외를 발생 시키는 역할을 합니다.

이것을 이용하면 run()메소드를 정상 종료시킬 수 있습니다.

 

지금 Thread.sleep(1)이라도 준 이유일시정지 일 때 예외를 발생시키기 때문입니다.

 

반응형
반응형
package multi_thread.thread_alternate;

public class WorkObject {
	public synchronized void methodA() { // 동기화 메소드에서만 사용 가능 (synchronized)

		System.out.println("ThreadA의 methodA() 작업 실행");
		notify(); // wait() 상태 스레드를 실행 대기로 변경 (실행 가능한 상태)
		try { wait(); } // 자기 자신 일시정지 상태로 변경
		catch (InterruptedException e) { }
	}

	public synchronized void methodB() { // 동기화 메소드에서만 사용 가능 (synchronized)

		System.out.println("ThreadB의 methodB() 작업 실행");
		notify();  // wait() 상태 스레드를 실행 대기로 변경 (실행 가능한 상태)
		try { wait(); }  // 자기 자신 일시정지 상태로 변경
		catch (InterruptedException e) { }
	}
}
package multi_thread.thread_alternate;

public class ThreadA extends Thread{
	private WorkObject workObject;
	
	public ThreadA(WorkObject workObject) {
		this.workObject = workObject;
	}
	
	@Override
	public void run() {
		for(int i = 0 ; i < 10; i++) {
			workObject.methodA();
		}
	}
}
package multi_thread.thread_alternate;

public class ThreadB extends Thread{

	private WorkObject workObject;
	
	public ThreadB(WorkObject workObject) {
		this.workObject = workObject;
	}
	
	@Override
	public void run() {
		for(int i = 0 ; i < 10; i++) {
			workObject.methodB();
		}
	}
}
package multi_thread.thread_alternate;

public class WaitNotifyExample {

	public static void main(String[] args) {
		WorkObject sharedObject = new WorkObject();
		
		ThreadA threadA = new ThreadA(sharedObject);
		ThreadB threadB = new ThreadB(sharedObject);
		
		threadA.start();
		threadB.start();

	}

}

두 개 스레드를 교대로 번갈아 실행 시키고 싶을 때 notify()와 wait()를 이용하면 됩니다.

 

자신의 작업을 시작하면 상대방 스레드(B)를 실행대기 상태를 걸고 자신(A)은 실행합니다.

그 후 자신의 작업이 끝나면(A)상대방 스레드(B)상대방(A)을 실행대기로 만들고 자기(B)는 실행합니다.

실행 끝난 후 자신(B)을 일시정지 상태로 만들어야합니다.

 

공유객체는 각 작업 내용을 동기화 메소드로 구분해야합니다.


notify() 같은 공유 객체동기화 메소드를 이용하는 상대방 스레드 실행대기상태로 만듭니다.
wait() 자신은 일시 정지 상태로 만듭니다.

 

이렇게 번갈아가면서 실행 되게 됩니다.

 

반응형
반응형
package multi_thread.thread_join;

public class SumThread extends Thread{
	private long sum;
	
	public long getSum() {
		return sum;
	}
	
	public void setSum(long sum) {
		this.sum = sum;
	}
	
	public void run() {
		for (int i = 1 ; i <= 100 ; i++) {
			sum += i;
		}
	}

}
package multi_thread.thread_join;

public class JoinExample {

	public static void main(String[] args) {
		
		SumThread sumThread = new SumThread();
		sumThread.start();
		
		try { 
			sumThread.join(); 
			// sumThread를 일시중지하는게 아니라 sumThread가 다 종료될 때까지 
			// 호출한 스레드(여기선 메인스레드)를 일시정지시킵니다.
		}catch (InterruptedException e) {
			
		}

		System.out.println("1 ~ 100 합 : " + sumThread.getSum());
	}

}

join이라는 메소드사용 스레드가 전부 끝날 때 까지 다른 스레드를 중지시키는 역할입니다.

 

스레드는 번갈아 실행 되기 때문에 메인 스레드를 멈추지 않으면 연산하기도 전에 Sum 값을 출력해버려 0이 나오게됩니다.

그래서 join을 걸어서 메인스레드를 멈추게 한 것입니다.

 

 

그리고 해당 스레드가 다 끝나면 모든 스레드를 다시 정상 실행시킵니다.

반응형
반응형
package multi_thread.thread_status;

public class ThreadA extends Thread{

	public boolean stop = false; // 종료 플래그
	public boolean work = true ; // 작업 진행 여부 플래그
	
	public void run() {
		while(!stop) {
			if(work) {
				System.out.println("ThreadA 작업 내용");
			} else {
				Thread.yield(); // 실행 대기 상태 만들기
			}
		}
		System.out.println("ThreadA 종료");
	}
}
package multi_thread.thread_status;

public class ThreadB extends Thread {
	
	public boolean stop = false; // 종료 플래그
	public boolean work = true ; // 작업 진행 여부 플래그
	
	public void run() {
		while(!stop) {
			if(work) {
				System.out.println("ThreadB 작업 내용");
			} else {
				Thread.yield(); // 실행 대기 상태 만들기
			}
		}
		System.out.println("ThreadB 종료");
	}
}
package multi_thread.thread_status;

public class YieldExample {

	public static void main(String[] args) {
		ThreadA threadA = new ThreadA();
		ThreadB threadB = new ThreadB();

		threadA.start();
		threadB.start();
		
		try {Thread.sleep(1000);} catch (InterruptedException e) {}
		threadA.work = false;
		
		try {Thread.sleep(1000);} catch (InterruptedException e) {}
		threadA.work = true;
		
		try {Thread.sleep(1000);} catch (InterruptedException e) {}
		threadA.stop = true; 
		threadB.stop = true;
		// thread.stop() 이라는 메소드가 존재하지만 강제로 종료하는 거이기 때문에 스레드가 살아있을 수가 있기 때문에 플래그값을 변경해 스레드 자체를 정상 종료시키는게 더 좋은 방법
		}
	}

yield() 메소드호출한 스레드를 실행 대기 상태로 돌아가 다른 스레드가 실행 기회를 가질 수 있게 도와줍니다.

(동일 또는 높은 우선순위의 스레드)

 

여기에서 ThreadA, B가 번갈아가면서 사용하지만 ThreadA의 work 값이 false가 되면 아무 이유 없는 무한루프를 반복합니다.

 

멀티스레드가 정말 병렬처리라면 상관 없는데 번갈아가면서 사용하는 거기 때문에(싱글코어 일시 = CPU1개) Thread A가 의미 없는 짓을 할 때 동안 ThreadB는 사용을 못하게 되는 것이죠 그걸 yield()메소드를 이용해 ThreadB가 계속적으로 사용될 수 있게  ThreadB가 의미 없는짓 할 땐 ThreadA가 쓰게 되면 번갈아 가면서 안 써도 되니까 속도가 더 빨라지겠죠?

 

 

반응형