반응형
반응형

@app.route 같이 어노테이션으로 맵핑되는 함수라우트 함수라고 합니다.

새로운 URL이 생길 때 라우트 함수를 create_app 함수 안에 계속 추가해야 하는 불편함이 있습니다. 

이 때 사용할 수 있는 클래스가 블루프린트입니다.

블루 프린트를 이용하면 라우트 함수를 구조적으로 관리할 수 있습니다.

@bp.route에서 bp는 Blueprint클래스로 생성한 객체입니다. 
생성시 Blueprint(이름모듈명URL프리픽스)를 전달해야 합니다.

url_prefix에 대해 설명하자면 url_prefix='/' 일 경우 localhost:5000/ 
(localhost:5000은 기본적으로 설정된 아이피와 포트번호입니다. 다를 수도 있어요)

url_prefix='/main' 이라고 입력 되면 localhost:5000/main이 되게 됩니다.

 



from flask import Blueprint

bp = Blueprint('main', __name__, url_prefix='/')

@bp.route('/hello')
def hello_pybo():
        return 'Hello, Pybo!'

@bp.route('/')
def index():
        return 'Pybo, index'

main_views.py 내용을 작성해주세요

from flask import Flask

def create_app():
        app = Flask(__name__)

        from .views import main_views # .view에서 .은 현재위치의 views 폴더로부터 import한다는 말
        app.register_blueprint(main_views.bp) # 블루프린트 객체 bp 등록

        return app

pybo.py를 수정해주세요

 

이렇게 블루프린트 객체app.register_blueprint(파일.bp객체명)으로 등록해주면 main_views.py를 참조하게 됩니다.

 

 

이제 플라스크 실행 후 들어가서 확인 해보겠습니다.

 

반응형
반응형

프로젝트 규모가 커질수록 문제가 발생할 확률이 높아집니다.

app 객체를 전역으로 사용할 때 발생하는 문제가 생기는데
예방하려면 애플리케이션 팩토리를 사용하라고 권합니다.

pybo.py파일을 pybo/__init__.py 파일로 대체하고 플라스크 서버를 실행해보겠습니다.

pybo라는 폴더를 생성해주고 기존의 pybo.py를 pybo/__init__.py로 옮기고 이름을 변경해봤습니다.

그리고 실행 시켰는데 아주 잘 실행됩니다.

 

우리는 저번에 FLASK_APP=pybo로 설정해놨기 때문에 c:\projects\myproject 에서 pybo.py를 찾을 수 있습니다.

만약 pybo.py가 아니라 pybo123로 cmd를 설정하고 pybo123으로 이름 바꾸면 또한 찾을 수 있습니다.

 

그리고 만약 pybo라는 파일이 없는데 폴더가 있는 경우 거기에서

기본적으로 __init__.py라는 파일을 실행(기본적으로 __init__.py가 default값)시켜주는 것입니다.

애플리케이션 팩토리를 사용해보도록 하겠습니다.

 

from flask import Flask

def create_app():
        app = Flask(__name__)
        @app.route('/')
        def heello_pybo():
            return 'Hello, Pybo!'
        return app

만약 app이라는 변수를 전역으로 사용할 경우 문제가 생길 수 있기 때문에 지역변수로 선언해 문제가 없게 합니다.

create_app 대신 다른 이름을 사용하면 정상 동작하지 않습니다. flask 내부 정의된 함수명입니다.

 

반응형
반응형

규모를 갖춘 플라스크 프로젝트를 만들고자 한다면 프로젝트 구조를 잘 만들어줘야 합니다.
프로젝트 구성할 때 생각을 많이 해야합니다.

|-- pybo/
|      |- __init__.py
|      |
|      |- models.py
|      |
|      |- forms.py
|      |
|      |- view.py
|      |      |-main_views.py
|      | 
|      |-static/
|      |      |-style.css
|      |
|      |-templates/
|              |-index.html
|    
|-- config.py

 

무조건 이 구조는 아니지만 일반적으로 이러한 구조입니다.

 

models.py : 데이터베이스를 처리합니다.

forms.py   : 서버로 전송된 폼을 처리해줍니다.

views       : 화면을 구성해주는 디렉터리입니다. 저번에 작성한 pybo.py 같은 걸 의미합니다.

static       : CSS, 자바스크립트, 이미지 파일을 저장하는 디렉터리입니다.

templates : HTML파일을 저장하는 디렉터리입니다.

config.py  : 파이보 프로젝트를 설정합니다.

 

 

반응형
반응형

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을 걸어서 메인스레드를 멈추게 한 것입니다.

 

 

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

반응형