<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>jjinny_0609.log</title>
        <link>https://velog.io/</link>
        <description>뉴비 개발자 입니다. velog 주소 : https://velog.io/@jjinny_0609  Github 주소 :</description>
        <lastBuildDate>Fri, 26 May 2023 03:26:24 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>jjinny_0609.log</title>
            <url>https://velog.velcdn.com/images/jjinny_0609/profile/dbdfa2e5-9ee9-41bb-847a-4a3ba95970f3/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. jjinny_0609.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/jjinny_0609" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[팀 프로젝트 #2]]></title>
            <link>https://velog.io/@jjinny_0609/%ED%8C%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2</link>
            <guid>https://velog.io/@jjinny_0609/%ED%8C%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-2</guid>
            <pubDate>Fri, 26 May 2023 03:26:24 GMT</pubDate>
            <description><![CDATA[<p>라즈베리 파이 BMP085 센서를 이용한 데이터 수집</p>
<h2 id="개발-환경"><strong>개발 환경</strong></h2>
<p>mysql
vscode 원격 터미널 사용
raspberry pi
flask web framework</p>
<hr>

<h2 id="개발-과정"><strong>개발 과정</strong></h2>
<ol>
<li>라즈베리파이의 GPIO핀을 사용하여 BMP085(대기압 센서) 센서 연결</li>
<li>Flask 개발 환경 구축</li>
<li>vscode 원격 사용을 위한 환경 구축 및 라이브러리 설치</li>
<li>MySQL Connect</li>
<li>차트 생성을 위한 코드 작성</li>
<li>데이터 측정값 확인</li>
</ol>
<hr>

<h3 id="라즈베리파이의-gpio핀을-사용하여-bmp085대기압-센서-센서-연결">라즈베리파이의 GPIO핀을 사용하여 BMP085(대기압 센서) 센서 연결</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/1a21677c-c4b7-4ac6-b945-d6929fbdb62e/image.jpg" alt="">
위 그림과 같이 세팅해 주었다. 원격으로 작업하기 위해서 랜선을 연결하였고, 라즈베리파이에서 터미널을 열고 &#39;ifconfig&#39; 명령어로 아이피를 조회 후, VScode에서 Remote-SSH를 조회한 아이피를 이용해 원격으로 연결해 작업을 진행하였습니다.</p>
<hr>

<h3 id="flask-개발-환경-구축">Flask 개발 환경 구축</h3>
<p>라즈베리파이에도 VScode가 설치되어 있는 환경에서 진행함을 미리 밝힙니다.</p>
<h4 id="vscode가-미설치된-환경">VScode가 미설치된 환경</h4>
<p>VScode가 설치되어 있지 않다면 터미널을 열고 </p>
<pre><code>sudo apt install code</code></pre><p>위 명령어를 입력하면 설치가 진행될텐데 라즈베리파이 메뉴서 
&#39;개발 - CODE - OSS&#39; 를 클릭하면 실행됩니다.</p>
<p>이후 메뉴에서 File - Open Folder 클릭 이후 본인이 사용하고자 하는 폴더를 기본폴더로 지정해주시면 됩니다.</p>
<hr>

<h4 id="flask">Flask</h4>
<p><strong>_플라스크란 ? _</strong>
파이썬으로 작성된 마이크로 웹 프레임워크입니다. 마이크로 웹 프레임워크란 매우 간단하고 가벼운 웹 개발 도구를 의미합니다. 작은 규모의 웹 프로젝트나 API 서비스 등을 개발하기에 적합한 도구라 Flask를 사용하게 되었습니다.</p>
<hr>

<h4 id="flask-설치">Flask 설치</h4>
<ol>
<li>VSCode에서 터미널을 열고 _(Ctrl + `) _ d</li>
<li>파이썬 버전먼저 확인 <code>$ python -v</code>
2_1. 파이썬이 설치되어 있지 않다면.. <code>$ sudo apt update</code>
 apt 버전 업데이트 후 
  <code>$ sudo apt install python3</code>
파이썬 버전 2를 설치하려면 &#39;python3&#39;를 &#39;python2&#39;로 바꿔주시면 됩니다.</li>
<li>파이썬이 설치되어있으면 플라스크를 설치
<code>$ sudo pip install flask</code>
3_1. 간혹 설치가 되지않는 경우가 있는데 pip버전이 너무 낮아서 그런 것으므로 pip버전을 업그레이드 해주면 해결됩니다.
<code>$ sudo pip install --upgrade pip</code>
<code>$ sudo pip install flask</code>
설치가 완료되면 4. 로 이동</li>
<li>flask가 잘 설치되엇는지 확인하기 위해 flask를 import 해봅시다.
설치된 것을 확인하기 위해서 파이썬 인터프리터 실행합니다.
터미널에서 <code>$ python</code> 혹은 <code>$ python3</code>
이후 
<code>&gt;&gt;&gt; from flask import Flask</code>
위 코드를 입력했는데 아무런 메시지가 없으면 정상적으로 설치된 것 입니다.</li>
</ol>
<hr>

<h3 id="vscode-원격-사용을-위한-환경-구축-및-라이브러리-설치">vscode 원격 사용을 위한 환경 구축 및 라이브러리 설치</h3>
<p>VSCode 원격 개발을 하기 위해
사이드바의 &quot;Extensions(확장)&quot; 아이콘을 클릭합니다. 그런 다음, 검색 창에 &quot;Remote Development&quot;를 입력하여 &quot;Remote Development&quot; 확장을 찾고 설치합니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c7999095-0000-4b66-b2fc-e3f64dc0ee3e/image.png" alt=""></p>
<p>확장이 설치되면 왼쪽 사이드바의 &quot;Explorer(탐색기)&quot; 아이콘을 클릭한 다음, 상단 메뉴에서 &quot;Remote Explorer&quot;를 선택합니다. &quot;SSH Targets&quot; 섹션에서 &quot;+&quot; 아이콘을 클릭하고, 라즈베리 파이에 연결할 SSH 호스트 정보를 입력합니다.</p>
<p>라즈베리파이의 아이피를 이용해 호스트 구성 설정을 해줍니다.</p>
<hr>

<h3 id="mysql-connect">MySQL Connect</h3>
<ol>
<li>먼저, 라즈베리 파이에 MySQL을 설치합니다. 터미널에서 다음 명령어를 실행하여 MySQL을 설치합니다.<pre><code>sudo apt update
sudo apt install mysql-server
</code></pre></li>
</ol>
<pre><code>
2. MySQL 설치가 완료되면, MySQL 서버를 시작합니다.</code></pre><p>$ sudo systemctl start mysql</p>
<pre><code>
3. MySQL에 액세스하기 위해 MySQL 클라이언트를 설치합니다.</code></pre><p>sudo apt install mysql-client</p>
<pre><code>
4. Python에서 MySQL에 연결하기 위해 mysql-connector-python 라이브러리를 설치합니다. 터미널에서 다음 명령어를 실행합니다.</code></pre><p>pip install mysql-connector-python</p>
<pre><code>
5. 이제 파이썬 스크립트에서 MySQL에 연결하여 작업할 수 있습니다. 다음과 같은 코드를 작성하여 MySQL에 연결하고 쿼리를 실행하여 연결해보자.


**[connect_test.py] 작성** </code></pre><p>from flask.json import jsonify
import mysql.connector
import Adafruit_BMP.BMP085 as BMP085
import time
import threading
from flask import Flask, render_template</p>
<h1 id="mysql-서버-연결-설정mysqlconnector-모듈-사용">MySQL 서버 연결 설정(mysql.connector 모듈 사용)</h1>
<p>db = mysql.connector.connect(
    host=&#39;HOST 정보(ip)&#39;,
    user=&#39;USER 작성&#39;,
    password=&#39;PASSWORD 작성&#39;,
    database=&#39;데이터베이스명 작성&#39;
)</p>
<p>cursor = db.cursor()</p>
<h1 id="bmp180-센서-객체-생성이-센서를-통해-온도-압력-고도-값을-측정">BMP180 센서 객체 생성(이 센서를 통해 온도, 압력, 고도 값을 측정)</h1>
<p>sensor = BMP085.BMP085(busnum=1)</p>
<h1 id="flask-애플리케이션-생성">Flask 애플리케이션 생성</h1>
<p>app = Flask(<strong>name</strong>)</p>
<h1 id="서버에-값-전달">서버에 값 전달</h1>
<p>@app.route(&#39;/update_sensor_data&#39;) # 센서 데이터를 JSON 형식으로 반환
def update_sensor_data():
    temp = sensor.read_temperature()
    pressure = sensor.read_pressure()
    altitude = sensor.read_altitude()
    sensor_data = {&#39;temp&#39;: temp, &#39;pressure&#39;: pressure, &#39;altitude&#39;: altitude}
    return jsonify(sensor_data)</p>
<h1 id="루트-경로-처리">루트 경로 처리</h1>
<p>@app.route(&#39;/&#39;)
def home():
    return render_template(&#39;html/home.html&#39;)    # render_template 함수를 사용해서 HTML 파일을 렌더링</p>
<h1 id="데이터-측정-및-저장-함수-bmp180-센서를-통해-값을-측정하고-현재-시간과-함께-db에-데이터를-저장">데이터 측정 및 저장 함수 ,BMP180 센서를 통해 값을 측정하고, 현재 시간과 함께 DB에 데이터를 저장</h1>
<p>def measure_and_store_data():
    try:
        temp = sensor.read_temperature()
        pressure = sensor.read_pressure()
        altitude = sensor.read_altitude()
        timestamp = time.strftime(&#39;%Y-%m-%d %H:%M:%S&#39;)</p>
<pre><code>    # 데이터베이스에 데이터 저장
    query = &quot;INSERT INTO sensor_data(temp, pressure, altitude, timestamp) VALUES (%s, %s, %s, %s)&quot;
    values = (temp, pressure, altitude, timestamp)
    cursor.execute(query, values)
    db.commit()
    print(&quot;데이터 저장 완료&quot;)

except mysql.connector.Error as error:
    print(&quot;MySQL 예외 발생:&quot;, error)</code></pre><h1 id="초기-데이터-저장">초기 데이터 저장</h1>
<p>measure_and_store_data()</p>
<h1 id="추가적인-데이터-측정-및-저장">추가적인 데이터 측정 및 저장</h1>
<p>@app.before_first_request
def start_measurement():
    def run_measurement():
        while True:
            measure_and_store_data()
            time.sleep(5)  # 5초 간격으로 측정</p>
<pre><code>measurement_thread = threading.Thread(target=run_measurement)
measurement_thread.start()</code></pre><h1 id="flask-애플리케이션-실행">Flask 애플리케이션 실행</h1>
<p>if <strong>name</strong> == &#39;<strong>main</strong>&#39;:
    app.run(host=&#39;0.0.0.0&#39;, port=5000, debug=True)  # debug=True로 설정하면 개발 모드에서 디버그 정보가 표시</p>
<h1 id="연결-종료">연결 종료</h1>
<p>cursor.close()
db.close()</p>
<pre><code>
### 차트 생성을 위한 코드 작성
**[chart-line-demo.js] 작성**</code></pre><p>// Set new default font family and font color to mimic Bootstrap&#39;s default styling
Chart.defaults.global.defaultFontFamily = &#39;-apple-system,system-ui,BlinkMacSystemFont,&quot;Segoe UI&quot;,Roboto,&quot;Helvetica Neue&quot;,Arial,sans-serif&#39;;
Chart.defaults.global.defaultFontColor = &#39;#292b2c&#39;;</p>
<p>// Area Chart Example(기온)
var ctx = document.getElementById(&quot;myAreaChart&quot;);   // HTML 요소를 선택하여 차트를 그리는 컨텍스트
var myLineChart = new Chart(ctx, {
  type: &#39;line&#39;, // 타입 지정 : 선
  data: {
    labels: [], // 배열 x축의 레이블 값을 나타냄, 빈 배열로 설정
    datasets: [{
      label: &quot;Sessions&quot;,    // label은 데이터셋의 라벨을 지정
      lineTension: 0.3,     // lineTension은 선의 곡선 정도를 나타냄
      backgroundColor: &quot;rgba(2,117,216,0.2)&quot;,   // 그래프 영역의 배경색을 설정
      borderColor: &quot;rgba(2,117,216,1)&quot;,     // 선의 색상을 설정
      pointRadius: 5,   // 데이터 포인트 점의 크기
      pointBackgroundColor: &quot;rgba(2,117,216,1)&quot;,    // 포인트의 배경색
      pointBorderColor: &quot;rgba(255,255,255,0.8)&quot;,    // 포인트의 테두리 색
      pointHoverRadius: 5,                          // 마우스를 올렸을때 포인트의 크기
      pointHoverBackgroundColor: &quot;rgba(2,117,216,1)&quot;,   // 포인트에 마우스를 올렸을 때 배경색
      pointHitRadius: 50,   // 포인트와의 거리를 판단하는 반경
      pointBorderWidth: 2,  // 포인트의 테두리 너비
      data: [], // data배열은 초기에 빈 배열로 설정, 그래프의 실제 데이터를 담는다.
    }],
  },
  options: {    // 옵션 설정
    animation: {    // 그래프의 애니메이션 효과를 제어
      duration: 0, // 애니메이션의 지속 시간을 0으로 설정하여 애니메이션을 비활성화합니다.
    },
    scales: {   // 객체는 x축과 y축의 스케일(눈금)을 설정
      xAxes: [{ // xAxes 배열은 x축의 설정을 나타냅니다.
        time: { // x축의 시간 관련 설정을 정의
          unit: &#39;date&#39;  // x축의 레이블이 날짜 형식임을 나타냄
        },
        gridLines: {    // 객체는 그리드 라인의 표시 여부를 설정
          display: false    // false : 그리드 라인을 숨김
        },
        ticks: {    // x축의 눈금 설정을 지정
          maxTicksLimit: 7  // 표시할 최대 눈금 개수를 나타냄
        }
      }],
      yAxes: [{     // 배열의 y축 설정을 나타냄
        ticks: {    // y축의 눈금 설정을 지정
          min: 0,   // y축의 최소값
          max: 50,  // y축의 최대값
          maxTicksLimit: 10 // 표시할 최대 눈금 개수를 나타냄
        },
        gridLines: {    // y축 그리드 라인 색상을 설정
          color: &quot;rgba(0, 0, 0, .125)&quot;,
        }
      }],
    },
    legend: {
      display: false    // 범례 설정을 제어, false : 표시하지않음
    }
  }
});</p>
<p>// 함수를 정의하여 데이터 값 업데이트 및 차트 업데이트를 호출하는 부분을 만듦
function updateChart() {
  // 서버에 센서 데이터 요청을 보냄
  fetch(&#39;<a href="http://localhost:5000/update_sensor_data&#39;">http://localhost:5000/update_sensor_data&#39;</a>)
    .then(response =&gt; response.json())  // 응답 데이터를 처리
    .then(data =&gt; {
      const newData = data.temp; // 새로운 데이터
      const labels = myLineChart.data.labels;   // &#39;myLineChart.data.labels&#39;는 차트의 레이블 배열을 나타냄
      const datasetData = myLineChart.data.datasets[0].data;    // &#39;myLineChart.data.datasets[0].data&#39;는 데이터셋의 데이터 배열을 나타냄</p>
<pre><code>  // 데이터 길이를 5개로 유지하도록 제한
  if (labels.length === 5) {
    labels.shift(); // 레이블의 첫 번째 값을 제거
    datasetData.shift(); // 데이터셋의 첫 번째 값을 제거
  }

  labels.push(new Date().toLocaleTimeString()); // 현재 시간 추가
  datasetData.push(newData); // 새로운 데이터 추가

  // 차트를 업데이트합니다.
  myLineChart.update();
});</code></pre><p>}</p>
<p>// 일정한 간격으로 updateChart 함수를 호출하는 타이머를 설정 (10초마다)
// setInterval(updateChart, 500); 기존 바로 시작</p>
<p>  var stopButton = document.getElementById(&quot;stopButton&quot;);
  var startButton = document.getElementById(&quot;startButton&quot;);
  var timerId;</p>
<p>  // 정지 버튼 클릭 시 데이터 업데이트 타이머를 멈춥니다.
  stopButton.addEventListener(&quot;click&quot;, function() {
    clearInterval(timerId);
  });</p>
<p>  // 시작 버튼 클릭 시 데이터 업데이트 타이머를 다시 시작합니다.
  startButton.addEventListener(&quot;click&quot;, function() {
    timerId = setInterval(updateChart, 500);
  });</p>
<pre><code>
2개의 차트를 작동시킬 코드도 같은 방식으로 만들어 준다. 코드의 방식은 비슷하다.

**[chart-line1-demo.js] 작성** </code></pre><p>// Set new default font family and font color to mimic Bootstrap&#39;s default styling
Chart.defaults.global.defaultFontFamily = &#39;-apple-system,system-ui,BlinkMacSystemFont,&quot;Segoe UI&quot;,Roboto,&quot;Helvetica Neue&quot;,Arial,sans-serif&#39;;
Chart.defaults.global.defaultFontColor = &#39;#292b2c&#39;;</p>
<p>// Area Chart Example(고도)
var ctx = document.getElementById(&quot;myAreaChart2&quot;);
var myLineChart2 = new Chart(ctx, {
  type: &#39;line&#39;,
  data: {
    labels: [],
    datasets: [{
      label: &quot;Sessions&quot;,
      lineTension: 0.3,
      backgroundColor: &quot;rgba(2,117,216,0.2)&quot;,
      borderColor: &quot;rgba(2,117,216,1)&quot;,
      pointRadius: 5,
      pointBackgroundColor: &quot;rgba(2,117,216,1)&quot;,
      pointBorderColor: &quot;rgba(255,255,255,0.8)&quot;,
      pointHoverRadius: 5,
      pointHoverBackgroundColor: &quot;rgba(2,117,216,1)&quot;,
      pointHitRadius: 50,
      pointBorderWidth: 2,
      data: [],
    }],
  },
  options: {
    animation: {
      duration: 0, // 애니메이션의 지속 시간을 0으로 설정하여 애니메이션을 비활성화합니다.
    },
    scales: {
      xAxes: [{
        time: {
          unit: &#39;date&#39;
        },
        gridLines: {
          display: false
        },
        ticks: {
          maxTicksLimit: 7
        }
      }],
      yAxes: [{
        ticks: {
          min: -40,
          max: 40,
          maxTicksLimit: 30
        },
        gridLines: {
          color: &quot;rgba(0, 0, 0, .125)&quot;,
        }
      }],
    },
    legend: {
      display: false
    }
  }
});</p>
<p>//함수를 정의하여 데이터 값 업데이트 및 차트 업데이트를 호출하는 부분을 만듦
function updateChart2() {
  // 서버에 센서 데이터 요청을 보냄
  fetch(&#39;<a href="http://localhost:5000/update_sensor_data&#39;">http://localhost:5000/update_sensor_data&#39;</a>)
    .then(response =&gt; response.json())
    .then(data =&gt; {
      const newData = data.altitude; // 새로운 데이터
      const labels = myLineChart2.data.labels;
      const datasetData = myLineChart2.data.datasets[0].data;</p>
<pre><code>  // 데이터셋의 데이터 값을 업데이트
  if (labels.length === 5) {
    labels.shift(); // 레이블의 첫 번째 값을 제거
    datasetData.shift(); // 데이터셋의 첫 번째 값을 제거
  }

  labels.push(new Date().toLocaleTimeString()); // 현재 시간 추가
  datasetData.push(newData); // 새로운 데이터 추가

  // 빈 공간이 아닌 경우에만 차트를 업데이트합니다.
    myLineChart2.update();
});</code></pre><p>}</p>
<p>// 일정한 간격으로 updateChart 함수를 호출하는 타이머를 설정 (10초마다)
// setInterval(updateChart2, 500); 기존 바로 시작</p>
<p>  var stopButton = document.getElementById(&quot;stopButton&quot;);
  var startButton = document.getElementById(&quot;startButton&quot;);
  var timerId2;</p>
<p>  // 정지 버튼 클릭 시 데이터 업데이트 타이머를 멈춥니다.
  stopButton.addEventListener(&quot;click&quot;, function() {
    clearInterval(timerId2);
  });</p>
<p>  // 시작 버튼 클릭 시 데이터 업데이트 타이머를 다시 시작합니다.
  startButton.addEventListener(&quot;click&quot;, function() {
    timerId2 = setInterval(updateChart2, 500);
  });</p>
<pre><code>
**[chart-line2-demo.js] 작성** </code></pre><p>// Set new default font family and font color to mimic Bootstrap&#39;s default styling
Chart.defaults.global.defaultFontFamily = &#39;-apple-system,system-ui,BlinkMacSystemFont,&quot;Segoe UI&quot;,Roboto,&quot;Helvetica Neue&quot;,Arial,sans-serif&#39;;
Chart.defaults.global.defaultFontColor = &#39;#292b2c&#39;;</p>
<p>// Area Chart Example,규선
var ctx = document.getElementById(&quot;myAreaChart3&quot;);
var myLineChart3 = new Chart(ctx, {
  type: &#39;line&#39;,
  data: {
    labels: [],
    datasets: [{
      label: &quot;Sessions&quot;,
      lineTension: 0.3,
      backgroundColor: &quot;rgba(2,117,216,0.2)&quot;,
      borderColor: &quot;rgba(2,117,216,1)&quot;,
      pointRadius: 5,
      pointBackgroundColor: &quot;rgba(2,117,216,1)&quot;,
      pointBorderColor: &quot;rgba(255,255,255,0.8)&quot;,
      pointHoverRadius: 5,
      pointHoverBackgroundColor: &quot;rgba(2,117,216,1)&quot;,
      pointHitRadius: 50,
      pointBorderWidth: 2,
      data: [],
    }],
  },
  options: {
    animation: {
      duration: 0, // 애니메이션의 지속 시간을 0으로 설정하여 애니메이션을 비활성화합니다.
    },
    scales: {
      xAxes: [{
        time: {
          unit: &#39;date&#39;
        },
        gridLines: {
          display: false
        },
        ticks: {
          maxTicksLimit: 7
        }
      }],
      yAxes: [{
        ticks: {
          min: 0,
          max: 150000,
          maxTicksLimit: 10
        },
        gridLines: {
          color: &quot;rgba(0, 0, 0, .125)&quot;,
        }
      }],
    },
    legend: {
      display: false
    }
  }
});</p>
<p>//함수를 정의하여 데이터 값 업데이트 및 차트 업데이트를 호출하는 부분을 만듦
function updateChart3() {
  // 서버에 센서 데이터 요청을 보냄
  fetch(&#39;<a href="http://localhost:5000/update_sensor_data&#39;">http://localhost:5000/update_sensor_data&#39;</a>)
    .then(response =&gt; response.json())
    .then(data =&gt; {</p>
<pre><code>   // 데이터셋의 데이터 값을 업데이트
   myLineChart3.data.datasets[0].data.push(data.pressure);
   myLineChart3.data.labels.push(new Date().toLocaleTimeString()); // 현재 시간 추가

   // 데이터 길이를 5개로 유지하도록 제한
   if (myLineChart3.data.datasets[0].data.length &gt; 5) {
     myLineChart3.data.datasets[0].data.shift();
     myLineChart3.data.labels.shift();
   }

  // 차트를 업데이트합니다.
  myLineChart3.update();
});</code></pre><p>}</p>
<p>// 일정한 간격으로 updateChart 함수를 호출하는 타이머를 설정 (10초마다)
// setInterval(updateChart3, 500);</p>
<p>var stopButton = document.getElementById(&quot;stopButton&quot;);
var startButton = document.getElementById(&quot;startButton&quot;);
var timerId3;</p>
<p>// 정지 버튼 클릭 시 데이터 업데이트 타이머를 멈춥니다.
stopButton.addEventListener(&quot;click&quot;, function() {
  clearInterval(timerId3);
});</p>
<p>// 시작 버튼 클릭 시 데이터 업데이트 타이머를 다시 시작합니다.
startButton.addEventListener(&quot;click&quot;, function() {
  timerId3 = setInterval(updateChart3, 500);
});</p>
<p>```</p>
<h3 id="데이터-측정값-확인">데이터 측정값 확인</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/a9946ff6-0faf-4aa4-b00d-d972f148eb80/image.png" alt=""></p>
<h3 id="프로젝트-완성본"><strong>프로젝트 완성본</strong></h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/ac4a96d8-3093-46be-93b5-f21ddb9b5600/image.gif" alt=""></p>
<h3 id="erd">ERD</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/0f137b89-c072-4648-abd3-d8474b8e141e/image.png" alt=""></p>
<h3 id="mysql에-저장된-값-조회">MYSQL에 저장된 값 조회</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/41d4e361-1bb4-4b80-93df-890f1c19519e/image.png" alt=""></p>
<p>프로젝트를 진행하면서 아쉬웠던 점은 애플 워치를 사용하여 나의 심박수를 실시간으로 조회하는 기능을 구현하지 못한 것입니다. 이 기능은 원하였으나, 제한된 시간과 예비군 훈련까지 겹쳐 구현하지 못한 점이 아쉬웠습니다.</p>
<p>그래도 맥북을 사서 스위프트를 경험해볼 수 있어서 좋았음..!</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[SNS 로그인 구현 # 팀 프로젝트]]></title>
            <link>https://velog.io/@jjinny_0609/%ED%8C%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-SNS-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84</link>
            <guid>https://velog.io/@jjinny_0609/%ED%8C%80-%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-SNS-%EB%A1%9C%EA%B7%B8%EC%9D%B8-%EA%B5%AC%ED%98%84</guid>
            <pubDate>Tue, 09 May 2023 07:16:55 GMT</pubDate>
            <description><![CDATA[<p>*<em>팀 프로젝트 *</em>
MVC모델을 이용한 SNS 로그인(네이버,구글,카카오) 구현</p>
<p>본인은 구글 부분을 맡아서 처리했습니다.
다 만들고 작성하는거라 틀린 부분이 있을수도 있으니 참고만 부탁드립니다.</p>
<p>참고 문서
<a href="https://developers.google.com/identity/gsi/web/guides/overview?hl=ko">https://developers.google.com/identity/gsi/web/guides/overview?hl=ko</a></p>
<p><a href="https://developers.google.com/identity/protocols/oauth2/web-server?hl=ko#httprest_5">https://developers.google.com/identity/protocols/oauth2/web-server?hl=ko#httprest_5</a></p>
<p>구글 HTML 통합 코드 생성
<a href="https://developers.google.com/identity/gsi/web/tools/configurator?hl=ko">https://developers.google.com/identity/gsi/web/tools/configurator?hl=ko</a></p>
<h2 id="개발환경-및-maven-빌드">개발환경 및 Maven 빌드</h2>
<p>java 1.8
spring framework 5.0.7
mysql, mybatis 1.3.2, HikariCP 2.7.4
Apache Tomcat 8.5
Oauth 2.0</p>
<h2 id="구글-로그인-전체적인-흐름">구글 로그인 전체적인 흐름</h2>
<p><strong>google login_sequence diagram</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/24323d7a-ae02-480c-b6cf-97d691e30113/image.png" alt=""></p>
<h2 id="로그인을-구현하는-절차">로그인을 구현하는 절차</h2>
<ol>
<li>구글 API Console에서 프로젝트 생성 및 프로젝트 생성</li>
<li>Maven을 사용하여 프로젝트에 OAuth 라이브러리 및 의존성 추가</li>
<li>로그인 버튼 생성 및 인증 요청 처리</li>
<li>모델(Model) 작성 - 데이터베이스와 연동하여 구글에서 받아온 데이터를 처리하기 위해서 만듦</li>
<li>서비스(Service) 작성 - 프로젝트에 필요한 OAuth 스코프를 정의합니다. (스코프는 OAuth 클라이언트에서 요청할 수 있는 권한의 범위를 지정하는 것)</li>
<li>매퍼(Mapper) 작성 - 데이터베이스와 연동을 담당</li>
<li>뷰(View) 작성 - 인터페이스를 위한 페이지를 만듦 HTML, JSP, Thymeleaf 등의 템플릿 엔진을 이용하여 작성</li>
<li>컨트롤러 작성(Controller) - 클라이언트의 요청을 처리하고 서비스 호출결과를 반환, </li>
</ol>
<hr>

<h3 id="1-구글-api-console에서-프로젝트-생성-및-프로젝트-생성">1. 구글 API Console에서 프로젝트 생성 및 프로젝트 생성</h3>
<p><a href="https://console.developers.google.com">https://console.developers.google.com</a>
해당 링크로 들어가 왼쪽 탭에 &#39;<strong>사용자 인증정보</strong>&#39; 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5c3a5c6a-8a62-4487-9ee2-072109f722f0/image.png" alt=""></p>
<p>글쓴이는 이미 만들어둔 상태라 아래와 같은 화면이다. &#39;<strong>사용자 인증 정보 만들기</strong>&#39; 클릭</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/7c441970-cd60-4ab8-9ca5-b95458284f3c/image.png" alt=""></p>
<p><strong>OAuth 클라이언트 ID</strong> 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bc9ca187-9843-4dde-9aad-d5d0c74db024/image.png" alt=""></p>
<p>본인에게 맞는 유형 클릭
글쓴이는 &#39;<strong>웹 애플리케이션</strong>&#39;이므로 웹 애플리케이션 선택함
<img src="https://velog.velcdn.com/images/jjinny_0609/post/485b2f48-c57a-4540-bad5-72c3d6bec2d1/image.png" alt=""></p>
<p>설정은 아래와 같이 하거나 본인에게 맞는 설정을 해주자.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4bca56bf-9140-43a1-b1b4-4bcfacc168d7/image.png" alt=""></p>
<p>생성이 완료되면 다음과 같은 창이 나타난다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/7bcaddd3-35e3-4d6c-87d1-54d6d6e4727c/image.png" alt=""></p>
<p>클라이언트 ID와 클라이언트 보안 비밀번호는 자주 쓰이니 따로 기록하거나 즐겨찾기로 자주 보는걸 추천합니다.</p>
<h4 id="프로젝트-생성sts툴-사용"><strong>프로젝트 생성(STS툴 사용)</strong></h4>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/4a692041-86d6-4143-b8c5-6507ba40f5d3/image.png" alt="">
View 와 Controller 부분은 필요한 기능이 있으면 따로 추가해주세요.</p>
<hr>

<h3 id="maven을-사용하여-프로젝트에-oauth-라이브러리-및-의존성-추가">Maven을 사용하여 프로젝트에 OAuth 라이브러리 및 의존성 추가</h3>
<p>pom.xml에 다음과 같이 의존성 추가</p>
<pre><code>        &lt;!-- http client(구글)--&gt;
        &lt;dependency&gt;
          &lt;groupId&gt;com.google.api-client&lt;/groupId&gt;
          &lt;artifactId&gt;google-api-client&lt;/artifactId&gt;
          &lt;version&gt;1.31.3&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;!-- https://mvnrepository.com/artifact/com.google.http-client/google-http-client-jackson2 --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;com.google.http-client&lt;/groupId&gt;
            &lt;artifactId&gt;google-http-client-jackson2&lt;/artifactId&gt;
            &lt;version&gt;1.31.0&lt;/version&gt;
        &lt;/dependency&gt;

        &lt;!-- https://mvnrepository.com/artifact/org.thymeleaf/thymeleaf --&gt;
        &lt;dependency&gt;
            &lt;groupId&gt;org.thymeleaf&lt;/groupId&gt;
            &lt;artifactId&gt;thymeleaf&lt;/artifactId&gt;
            &lt;version&gt;3.0.11.RELEASE&lt;/version&gt;
        &lt;/dependency&gt;</code></pre><hr>

<h3 id="로그인-버튼-생성-및-인증-요청-처리">로그인 버튼 생성 및 인증 요청 처리</h3>
<p>home.jsp (view 부분)</p>
<pre><code>&lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot; %&gt;
// 최상단에 넣기

&lt;c:url value=&quot;/oauth2/google/login&quot; var=&quot;googleOAuthUrl&quot; /&gt;
&lt;a href=&quot;${googleOAuthUrl}&quot;&gt;&lt;img src=&quot;구글 버튼 이미지 경로&quot; class=&quot;social-icon&quot; id=&quot;google&quot;&gt;&lt;/a&gt;
</code></pre><hr>

<h3 id="모델model-작성">모델(Model) 작성</h3>
<p><strong>GoogleProfile.jsp</strong></p>
<pre><code>package com.tit.model;

public class GoogleProfile {
    private String email;
    private String nickname;
    private String id;
    private String sns;

    public GoogleProfile() {
    }

    public GoogleProfile(String email, String nickname, String id) {
        this.email = email;
        this.nickname = nickname;
        this.id = id;
        this.sns = &quot;google&quot;;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getNickname() {
        return nickname;
    }

    public void setNickname(String nickname) {
        this.nickname = nickname;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getSns() {
        return sns;
    }

    public void setSns(String sns) {
        this.sns = sns;
    }

    @Override
    public String toString() {
        return &quot;UserProfile [email=&quot; + email + &quot;, nickname=&quot; + nickname + &quot;, sns=&quot; + sns + &quot;]&quot;;
    }

}
</code></pre><hr>


<h3 id="서비스service-작성">서비스(Service) 작성</h3>
<p><strong>GoogleLoginBO 작성</strong></p>
<pre><code>package 본인 패키지명;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Arrays;

import javax.servlet.http.HttpSession;

import org.springframework.stereotype.Service;

import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;

@Service // @Service로 주석 처리된 서비스 클래스로 Spring 서비스 구성 요소임을 나타냅니다.
public class GoogleLoginBO {
    /* 인증 요청문을 구성하는 파라미터 */
    // client_id: 애플리케이션 등록 후 발급받은 클라이언트 아이디
    // client_secret : 애플리케이션 등록 후 발급받은 클라이언트 시크릿
    // redirect_uri: 로그인 인증의 결과를 전달받을 콜백 URL(URL 인코딩). 애플리케이션을 등록할 때 Callback URL에 설정한 정보입니다.
    // SCOPE = 요청할 권한의 범위를 지정하는 값입니다. 구글 API에 따라 다르게 설정할 수 있습니다.

    private static final HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private final static String CLIENT_ID = &quot;본인 클라이언트 아이디&quot;;
    private final static String CLIENT_SECRET = &quot;본인 클라이언트 시크릿&quot;;
    private final static String REDIRECT_URI = &quot;http://localhost:8080/oauth2/google/callback&quot;;
    private final static String SCOPE = &quot;openid email profile&quot;;    // 요청할 권한의 범위

    private GoogleAuthorizationCodeFlow getGoogleAuthorizationCodeFlow() {
        GoogleClientSecrets.Details web = new GoogleClientSecrets.Details();
        web.setClientId(CLIENT_ID);
        web.setClientSecret(CLIENT_SECRET);

        GoogleClientSecrets clientSecrets = new GoogleClientSecrets().setWeb(web);

        return new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets,Arrays.asList(SCOPE.split(&quot; &quot;))).setAccessType(&quot;offline&quot;).setApprovalPrompt(&quot;force&quot;).build();
    }

    public String getAuthorizationUrl(HttpSession session) {
        GoogleAuthorizationCodeFlow flow = getGoogleAuthorizationCodeFlow();
        String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).build();
//        String url = flow.newAuthorizationUrl().setRedirectUri(REDIRECT_URI).setState(&quot;state&quot;).build();    // state는 CSRF 공격을 방지하려면 작성
        return url;
    }

    public String[] getUserProfile(String authCode) throws IOException {
        GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(HTTP_TRANSPORT, JSON_FACTORY,
                CLIENT_ID, CLIENT_SECRET, authCode, REDIRECT_URI).execute();

        GoogleIdToken idToken = tokenResponse.parseIdToken();
        GoogleIdToken.Payload payload = idToken.getPayload();

        String email = payload.getEmail();
        String name = (String) payload.get(&quot;name&quot;);
        String id = payload.getSubject();

        return new String[]{email, name, id};
    }

 // 회원 탈퇴
        public void revokeToken(String accessToken) throws IOException {    // 사용자의 액세스 토큰을 취소
            URL url = new URL(&quot;https://oauth2.googleapis.com/revoke?token=&quot; + accessToken);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            conn.setRequestMethod(&quot;POST&quot;);
            conn.getResponseCode(); // 응답 코드를 읽어야 API 요청이 발생합니다.
        }    
}</code></pre><br>

<p><strong>GoogleProfileService 작성</strong> </p>
<pre><code>package 본인 패키지명;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import 본인 패키지명.GoogleMapper;
import 본인 패키지명.GoogleProfile;

@Service
public class GoogleProfileService {
    @Autowired
    private GoogleMapper googleMapper;

    public void addUserProfile(GoogleProfile googleProfile) {
        googleMapper.insertUserProfile(googleProfile);
    } // GoogleProfile 객체를 가져와 googleMapper의 insertUserProfile 메서드를 사용하여 데이터베이스에 삽입

    public int findUserProfileByEmail(String email) {
        return googleMapper.findByEmail(email);
    } // 이메일 주소를 매개변수로 받아 findByEmail 메서드를 사용하여 해당 이메일로 등록된 사용자 프로필 수를 반환하는 public 메서드입니다. 데이터베이스에 이미 해당 사용자 프로필이 있는지 확인할때 사용

    public void delUserProfile(GoogleProfile delProfile) {
        googleMapper.delUserProfile(delProfile);
        // 회원탈퇴 -&gt; DB에 있는 회원 삭제
    } // GoogleProfile 객체를 가져와 googleMapper의 delUserProfile 메서드를 사용하여 데이터베이스에서 해당 사용자 프로필을 삭제
}</code></pre><h3 id="매퍼mapper-작성">매퍼(Mapper) 작성</h3>
<p><strong>GoogleMapper.java 작성</strong></p>
<pre><code>package 본인 패키지명;

import 본인 패키지명.GoogleProfile;

public interface GoogleMapper {
    void insertUserProfile(GoogleProfile googleProfile); // GoogleProfile 객체를 DB에 삽입(insert)하는 메소드
    int findByEmail(String email);

    void delUserProfile(GoogleProfile delProfile);
    // int로 설정한 이유는 삭제된 행의 수를 반환하기 위해서입니다.
    // MyBatis에서는 INSERT, UPDATE, DELETE와 같은 쓰기 작업을 수행할 때 영향을 받은 행의 수를 반환합니다. 이렇게 함으로써, 호출자가 해당 작업이 실제로 수행되었는지 확인할 수 있습니다.
    // 예를 들어, deleteUserProfile 메소드를 호출한 후 반환된 값이 1이면 한 명의 사용자가 삭제된 것을 알 수 있습니다. 반면, 반환된 값이 0이면 이메일 주소와 일치하는 사용자가 없어 삭제되지 않았음을 알 수 있습니다. 
    // 이를 통해 오류를 처리하거나 로깅 목적으로 사용할 수 있습니다.
    String checksns(String email);
    // 이메일 주소를 입력받아 해당 이메일 주소와 연동된 SNS 계정이 있는지 조회(select)하는 메소드입니다. 반환값은 SNS 계정이 존재한다면 해당 SNS 계정 종류를 문자열(String)로 반환하고, 존재하지 않으면 null을 반환
}</code></pre><br>

<p><strong>GoogleMapper.xml 작성</strong></p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;

    &lt;mapper namespace=&quot;com.tit.mapper.GoogleMapper&quot;&gt;
    &lt;insert id=&quot;insertUserProfile&quot; parameterType=&quot;com.tit.model.GoogleProfile&quot;&gt;
        INSERT INTO member (id, email, nickname, sns)
        VALUES (#{id}, #{email}, #{nickname}, #{sns})
    &lt;/insert&gt;

    &lt;select id=&quot;findByEmail&quot; parameterType=&quot;String&quot; resultType=&quot;int&quot;&gt;
        SELECT COUNT(*) FROM member
        WHERE email = #{email}
    &lt;/select&gt;

    &lt;delete id=&quot;delUserProfile&quot;&gt;
        DELETE FROM member WHERE email = #{email}
    &lt;/delete&gt;

    &lt;select id=&quot;checksns&quot; parameterType=&quot;string&quot; resultType=&quot;string&quot;&gt;
        SELECT sns FROM member WHERE email = #{email};
    &lt;/select&gt;
&lt;/mapper&gt;</code></pre><hr>

<h3 id="뷰view-작성">뷰(View) 작성</h3>
<p>본인은 아래와 같이 파일을 구성했다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/0c2314de-a139-444e-914e-79bf5ca1e9f2/image.png" alt=""></p>
<p>파일별로 기능을 정리해보자면</p>
<p>findpassword : 비밀번호 찾기 페이지
home : 홈페이지 가장 첫화면(여기에 SNS로그인을 넣음)
Medical : 로그인 후 도착하는 페이지
MemberJoin : 아이디가 없는 회원이 회원 가입했을때 오는 페이지</p>
<h3 id="컨트롤러-작성controller">컨트롤러 작성(Controller)</h3>
<p><strong>GoogleController.java 작성</strong></p>
<pre><code>package com.tit.app;

import java.io.IOException;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

import com.tit.mapper.GoogleMapper;
import com.tit.model.GoogleProfile;
import com.tit.service.GoogleLoginBO;
import com.tit.service.GoogleProfileService;

@Controller
public class GoogleLoginController {

    // GoogleLoginBO, GoogleProfileService, GoogleMapper @Autowired를 이용해 의존성 주입
    // Google OAuth2 인증, Google 프로필 정보를 DB에 CRUD 작업, Google 프로필 정보를 DB에 저장하는 데 사용
    @Autowired
    private GoogleLoginBO googleLoginBO;

    @Autowired
    private GoogleProfileService googleProfileService;

    @Autowired
    private GoogleMapper googleMapper;

    // GET /oauth2/google/login 요청이 들어오면, GoogleLoginBO를 이용하여 구글 로그인 URL을 생성
    // 이를 포함한 redirect 응답을 보냄 이 과정을 통해 사용자는 구글 계정으로 로그인
    @GetMapping(&quot;/oauth2/google/login&quot;)
    public String login(HttpSession session) {
        String googleAuthorizationUrl = googleLoginBO.getAuthorizationUrl(session);
        return &quot;redirect:&quot; + googleAuthorizationUrl;
    } 

    // REDIRECT_URI /oauth2/google/callback
    // GET /oauth2/google/callback 요청이 들어오면, GoogleLoginBO를 이용하여 사용자의 access token을 받아
    // getUserProfile 메소드를 이용하여 access token으로부터 사용자의 이메일, 이름, ID 등의 정보를 받아옵니다. 
    // 받아온 정보를 바탕으로 GoogleProfile 객체를 생성
    @RequestMapping(&quot;/oauth2/google/callback&quot;)    // 이부분 유효한지 확인
    public String callback(@RequestParam(&quot;code&quot;) String authCode, HttpSession session) throws IOException {
        String[] userProfileData = googleLoginBO.getUserProfile(authCode);
        String email = userProfileData[0];
        String name = userProfileData[1];
        String id = userProfileData[2];

        GoogleProfile userProfile = new GoogleProfile(email, name, id);

        int count = googleProfileService.findUserProfileByEmail(userProfile.getEmail());
        if(count &gt; 0) {
            session.setAttribute(&quot;UserProfile&quot;, userProfile);
            session.setAttribute(&quot;oauthToken&quot;, authCode);
            session.setAttribute(&quot;googleNickname&quot;, name);
            String snsid = googleMapper.checksns(email);
            session.setAttribute(&quot;Snsid&quot;, snsid);
            System.out.println(snsid);    //test
            return &quot;redirect:/Medical&quot;;
        } else {
            googleProfileService.addUserProfile(userProfile);
            session.setAttribute(&quot;UserProfile&quot;, userProfile);
            session.setAttribute(&quot;googleNickname&quot;, name);
            String snsid = googleMapper.checksns(email);
            session.setAttribute(&quot;Snsid&quot;, snsid);
            return &quot;redirect:/MemberJoin&quot;;
        }
    }

    // 로그아웃
    // /oauth2/google/logout 요청이 들어오면, 세션을 초기화하고, 
    // 홈 화면으로 redirect 합니다 이 과정을 통해 사용자는 로그아웃 할 수 있다.
    @RequestMapping(value = &quot;/oauth2/google/logout&quot;, method = { RequestMethod.GET, RequestMethod.POST })
    public String logout(HttpSession session) throws IOException {
        session.invalidate();
        return &quot;redirect:/&quot;;
    }

    // 회원 탈퇴
    // GET /oauth2/google/account_rm 요청이 들어오면 
    // GoogleProfileService의 delUserProfile 메소드를 호출하여 DB에서 해당 사용자 정보를 삭제
    // GoogleLoginBO의 revokeToken 메소드를 호출하여 access token을 폐기합니다. 세션을 초기화하고, 홈 화면으로 redirect 한다.
    // 이 과정을 통해 사용자는 회원 탈퇴를 할 수 있다.
    @RequestMapping(value = &quot;/oauth2/google/acount_rm&quot;, method = { RequestMethod.GET, RequestMethod.POST })
    public String revokeAccessToken(HttpSession session) throws IOException {

        String oauthToken = (String) session.getAttribute(&quot;oauthToken&quot;);
        GoogleProfile delProfile = (GoogleProfile) session.getAttribute(&quot;UserProfile&quot;);

        System.out.println(oauthToken);
        System.out.println(delProfile);

        googleProfileService.delUserProfile(delProfile);
        googleLoginBO.revokeToken(oauthToken);
        session.invalidate();
        return &quot;redirect:/&quot;;
    }
}
</code></pre><hr>

<p>spring security를 사용하지 못한게 아쉬웠던 프로젝트 입니다.
다음번에는 공부해서 security를 적용해보고 싶네요..
이상으로 OAuth2를 이용한 SNS구글 로그인을 마치도록 하겠습니다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Lombok(롬복) 설치해서 사용하기]]></title>
            <link>https://velog.io/@jjinny_0609/Lombok%EB%A1%AC%EB%B3%B5-%EC%84%A4%EC%B9%98%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jjinny_0609/Lombok%EB%A1%AC%EB%B3%B5-%EC%84%A4%EC%B9%98%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 17 Apr 2023 03:41:57 GMT</pubDate>
            <description><![CDATA[<h3 id="롬복-설치하기">롬복 설치하기</h3>
<ol>
<li><a href="https://projectlombok.org/download">https://projectlombok.org/download</a></li>
</ol>
<p>해당 경로로 이동해서 아래와 같은 버튼 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5fe602c2-8b5d-4966-8c28-b199ade02641/image.png" alt=""></p>
<ol start="2">
<li>파일을 다운받아 이클립스가 설치된 경로에 lombok.jar을 붙여넣기
<img src="https://velog.velcdn.com/images/jjinny_0609/post/cff4adb7-c82a-4661-a010-2ea341a0632a/image.png" alt=""></li>
</ol>
<p>※ 경로에 한글이 없도록 주의하도록 하자.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/68d851a0-2e84-4ae0-baa2-ea68e671855b/image.png" alt=""></p>
<p>만약 오류가 뜨면서 경로를 찾을 수 없다고 뜨면 Specify location... 으로 경로를 직접 지정해주자</p>
<p>경로를 지정했다면 Install / Update를 눌러서 설치
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ed2f1663-0033-4203-8269-029750e464ed/image.png" alt=""></p>
<p>다음과 같은 화면이 나오면 설치가 완료된것이다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f98fa90e-c35a-46b4-a45a-58650e3a9f9a/image.png" alt=""></p>
<hr>

<h3 id="maven을-이용한-lombok-적용하기">Maven을 이용한 Lombok 적용하기</h3>
<p>해당 프로젝트의 pom.xml에 dependency 추가해주자.
version사이에는 본인 해당하는 버전을 넣어주자.</p>
<pre><code>&lt;dependency&gt;
    &lt;groupId&gt;org.projectlombok&lt;/groupId&gt;
    &lt;artifactId&gt;lombok&lt;/artifactId&gt;
    &lt;version&gt;1.18.26&lt;/version&gt;
    &lt;scope&gt;provided&lt;/scope&gt;
&lt;/dependency&gt;</code></pre><hr>

<h3 id="lombok을-이용해보기">Lombok을 이용해보기</h3>
<p>Lombok을 사용하여 간단한 모델 클래스를 만드는 예제</p>
<pre><code>import lombok.Data;

@Data
public class User {
    private Long id;
    private String firstName;
    private String lastName;
    private String email;
}</code></pre><p>위의 예제에서 @Data 어노테이션을 사용하면 id, firstName, lastName, email 필드에 대한 getter와 setter, toString, equals, hashCode 메소드를 자동으로 생성할 수 있습니다.</p>
<p>위의 예제에서 @Data 어노테이션을 사용하면 id, firstName, lastName, email 필드에 대한 getter와 setter, toString, equals, hashCode 메소드를 자동으로 생성할 수 있습니다.</p>
<p>아래는 Lombok을 사용하여 Builder 패턴을 적용한 예제입니다.</p>
<pre><code>import lombok.Builder;
import lombok.Data;

@Data
@Builder
public class User {
    private Long id;
    private String firstName;
    private String lastName;
    private String email;
}
</code></pre><p>위의 예제에서 @Builder 어노테이션을 사용하면 User 객체를 생성할 때 Builder 패턴을 사용할 수 있습니다.</p>
<pre><code>User user = User.builder()
        .id(1L)
        .firstName(&quot;John&quot;)
        .lastName(&quot;Doe&quot;)
        .email(&quot;john.doe@example.com&quot;)
        .build();</code></pre><p>이렇게 하면 User 객체를 생성하면서 값을 설정할 수 있습니다. 또한, @Data 어노테이션을 사용하여 자동으로 getter와 setter, toString, equals, hashCode 메소드를 생성할 수 있습니다.</p>
<p>기능과 API에 관한건 아래의 링크를 참고해주세요.
<a href="https://projectlombok.org/features/">https://projectlombok.org/features/</a></p>
<p><a href="https://projectlombok.org/api/">https://projectlombok.org/api/</a></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[DB 서버로 연결해서 사용하기 #팀프로젝트]]></title>
            <link>https://velog.io/@jjinny_0609/DB-%EC%84%9C%EB%B2%84%EB%A1%9C-%EC%97%B0%EA%B2%B0%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</link>
            <guid>https://velog.io/@jjinny_0609/DB-%EC%84%9C%EB%B2%84%EB%A1%9C-%EC%97%B0%EA%B2%B0%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%ED%8C%80%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8</guid>
            <pubDate>Mon, 17 Apr 2023 03:20:34 GMT</pubDate>
            <description><![CDATA[<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/f9b0b441-4e03-4129-9326-3a4258b75818/image.png" alt="">
root-context에서 localhost로 사용하고 있기 때문에 본인만 사용가능함.. </p>
<p>CMD에서 ifconfig로 본인의 IP주소를 알아오자.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f1d362b4-2f9a-4327-a30e-768a7ea200f9/image.png" alt="">
Mysql 홈화면(왼쪽 상단 홈버튼)에서 MySQL Connections +버튼 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4f485eb0-f9c1-44df-8c35-5167f2b54f5c/image.png" alt="">
Connection Name 작성
Hostname : ipconfig에서 나온 본인의 아이피주소 작성
Username : 본인 원하는 name 작성 후 OK버튼 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/0c584624-20b8-46fb-98df-cfb53ddf1c8f/image.png" alt=""></p>
<p>Navigator - <strong>MANAGEMENT</strong> - administration - Users and privileges
<img src="https://velog.velcdn.com/images/jjinny_0609/post/7a7dcc21-67ce-4272-8bc7-694d68a09215/image.png" alt=""></p>
<p>Add Account 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e0e26332-b430-4a1e-96a0-c16272f58500/image.png" alt=""></p>
<p>Login name : 본인 원하는 name
Limit to Hosts Matching : 데이터 베이스 권한을 선택하는 부분
(Confirm)Password : 패스워드 입력, 패스워드 확인
설정 다하고 Apply
<img src="https://velog.velcdn.com/images/jjinny_0609/post/84b1564a-743b-499f-b9d3-e23c07a70ab3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/ab8fc660-e1f0-4397-b38f-0c32e8005855/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/241de3b6-09b1-46ec-a22b-60776879243d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/6b7a4890-1a32-402f-b09d-d041c329d426/image.png" alt="">
권한을 지정해 해당 권한만 수정할 수 있도록 체크후 APPLY 하면 설정 끝</p>
<p>아래 부분에 root-context에 본인이 작성한 설정으로 바꿔주면 끝</p>
<pre><code>&lt;bean id=&quot;hikariConfig&quot; class=&quot;com.zaxxer.hikari.HikariConfig&quot;&gt;
        &lt;property name=&quot;driverClassName&quot; value=&quot;com.mysql.jdbc.Driver&quot;&gt;&lt;/property&gt;
        &lt;property name=&quot;jdbcUrl&quot; value=&quot;jdbc:mysql://HOSTNAME(ip):3306(포트번호)/kakao(Database name)?serverTimezone=Asia/Seoul&quot;&gt;&lt;/property&gt;
        &lt;property name=&quot;username&quot; value=&quot;아이디&quot;&gt;&lt;/property&gt;
        &lt;property name=&quot;password&quot; value=&quot;패스워드&quot;&gt;&lt;/property&gt;
&lt;/bean&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[정보처리기사 실기 #디자인패턴]]></title>
            <link>https://velog.io/@jjinny_0609/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4</link>
            <guid>https://velog.io/@jjinny_0609/%EC%A0%95%EB%B3%B4%EC%B2%98%EB%A6%AC%EA%B8%B0%EC%82%AC-%EC%8B%A4%EA%B8%B0-%EB%94%94%EC%9E%90%EC%9D%B8%ED%8C%A8%ED%84%B4</guid>
            <pubDate>Sun, 16 Apr 2023 08:36:25 GMT</pubDate>
            <description><![CDATA[<h4 id="--creational-patterns생성패턴"><strong>- Creational Patterns(생성패턴)</strong></h4>
<p>객체를 생성하는 방법을 추상화하여 객체를 생성, 조합 및 표현하는 방법을 정의한다. 패턴의 생성과 초기화를 다루기 때문에, 프로그램의 유지 보수성과 확장성을 향상시키는데 도움이 된다.</p>
<ul>
<li><p><strong>Singleton(싱글톤)</strong> :  전역 변수를 사용하지 않고 단 하나의 인스턴스를 생성하고, 이를 통해 접근하도록 하는 패턴
클래스의 인스턴스가 오직 하나만 존재하도록 보장하고, 다른 객체들이 해당 인스턴스에 접근할 수 있도록 한다.</p>
</li>
<li><p><strong>Factory Method(팩토리 메서드)</strong> : 객체를 생성하는 인터페이스를 정의하고, 이를 서브 클래스에서 구현하여 객체 생성을 캡슐화하는 패턴
객체 생성을 하위클래스에서 위임함으로써, 객체 생성에 대한 유연성을 높이고 객체 생성 코드를 중앙 집중화한다.</p>
</li>
<li><p><strong>Abstract Factory(추상 팩토리)</strong> : 관련된 객체들의 집합을 생성하는 인터페이스를 제공하는 패턴이다.
객체들의 생성과 조합을 추상화하여, 서로 다른 구현 클래스를 사용해 다양한 종류의 객체들을 생성할 수 있도록 한다.</p>
</li>
<li><p><strong>Builder(빌더)</strong> : 복잡한 객체를 생성하는 과정을 단순화하기 위해 사용되는 패턴이다.
객체를 생성하는 과정을 단계별로 분리하여, 여러 단계에서 객체를 생성하고 초기화할 수 있다.</p>
</li>
<li><p><strong>Prototype(프로토타입)</strong> : 이미 존재하는 객체를 복제함으로써 새로운 객체를 생성하고 초기화화는 과정을 간소화 하는 패턴이다.</p>
<hr>

</li>
</ul>
<h4 id="--structural-patterns-구조-패턴"><strong>- Structural Patterns (구조 패턴)</strong></h4>
<p>객체와 클래스 간의 관계를 다룬다. 이런 패턴은 다른 객체들 과의 관계, 즉 상속이나 인터페이스 구현 등을 통해 클래스를 조합하여 더 복잡한 구조를 만들 수 있다.</p>
<ul>
<li><p><strong>Adapter(어댑터)</strong> : 호환되지 않는 인터페이스들을 함께 동작할 수 있도록 변환하는 패턴이다. 서로 다른 인터페이스를 가진 두 객체 사이에서 인터페이스를 중간에 삽입해 두 객체가 함께 동작할 수 있도록 한다.</p>
</li>
<li><p><strong>Bridge(브릿지)</strong> : 추상화와 구현을 분리하여 서로 독립적으로 확장할 수 있는 구조를 만드는 패턴이다. 구현부와 추상화 부분을 서로 분리함으로써, 서로 다른 구현체를 자유롭게 조합할 수 있다.</p>
</li>
<li><p><strong>Composite(컴포지트)</strong> : 객체들의 계층 구조를 포현하는 패턴
단일 객체와 복합 객체를 동일한 인터페이스로 다룰 수 있도록 하여, 객체의 계층구조를 표현하고 트리 구조를 만들 수 있다.</p>
</li>
<li><p><strong>Decorator(데코레이터)</strong> : 객체에 새로운 기능을 동적으로 추가할 수 있도록 하는 패턴이다.
객체의 코어 기능을 변경하지 않고, 새로운 동작을 추가하여 객체의 기능을 확장한다.</p>
</li>
<li><p><strong>Facade(퍼사드)</strong> : 복잡한 시스템에 대한 단순화된 인터페이스를 제공하는 패턴이다.
복잡한 시스템의 일부분을 숨기고, 사용자에게 간단한 인터페이스만 노출시켜서 사용자가 더 쉽게 시스템을 사용할 수 있도록 한다.</p>
</li>
<li><p><strong>Flyweight(플라이웨이트)</strong> : 객체를 공유하여 메모리 사용량을 최소화하는 패턴이다.
동일한 객체를 여러 개 생성하지 않고, 객체를 공유하여 메모리 사용량을 줄일 수 있다.</p>
</li>
<li><p><strong>Proxy(프록시)</strong> : 다른 객체에 대한 대리자나 자리채움 역할을 하는 패턴이다.
객체에 대한 접근을 제어하거나, 객체의 생성과 초기화를 지연시켜 성능을 개선할 수 있다.</p>
</li>
</ul>
<hr>

<h4 id="--behavioral-patterns행동-패턴"><strong>- Behavioral Patterns(행동 패턴)</strong></h4>
<p>객체들이 서로 상호작용하는 방법과 역할을 중심으로 다루는 패턴이다. 이러한 패턴은 객체들 간의 행동과 상호작용을 조정하여, 시스템을 보다 유연하고 확장 가능하도록 만든다.</p>
<p><strong>- Chain of Responsibility(책임 연쇄)</strong> : 요청을 처리할 객체들의 연결(체인)을 만들어 처리할 객체를 동적으로 지정하는 패턴이다. 요청을 처리할 객체가 결정되지 않은 경우, 체인의 다음 객체에게 요청을 전달하여 요청을 처리한다.</p>
<p>*<em>- Command(커맨드) *</em>: 요청을 객체의 형태로 캡슐화하여 실행할 수 있는 패턴이다.
실행할 요청을 객체화함으로써, 요청을 처리할 수 있는 여러 객체들과 요청을 분리하여 실행할 수 있다.</p>
<p>*<em>- Interpreter(인터프리터) *</em> : 문법 규칙을 클래스화하여 처리하는 패턴이다.
문법 규칙을 객체로 나타내고, 이를 해석하여 실행하는 방식으로 동작한다.</p>
<p>*<em>- Iterator(이터레이터) *</em> : 집합체(컬렉션) 내부의 요소들을 순차적으로 접근하는 패턴이다.
집합체의 내부 구조를 노출하지 않으면서, 집합체 내부의 요소들에 접근할 수 있다.</p>
<p><strong>- Mediator(미디에이터)</strong> : 객체들 간의 복잡한 상호작용을 캡슐화하여 객체들 간의 결합도를 낮추는 패턴이다.
중재자 역할을 하는 객체를 이용하여, 객체들 간의 직접적인 상호작용을 줄여서 객체들 간의 결합도를 낮출 수 있다.</p>
<p><strong>- Memento(메멘토)</strong> : 객체의 상태 정보를 저장하고, 이를 복원하는 패턴이다.
객체의 상태를 저장하고, 이를 복원하여 객체의 이전 상태로 돌아갈 수 있다.</p>
<p><strong>- Observer(옵저버)</strong> : 객체들 간의 일대다 의존성 관계를 정의하는 패턴이다.
한 객체의 상태 변화에 대해 다수의 객체에게 자동으로 알리며, 객체 간의 결합도를 낮출 수 있다.</p>
<p><strong>- State(상태)</strong> : 객체의 내부 상태에 따라 행동을 변경하는 패턴이다.
객체의 상태를 클래스로 표현하여, 상태에 따라 다른 행동을 하도록 할 수 있다.</p>
<p><strong>- Strategy(전략)</strong> : 객체들이 동일한 문제를 해결하기 위해 상호 교환 가능한 알고리즘을 캡슐화하여 정의하는 패턴이다.
알고리즘을 인터페이스로 정의하고, 알고리즘을 캡슐화하여 객체로 만들어 컨텍스트(Context)에서 알고리즘을 변경할 수 있도록 한다.</p>
<p><strong>- Template Method(템플릿 메서드)</strong> : 상위 클래스에서 처리의 뼈대를 정의하고, 하위 클래스에서 구체적인 처리를 구현하는 패턴이다.
상위 클래스에서 처리의 뼈대를 정의하고, 하위 클래스에서는 상위 클래스에서 정의한 뼈대에 맞추어 구체적인 내용을 구현한다.</p>
<p><strong>- Visitor(방문자)</strong> : 객체 구조를 이루는 요소(Element)에 대해 처리를 수행하는 연산(Operation)을 캡슐화하는 패턴이다.
구조를 이루는 객체(Element)와 처리를 수행하는 객체(Operation)를 분리하여 유연한 구조를 만들 수 있다.
각 요소(Element)에서는 자신을 전달하여 처리를 위임하며, 처리를 수행하는 객체(Operation)에서는 요소(Element)의 타입에 따라 처리를 다르게 한다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[[오류] Tomcat 포트 이미 사용 중]]></title>
            <link>https://velog.io/@jjinny_0609/Tomcat-%ED%8F%AC%ED%8A%B8-%EC%9D%B4%EB%AF%B8-%EC%82%AC%EC%9A%A9-%EC%A4%91%EC%9D%BC%EB%95%8C</link>
            <guid>https://velog.io/@jjinny_0609/Tomcat-%ED%8F%AC%ED%8A%B8-%EC%9D%B4%EB%AF%B8-%EC%82%AC%EC%9A%A9-%EC%A4%91%EC%9D%BC%EB%95%8C</guid>
            <pubDate>Mon, 10 Apr 2023 06:32:00 GMT</pubDate>
            <description><![CDATA[<blockquote>
<p><strong>Several ports (8005, 8080, 8009) required by Tomcat v9.0 Server at localhost are already in use. The server may already be running in another process, or a system process may be using the port. To start this server you will need to stop the other process or change the port number(s).</strong></p>
</blockquote>
<h3 id="해결방법">해결방법</h3>
<ol>
<li>관리자 권한으로 CMD창 실행</li>
<li><strong>netstat -p tcp -ano</strong> 로 현재 사용중인 포트 검색
C:\Windows\system32&gt; <em>netstat -p tcp -ano</em></li>
</ol>
<pre><code>활성 연결

  프로토콜  로컬 주소              외부 주소              상태            PID
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       492
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:3306           0.0.0.0:0              LISTENING       4296
  TCP    0.0.0.0:5040           0.0.0.0:0              LISTENING       5832
  TCP    0.0.0.0:8080           0.0.0.0:0              LISTENING       1528
  TCP    0.0.0.0:33060          0.0.0.0:0              LISTENING       4296
  TCP    0.0.0.0:49664          0.0.0.0:0              LISTENING       684
  TCP    0.0.0.0:49665          0.0.0.0:0              LISTENING       1276
  TCP    0.0.0.0:49666          0.0.0.0:0              LISTENING       1628
  TCP    0.0.0.0:49667          0.0.0.0:0              LISTENING       2956
  TCP    0.0.0.0:49670          0.0.0.0:0              LISTENING       756
  TCP    0.0.0.0:49699          0.0.0.0:0              LISTENING       768
  TCP    0.0.0.0:58091          0.0.0.0:0              LISTENING       3552
  TCP    127.0.0.1:3306         127.0.0.1:58013   
   ...</code></pre><p>Tomcat이 사용하는 기본 포트 0.0.0.0:8080, 0.0.0.0:8009와 127.0.0.1 : 8005이다.</p>
<ol start="3">
<li>현재 사용중인 포트의 pid를 찾아 삭제 (글쓴이는 1528번)<pre><code>프로토콜  로컬 주소              외부 주소              상태            PID
TCP    0.0.0.0:8080           0.0.0.0:0              LISTENING       1528</code></pre></li>
</ol>
<p><strong>taskkill /f /pid 1528</strong>
C:\Windows\system32&gt;taskkill /f /pid 1528
성공: 프로세스(PID 1528)가 종료되었습니다.</p>
<ol start="4">
<li><strong>netstat -p tcp -ano</strong> 로 다시 포트를 확인해보면 
프로세스가 종료된것을 확인할 수 있다.<pre><code></code></pre></li>
</ol>
<p>활성 연결</p>
<p>  프로토콜  로컬 주소              외부 주소              상태            PID
  TCP    0.0.0.0:135            0.0.0.0:0              LISTENING       492
  TCP    0.0.0.0:445            0.0.0.0:0              LISTENING       4
  TCP    0.0.0.0:3306           0.0.0.0:0              LISTENING       4296
  TCP    0.0.0.0:5040           0.0.0.0:0              LISTENING       5832
  TCP    0.0.0.0:33060          0.0.0.0:0              LISTENING       4296
  TCP    0.0.0.0:49664          0.0.0.0:0              LISTENING       684
  TCP    0.0.0.0:49665          0.0.0.0:0              LISTENING       1276
  TCP    0.0.0.0:49666          0.0.0.0:0              LISTENING       1628
  TCP    0.0.0.0:49667          0.0.0.0:0              LISTENING       2956
  TCP    0.0.0.0:49670          0.0.0.0:0              LISTENING       756
  TCP    0.0.0.0:49699          0.0.0.0:0              LISTENING       768
  TCP    0.0.0.0:58091          0.0.0.0:0              LISTENING       3552
  TCP    127.0.0.1:3306         127.0.0.1:58013<br>   ...</p>
<p>```</p>
<ol start="5">
<li>다시 Tomcat을 실행시켜 서버를 구동하면 오류없이 잘 작동된다.</li>
</ol>
]]></description>
        </item>
        <item>
            <title><![CDATA[동기식과 비동기식]]></title>
            <link>https://velog.io/@jjinny_0609/%EB%8F%99%EA%B8%B0%EC%8B%9D%EA%B3%BC-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%8B%9D</link>
            <guid>https://velog.io/@jjinny_0609/%EB%8F%99%EA%B8%B0%EC%8B%9D%EA%B3%BC-%EB%B9%84%EB%8F%99%EA%B8%B0%EC%8B%9D</guid>
            <pubDate>Mon, 10 Apr 2023 01:44:31 GMT</pubDate>
            <description><![CDATA[<p>웹브라우저 -&gt; controller -&gt; .jsp(해당 화면으로 이동)</p>
<p>동기식 통신방식 : Request를 보내면 Response가 도착해야 다음으로 넘어간다. Request를 보냈을때 이때 Thread는 Response가 받을때 까지 block상태가 된다.</p>
<ul>
<li>회원가입
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5829eca0-5dd6-4ed3-a1c2-3a7e8de0a2a7/image.png" alt=""></li>
</ul>
<ul>
<li>로그인
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d9dd3885-6fc2-4f65-803e-d4649b24a667/image.png" alt=""></li>
</ul>
<p>비동기식 통신방식(ajax) : Request를 보내면 Response가 도착하는데 순차적으로 받는것을 보장못한다. 이때 Thread는 Response를 기다리지 않고 있기 때문에 다른일을 할 수 있다. 이상태를 Non Block 상태라고 한다.
컨트롤러와 모델은 있다.(CM) / 뷰가 없음 = .jsp가 없음 -&gt; 자바스크립트를 이용해서 전달, 이때 json을 이용 / 원래 화면의 데이터를 수집해서 데이터를 처리할때 사용</p>
<p>스프링 프레임워크는 기본적으로 언어는 자바다.
근데 비동기식은 데이터타입 javascript 또는 xml을 주로 사용</p>
<p>springframework에서 javascript 타입 또는 xml에 대한 인식을 시켜주어야한다.
인식 시켜주기 위해서 pom.xml 인식에 필요한 jar 파일을 다운로드</p>
<p>아래 두가지를 pom.xml에 추가해주어야 한다.
jackson-databind(javascript타입)
jackson-dataformat-xml(xml타입)</p>
<p><strong>[pom.xml]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/130e8173-0b65-4c3d-8357-6cb53afd9ca4/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[Git repository 공유해서 사용하기 & 불러오기]]></title>
            <link>https://velog.io/@jjinny_0609/Git-repository-%EA%B3%B5%EC%9C%A0%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0</link>
            <guid>https://velog.io/@jjinny_0609/Git-repository-%EA%B3%B5%EC%9C%A0%ED%95%B4%EC%84%9C-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-%EB%B6%88%EB%9F%AC%EC%98%A4%EA%B8%B0</guid>
            <pubDate>Mon, 03 Apr 2023 02:15:55 GMT</pubDate>
            <description><![CDATA[<p>깃허브 본인 프로젝트 리포지토리들어와서 Settings
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9337df4d-a2ef-44d7-adf7-65bc64c851c9/image.png" alt="">
Collaborators
<img src="https://velog.velcdn.com/images/jjinny_0609/post/de2ac603-f22d-48c4-806d-d5b5f7ad1b88/image.png" alt=""></p>
<p>권한 부여할 대상의 이메일이나 username을 입력
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6e1e5841-59e8-4932-b528-f3f6c76f4bf7/image.png" alt=""></p>
<hr>

<ul>
<li><strong>비어있는 프로젝트 하나 만들어 주기</strong></li>
</ul>
<p>불러오기 Import...
<img src="https://velog.velcdn.com/images/jjinny_0609/post/8baabfc1-5f2a-430a-b20a-b754deaaf36b/image.png" alt=""></p>
<p>Projects from Git
<img src="https://velog.velcdn.com/images/jjinny_0609/post/cab9e7a7-20bf-4ae2-b9d3-21ec1727969c/image.png" alt=""></p>
<p>Clone URI
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bd02e6b3-4606-4b67-8531-f21fd5955890/image.png" alt=""></p>
<p>URI 주소 입력
아이디 패스워드 입력
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ebc011ee-97fe-4248-87a9-38cc88f341ac/image.png" alt="">
Next
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a3113e5e-5037-4674-bcbc-4ac624ceae9d/image.png" alt="">
Next
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4524f59c-3a68-4da5-a7c8-e6ec06797e41/image.png" alt=""></p>
<p>셋 중 하나 선택후 Finish</p>
<ul>
<li>기존 프로젝트 가져오기</li>
<li>새 프로젝트 마법사를 사용하여 가져오기</li>
<li>일반 프로젝트로 가져오기
<img src="https://velog.velcdn.com/images/jjinny_0609/post/40eb45c6-20c1-4f63-8d58-f53d822bea52/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[프로젝트 파일 Git에 연동하기]]></title>
            <link>https://velog.io/@jjinny_0609/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8C%8C%EC%9D%BC-Git%EC%97%90-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@jjinny_0609/%ED%94%84%EB%A1%9C%EC%A0%9D%ED%8A%B8-%ED%8C%8C%EC%9D%BC-Git%EC%97%90-%EC%97%B0%EB%8F%99%ED%95%98%EA%B8%B0</guid>
            <pubDate>Mon, 03 Apr 2023 01:33:08 GMT</pubDate>
            <description><![CDATA[<p>Git Repositorires - Open
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b776a156-016e-4694-b5dd-89874f64f635/image.png" alt=""></p>
<p>Clone a Git repository 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e9c2c60c-6903-4a4b-a26e-1bef1eb9878a/image.png" alt=""></p>
<p>Git에서 만든 Repository URI값 복사
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c49a71e0-794c-4ef2-bd7d-068c0fd2627e/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/c512117f-b3f6-4709-a0a7-61489a9be808/image.png" alt=""></p>
<p>Authentication(입증)
아이디 패스워드 입력
<img src="https://velog.velcdn.com/images/jjinny_0609/post/24bd68bc-8116-41ec-993d-9e866727ae17/image.png" alt=""></p>
<p>아직 Branch가 없당
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6c3c050c-78ac-4303-a8bb-a541d4cf094b/image.png" alt=""></p>
<p>Finish
<img src="https://velog.velcdn.com/images/jjinny_0609/post/415a9ae6-40b4-4100-ab9e-a27914470913/image.png" alt=""></p>
<p>Git Repositories에 추가되었다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9895a966-965c-4b15-9a37-798aa0b09b21/image.png" alt=""></p>
<p>Finish
<img src="https://velog.velcdn.com/images/jjinny_0609/post/7d067622-ff40-4d74-9304-aaad3da86681/image.png" alt=""></p>
<p>Team - Share Project...
<img src="https://velog.velcdn.com/images/jjinny_0609/post/1062ecef-6869-41d3-a117-6844ae4ddc71/image.png" alt=""></p>
<p>아직 github에 올라간 상태는 아님 Commit을 해보자
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2bcca647-d475-460e-bfae-9a182289594e/image.png" alt=""></p>
<p>Team - Commit...
<img src="https://velog.velcdn.com/images/jjinny_0609/post/8de40719-7f2a-4032-b7c1-e1fcf38f8ed7/image.png" alt=""></p>
<p>Commit하기전 해야할 것이 있는데 토큰생성을 해줘야 한다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/0f8fa9f6-2c54-4518-a68b-d9c0a9147ce5/image.png" alt=""></p>
<p>토큰 생성을 위해서 깃허브페이지 실행 - 우측 상단 프로필(고양이) 클릭 - Settings
<img src="https://velog.velcdn.com/images/jjinny_0609/post/8349cd07-18bc-4e8c-83a9-fad5be15e5bc/image.png" alt=""></p>
<p>Developer settings
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b83af099-94c2-43ab-a5fc-143a815ee0bf/image.png" alt=""></p>
<p>Generate new token
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9b354349-0c80-448d-9913-98995a686267/image.png" alt=""></p>
<p>Generate new token(classic) 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/082f3da8-d3c4-4310-af19-661c5fcc521b/image.png" alt=""></p>
<p>Note 입력하고, Expiration (토큰 유지 기간 선택), 권한 선택
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bbcf673c-b4cd-4f97-a92d-ab3abbb46a27/image.png" alt=""></p>
<p>토큰이 생성된다. 토큰 값은 중요하니 백업 꼭 해두세요.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5faa17fb-3f39-4b02-989b-ce80f32e4c2d/image.png" alt=""></p>
<p>Commit을 위해 +를 눌러서 파일을 아래로 내려주자
이때 파일명앞에 .붙은건 제외
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2bca7158-3e40-456f-8bcd-e044c04c2ca1/image.png" alt=""></p>
<p>Commit &amp; Push를 누르고 
User에 본인 이메일넣고 아래에 토큰을 넣으면 정상적으로 Commit 된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/91407295-bc9c-42c3-a033-8c40a1d8175e/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링(Spring) #4]]></title>
            <link>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-4</link>
            <guid>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-4</guid>
            <pubDate>Thu, 30 Mar 2023 11:38:14 GMT</pubDate>
            <description><![CDATA[<h3 id="회원-상세-내용-페이지-detail에-회원-내용-받아오기">회원 상세 내용 페이지 (detail)에 회원 내용 받아오기</h3>
<p><strong>list.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;    
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%-- ${memlist} --%&gt;
    &lt;table border=&quot;1&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;ID&lt;/td&gt;&lt;td&gt;이름&lt;/td&gt;&lt;td&gt;나이&lt;/td&gt;&lt;td&gt;주소&lt;/td&gt;&lt;td&gt;이메일&lt;/td&gt;&lt;td&gt;폰번호&lt;/td&gt;
        &lt;/tr&gt;
        &lt;c:forEach items=&quot;${memlist}&quot; var=&quot;list&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;a href=&quot;detail?id=${list.id}&quot;&gt;${list.id}&lt;/a&gt;&lt;/td&gt;&lt;td&gt;${list.name}&lt;/td&gt;&lt;td&gt;${list.age}&lt;/td&gt;&lt;td&gt;${list.addr}&lt;/td&gt;&lt;td&gt;${list.email}&lt;/td&gt;&lt;td&gt;${list.phone}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;/c:forEach&gt;
    &lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>해당 경로에 <strong>detail.jsp 생성</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9b61f9f8-1b1e-4a30-a85f-86a516084a6b/image.png" alt=""></p>
<p><strong>detail.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;    
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
${detail}
    &lt;table border=&quot;1&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;이름&lt;/td&gt;
            &lt;td&gt;${detail.name}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;ID&lt;/td&gt;
            &lt;td&gt;${detail.id}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;password&lt;/td&gt;
            &lt;td&gt;${detail.password}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;나이&lt;/td&gt;
            &lt;td&gt;13&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;주소&lt;/td&gt;
            &lt;td&gt;${detail.addr}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;이메일&lt;/td&gt;
            &lt;td&gt;${detail.email}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;폰번호&lt;/td&gt;
            &lt;td&gt;${detail.phone}&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
    &lt;input type = &quot;button&quot; value=&quot;수정&quot;&gt;
    &lt;input type = &quot;button&quot; value=&quot;삭제&quot;&gt; 
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>MemberController.java</strong></p>
<pre><code>// 회원 상세 내용 페이지
    @RequestMapping(value = &quot;/detail&quot;, method = RequestMethod.GET)
    public String memberDetail(Model model) {//return type void가 아니니 return값이 꼭 있어야한다.
        model.addAttribute(&quot;memlist&quot;, ls.memlist());
        //ls.memlist();
        return &quot;member/detail&quot;; //member폴더에 detail.jsp를 실행하겠다 //WEB-INF/view/member/detail.jsp
    }</code></pre><p>MemberController.java의 내용을 수정해주고
detail.jsp를 만든후 id를 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f7ead7da-a73c-493e-ae2f-35e3461929f1/image.png" alt="">
이제 수정버튼을 누르면 수정이 되도록 만들어주자.</p>
<p>값은
MemberController.java -&gt;
LoginServive.java-&gt;
LoginServiceImpl.java-&gt;
LoginMapper.java-&gt;
LoginMapper.xml 순서로 id값 전달된다.</p>
<p><strong>LoginService.java</strong></p>
<pre><code>package org.hj.service;

import java.util.ArrayList;

import org.hj.model.LoginVO;

public interface LoginService {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
    public ArrayList&lt;LoginVO&gt; memlist();                        
    // ② memdetail() 메서드 생성, 리턴타입을 잘모르겠다면 일단 void로 해놓고 진행
    // 설계만하고 아직 구현을 아직 안해줬으니 구현을 해줘야함
    // 메서드 선언
//    public LoginVO memdetail(String id);
    public LoginVO memdetail(LoginVO login);    // ※ LoginVO로 하는법

}</code></pre><p><strong>LoginServicelmpl.java</strong></p>
<pre><code>package org.hj.service;

import java.util.ArrayList;

import org.hj.mapper.LoginMapper;
import org.hj.model.LoginVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    LoginMapper lm;    // loginMapper lm = new LoginMapper();

    public void memreg(LoginVO member) {
        lm.memreg(member);
    };

    public LoginVO login (LoginVO member) {
        System.out.println(&quot;service=&quot;+member);
        System.out.println(&quot;service return=&quot;+lm.login(member));
        return lm.login(member);
    }

    public ArrayList&lt;LoginVO&gt; memlist() {
        return lm.memlist();
    }

    // ③ 여기서 구현을 시작, LoginMapper.xml도 수정해야함
//    public void memdetail(String id) {
//        lm.memdetail(id);        // ④ 작성후,LoginMapper.java memdetail()을 만들어줘야함
//    };
    // ※ LoginVO로 하는법
    public LoginVO memdetail(LoginVO login) {
        return lm.memdetail(login);        
    };    // void가 아니니 return 추가
}</code></pre><p><strong>LoginMapper.java</strong></p>
<pre><code>package org.hj.mapper;

import java.util.ArrayList;

import org.hj.model.LoginVO;

public interface LoginMapper {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
    // 리턴이 있기때문에 void가 아닌  LoginVO를 리턴
    public ArrayList&lt;LoginVO&gt; memlist();
//    public LoginVO memdetail(String id);    // ⑤ memdetail() 생성 리턴값 잘모르니 일단 void
    // ※ LoginVO로 하는법
    public LoginVO memdetail(LoginVO login);

}
</code></pre><p><strong>LoginMapper.xml</strong></p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;


  &lt;mapper namespace=&quot;org.hj.mapper.LoginMapper&quot;&gt;

      &lt;insert id=&quot;memreg&quot;&gt;
          insert into member (id, password, name, birth, gender, phonenum)
          value(#{id},#{password},#{name},sysdate(),&quot;f&quot;,&quot;0101&quot;);
      &lt;/insert&gt;

      &lt;select id=&quot;login&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
          select id, password
          from member
          where id=#{id} and password=#{password}
      &lt;/select&gt;

      &lt;select id=&quot;memlist&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
          select *    &lt;!-- 값이 여러건이다. → 배열이 필요함 --&gt;
          from member
    &lt;/select&gt;

    &lt;!-- id=에 들어갈값은 loginMapper interface의 메서드이름 --&gt;
    &lt;select id=&quot;memdetail&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
        select *
        from member
        where id=#{id}  &lt;!-- 사용자가 선택한 아이디 --&gt;
        &lt;!-- id값을 긁어와야한다. 
        private 값이 있는지 생각하고 LoginVO로 받을지 String--&gt;
    &lt;/select&gt;

  &lt;/mapper&gt;</code></pre><hr>

<h3 id="회원-상세-내용-페이지detailjsp에서-수정-삭제-구현-하기">회원 상세 내용 페이지(detail.jsp)에서 수정 삭제 구현 하기</h3>
<p><strong>detail.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;    
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form method=&quot;post&quot;&gt;
&lt;%-- ${detail} --%&gt;
    &lt;table border=&quot;1&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;이름&lt;/td&gt;
            &lt;td&gt;
                &lt;input type=&quot;text&quot; value=&quot;${detail.name}&quot; name = &quot;name&quot;&gt;    
&lt;%--             ${detail.name} --%&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;ID&lt;/td&gt;
            &lt;td&gt;
                ${detail.id}&lt;input type=&quot;hidden&quot; value=&quot;${detail.id}&quot; name=&quot;id&quot;&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;password&lt;/td&gt;
                &lt;td&gt;&lt;input type=&quot;password&quot; value=&quot;${detail.password}&quot; name=&quot;password&quot;&gt;
&lt;%--             ${detail.password} --%&gt;
                &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;나이&lt;/td&gt;
            &lt;td&gt;13&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;주소&lt;/td&gt;
                &lt;td&gt;
                &lt;input type=&quot;text&quot; value=&quot;${detail.addr}&quot; name=&quot;addr&quot;&gt;
&lt;%--                 ${detail.addr} --%&gt;
                &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;이메일&lt;/td&gt;
            &lt;td&gt;${detail.email}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;폰번호&lt;/td&gt;
                &lt;td&gt;
                &lt;input type=&quot;text&quot; value=&quot;${detail.phone}&quot; name=&quot;phone&quot;&gt;
                ${detail.phone}
                &lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td colspan=&quot;2&quot;&gt;
                &lt;input type=&quot;submit&quot; value=&quot;수정&quot; formaction=&quot;modify&quot;&gt;
                &lt;input type=&quot;submit&quot; value=&quot;삭제&quot; formaction=&quot;remove&quot;&gt;
            &lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
&lt;/form&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre><p>여기서는 a태그보다 form 태그로 전체를 감싸서 보내준다 그리고 form태그를 사용해야 Id password값을 안전하게 보낼 수 있다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9484ba61-5b5c-408c-b401-7cbed1dfbc8b/image.png" alt=""></p>
<p>업데이트는 되지만 주소로 이동은 되지 않는다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/517ae97b-bdca-4e84-b19e-f11183c3c9c7/image.png" alt=""></p>
<p><strong>MemberController.java</strong></p>
<pre><code>
package org.hj.controller;

import javax.servlet.http.HttpSession;

import org.hj.model.LoginVO;
import org.hj.service.LoginService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

@Controller
public class MemberController {

    @Autowired        //스프링 프레임워크에서 사용되는 어노테이션 중 하나로, 객체 간 의존성을 자동으로 주입하는 기능을 제공합니다.
    LoginService ls;    // LoginService ls = new LoginService();

    // 회원가입
    @RequestMapping(value = &quot;/member&quot;, method = RequestMethod.GET)
    public String member () {
        return &quot;member/memberin&quot;;
    }

    // 회원가입서버
    @RequestMapping(value = &quot;/member&quot;, method = RequestMethod.POST)
//  public String memberPost(String id, String password, String name) { 
//    아래 3줄을 주석처리하고 위와같이 사용해도 되지만 메모리를 많이 차지한다.
    public String memberPost (LoginVO member) {
        System.out.println(member);
        ls.memreg(member);
        return &quot;board/list&quot;;
    }

    // 로그인 페이지
    @RequestMapping(value = &quot;/login&quot;, method = RequestMethod.GET)
    public String login () {
        System.out.println(&quot;aaaa&quot;);
        return &quot;member/login&quot;;
    }

    // 로그인 서버
    @RequestMapping(value = &quot;/login&quot;, method = RequestMethod.POST)
    public String loginPost (HttpSession session, LoginVO member) {
    // ↑ 세션 사용을 알려줌 HttpSession을 지우고 이줄에 HttpSession session = new session(); 도 가능 
/*        System.out.println(&quot;contorller=&quot;+member);
        System.out.println(ls.login(member));*/

        if (ls.login(member)==null) {
            return &quot;member/login&quot;;
            } else {    
                session.setAttribute(&quot;login&quot;, ls.login(member));
                return &quot;redirect:/list&quot;;    
            }
        }
    // 회원 관리 페이지(관리자용)
    @RequestMapping(value = &quot;/list&quot;, method = RequestMethod.GET)
    public String memberlist (Model model) {
        model.addAttribute(&quot;memlist&quot;, ls.memlist());            //멤버 리스트
        return &quot;member/list&quot;;    //    /WEB-INF/view/member/list.jsp  , 스프링에선 자동으로 해준다. root-context.xml 참고
    }
    // 회원 상세 내용 페이지
    @RequestMapping(value = &quot;/detail&quot;, method = RequestMethod.GET)
//    public String memberDetail (String id) {    // aaaa값을 id에
    public String memberDatail(LoginVO login, Model model){ // ※ LoginVO로 하는법    ⑥ , Model model 추가 뒤의 model명은 다르게 주어도 됨
//        ls.memdetail(id);        // ① ls -&gt; LoginService에 memdetail()선언확인
        // 메서드 호출 

        model.addAttribute(&quot;detail&quot;, ls.memdetail(login));            //멤버 리스트
//        ls.memdetail(login);    // ※ LoginVO로 하는법
        return &quot;member/detail&quot;;    //    /WEB-INF/view/member/detail.jsp
    }

    // 회원정보 수정
    @RequestMapping(value = &quot;/modify&quot;, method = RequestMethod.POST)
//    public String memberModify(String name, String id,String password, String phone) {    // 이렇게 작성한다면 메모리 낭비문제가 있다. 32byte
    public String memberModify(LoginVO login, RedirectAttributes rttr) {    // LoginVO로 받으면 8byte면 충분
        ls.memberModify(login);
        rttr.addAttribute(&quot;id&quot;, login.getId());
        return &quot;redirect:/detail&quot;;    //수정후 &quot; &quot; 안에는 어떤 화면으로 이동할 것인지 작성
        // forward방식이 아닌 redirect방식으로 해서 처리 
    }



    // 회원정보 삭제
    @RequestMapping(value = &quot;/remove&quot;, method = RequestMethod.POST)
    public String remove(LoginVO login) {
        ls.memberRemove(login);
        return &quot;redirect:/list&quot;;
    }
}
</code></pre><p><strong>LoginService.java</strong></p>
<pre><code>package org.hj.service;

import java.util.ArrayList;

import org.hj.model.LoginVO;

public interface LoginService {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
    public ArrayList&lt;LoginVO&gt; memlist();                        
    // ② memdetail() 메서드 생성, 리턴타입을 잘모르겠다면 일단 void로 해놓고 진행
    // 설계만하고 아직 구현을 아직 안해줬으니 구현을 해줘야함
    // 메서드 선언
//    public LoginVO memdetail(String id);
    public LoginVO memdetail(LoginVO login);    // ※ LoginVO로 하는법

    public void memberModify(LoginVO login);

    public void memberRemove(LoginVO login);
}</code></pre><p><strong>LoginServicelmpl.java</strong></p>
<pre><code>package org.hj.service;

import java.util.ArrayList;

import org.hj.mapper.LoginMapper;
import org.hj.model.LoginVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    LoginMapper lm;    // loginMapper lm = new LoginMapper();

    public void memreg(LoginVO member) {
        lm.memreg(member);
    };

    public LoginVO login (LoginVO member) {
        System.out.println(&quot;service=&quot;+member);
        System.out.println(&quot;service return=&quot;+lm.login(member));
        return lm.login(member);
    }

    public ArrayList&lt;LoginVO&gt; memlist() {
        return lm.memlist();
    }

    // ③ 여기서 구현을 시작, LoginMapper.xml도 수정해야함
//    public void memdetail(String id) {
//        lm.memdetail(id);        // ④ 작성후,LoginMapper.java memdetail()을 만들어줘야함
//    };
    // ※ LoginVO로 하는법
    public LoginVO memdetail(LoginVO login) {
        return lm.memdetail(login);        
    };    // void가 아니니 return 추가

    // 수정
    public void memberModify(LoginVO login) {
        lm.memberModify(login);
    }

    public void memberRemove(LoginVO login) {
        lm.memberRemove(login);
    }
}</code></pre><p><strong>LoginMapper.java</strong></p>
<pre><code>package org.hj.mapper;

import java.util.ArrayList;

import org.hj.model.LoginVO;

public interface LoginMapper {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
    // 리턴이 있기때문에 void가 아닌  LoginVO를 리턴
    public ArrayList&lt;LoginVO&gt; memlist();
//    public LoginVO memdetail(String id);    // ⑤ memdetail() 생성 리턴값 잘모르니 일단 void
    // ※ LoginVO로 하는법
    public LoginVO memdetail(LoginVO login);
    public void memberModify(LoginVO login);
    // 삭제
    public void memberRemove(LoginVO login);
}</code></pre><p><strong>LoginMapper.xml</strong></p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;


  &lt;mapper namespace=&quot;org.hj.mapper.LoginMapper&quot;&gt;

      &lt;insert id=&quot;memreg&quot;&gt;
          insert into member (id, password, name, birth, gender, phonenum)
          value(#{id},#{password},#{name},sysdate(),&quot;f&quot;,&quot;0101&quot;);
      &lt;/insert&gt;

      &lt;select id=&quot;login&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
          select id, password
          from member
          where id=#{id} and password=#{password}
      &lt;/select&gt;

      &lt;select id=&quot;memlist&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
          select *    &lt;!-- 값이 여러건이다. → 배열이 필요함 --&gt;
          from member
    &lt;/select&gt;

    &lt;!-- id=에 들어갈값은 loginMapper interface의 메서드이름 --&gt;
    &lt;select id=&quot;memdetail&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
        select *
        from member
        where id=#{id}  &lt;!-- 사용자가 선택한 아이디 --&gt;
        &lt;!-- id값을 긁어와야한다. 
        private 값이 있는지 생각하고 LoginVO로 받을지 String--&gt;
    &lt;/select&gt;

    &lt;!-- 수정, 없데이트는 바로 되기때문에 resultType이 필요없다--&gt;
    &lt;update id=&quot;memberModify&quot;&gt;
        update member
        set name =#{name},
            password =#{password},
            phonenum =#{phone}
        where id =#{id};
    &lt;/update&gt;
&lt;!--      phonenum =#{phone} --&gt;
&lt;!-- mysql의phonenum=#{LoginVO의 값 phone} --&gt;
&lt;!-- {phone}뒤에 ,는 빼도됨. --&gt;

    &lt;delete id=&quot;memberRemove&quot;&gt;
        delete from member where id=#{id}
    &lt;/delete&gt;
  &lt;/mapper&gt;</code></pre><p>위 과정을 진행하면 정상적으로 수정 삭제가 된다.</p>
<p>기존 리스트
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6ce8b90d-eb01-4eda-a026-a6fbe80196ca/image.png" alt=""></p>
<p>참새로 변경됨
<img src="https://velog.velcdn.com/images/jjinny_0609/post/8f735ac2-2c75-497e-8867-0a23977323fd/image.png" alt=""></p>
<p>삭제를 누르면 
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a90a6684-2f64-4b6f-ac43-c78f3b7056d4/image.png" alt=""></p>
<p>삭제도 잘 된다.</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링(Spring) #3]]></title>
            <link>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-3</link>
            <guid>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-3</guid>
            <pubDate>Wed, 29 Mar 2023 12:51:21 GMT</pubDate>
            <description><![CDATA[<h3 id="전체적인-구조에-대해">전체적인 구조에 대해</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/d693b732-ea0f-4524-ba6b-d915ae316700/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/c0d2a065-1af2-4751-bcd0-28f83928fd64/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/ca54278c-407f-4d08-926e-ec6e40600d54/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/4a0f242a-351f-478c-81b1-ecebb0d298a0/image.png" alt=""></p>
<p><strong>LoginService.java</strong></p>
<pre><code>package org.hj.service;

import org.hj.model.LoginVO;

public interface LoginService {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
}
</code></pre><p><strong>LoginServicelmpl.java</strong></p>
<pre><code>package org.hj.service;

import org.hj.mapper.LoginMapper;
import org.hj.model.LoginVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    LoginMapper lm;    // loginMapper lm = new LoginMapper();

    public void memreg(LoginVO member) {
        lm.memreg(member);
    };

    public LoginVO login (LoginVO member) {
        System.out.println(&quot;service=&quot;+member);
        System.out.println(&quot;service return=&quot;+lm.login(member));
        return lm.login(member);
    }
}</code></pre><p>위의 코드는 Spring Framework에서 사용되는 서비스 계층의 구현체인 LoginServiceImpl 클래스와 LoginService 인터페이스입니다.</p>
<p>LoginServiceImpl 클래스는 LoginService 인터페이스를 구현합니다. 이 클래스에는 memreg와 login 메서드가 구현되어 있습니다.</p>
<p>memreg 메서드는 LoginMapper 인터페이스를 사용하여 member 객체를 데이터베이스에 저장하는 역할을 합니다. @Autowired 어노테이션을 사용하여 LoginMapper를 주입합니다.</p>
<p>login 메서드는 LoginMapper 인터페이스를 사용하여 member 객체를 데이터베이스에서 조회하는 역할을 합니다. 이 메서드는 member 객체를 인자로 받아 LoginMapper의 login 메서드를 호출하고, 해당 결과를 반환합니다.</p>
<p>LoginService 인터페이스는 memreg와 login 메서드를 선언하고 있습니다. 이 인터페이스를 구현하는 클래스는 반드시 memreg와 login 메서드를 구현해야 합니다.</p>
<p>@Service 어노테이션은 스프링 컨테이너에서 해당 클래스를 빈으로 등록하도록 지시하는 어노테이션입니다. 따라서 LoginServiceImpl 클래스는 스프링 컨테이너에서 빈으로 등록되어, 다른 클래스에서 @Autowired 어노테이션을 사용하여 주입할 수 있습니다.</p>
<p>이렇게 구현된 LoginServiceImpl 클래스와 LoginService 인터페이스는 컨트롤러와 데이터 액세스 계층에서 사용되어 로그인과 회원가입 기능을 구현하는 데에 활용될 수 있습니다.</p>
<hr>

<p><strong>LoginMapper.java</strong></p>
<pre><code>package org.hj.mapper;

import org.hj.model.LoginVO;

public interface LoginMapper {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
}</code></pre><p><strong>LoginMapper.xml</strong></p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;


  &lt;mapper namespace=&quot;org.hj.mapper.LoginMapper&quot;&gt;

      &lt;insert id=&quot;memreg&quot;&gt;
          insert into member (id, password, name, birth, gender, phonenum)
          value(#{id},#{password},#{name},sysdate(),&quot;f&quot;,&quot;0101&quot;);
      &lt;/insert&gt;

      &lt;select id=&quot;login&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
          select id, password
          from member
          where id=#{id} and password=#{password}
      &lt;/select&gt;
  &lt;/mapper&gt;</code></pre><p>위 예제는 Mapper Interface인 LoginMapper는 memreg와 login 메서드를 정의하고 있습니다. memreg 메서드는 LoginVO 타입의 멤버를 입력받아, 데이터베이스의 member 테이블에 해당 정보를 삽입하는 쿼리를 실행합니다. login 메서드는 LoginVO 타입의 멤버를 입력받아, 데이터베이스의 member 테이블에서 해당하는 아이디와 비밀번호를 조회하는 쿼리를 실행하고, 조회 결과를 LoginVO 객체로 반환합니다.</p>
<p>XML 매퍼 파일인 LoginMapper.xml은 org.hj.mapper.LoginMapper 네임스페이스를 사용하는 매퍼 파일로, memreg와 login 메서드에 해당하는 SQL 쿼리를 정의하고 있습니다. memreg에 해당하는 SQL 쿼리는 insert 태그를 사용하여 삽입 쿼리를 정의하고, login에 해당하는 SQL 쿼리는 select 태그를 사용하여 조회 쿼리를 정의합니다. login의 결과 타입은 resultType 속성으로 org.hj.model.LoginVO를 지정하여, 조회 결과를 LoginVO 객체로 매핑할 수 있도록 합니다.</p>
<p>이렇게 작성된 Mapper Interface와 XML 매퍼 파일은 MyBatis ORM 프레임워크에서 사용되어, 애플리케이션에서 데이터베이스와 상호작용을 할 때에 사용됩니다.</p>
<hr>

<h4 id="mapper-interface">Mapper Interface</h4>
<p> MyBatis와 같은 ORM 프레임워크를 사용하여 데이터베이스와 상호작용을 할 때, Mapper Interface를 사용하는 것이 일반적입니다. Mapper Interface는 SQL 쿼리를 실행하고 결과를 매핑하는 메서드를 정의합니다.</p>
<p>Mapper Interface를 작성할 때에는, 인터페이스에 매핑할 SQL 쿼리를 정의하고, 매핑할 결과 객체와 매개변수를 지정합니다. 예를 들어, 다음과 같은 Mapper Interface를 작성할 수 있습니다.</p>
<pre><code>public interface UserMapper {
    @Select(&quot;SELECT * FROM users WHERE id = #{id}&quot;)
    User getUserById(@Param(&quot;id&quot;) int id);

    @Insert(&quot;INSERT INTO users (name, age, email) VALUES (#{name}, #{age}, #{email})&quot;)
    void insertUser(User user);

    @Update(&quot;UPDATE users SET name = #{name}, age = #{age}, email = #{email} WHERE id = #{id}&quot;)
    void updateUser(User user);

    @Delete(&quot;DELETE FROM users WHERE id = #{id}&quot;)
    void deleteUser(@Param(&quot;id&quot;) int id);
}</code></pre><p>위의 예제에서는 @Select, @Insert, @Update, @Delete와 같은 어노테이션을 사용하여 SQL 쿼리를 정의하고 있습니다. 또한, 매개변수를 전달할 때에는 @Param 어노테이션을 사용하여 매개변수의 이름을 명시합니다.</p>
<p>Mapper Interface를 작성한 후에는, 이를 MyBatis와 같은 ORM 프레임워크에서 매핑해줘야 합니다. 이를 위해서는 Mapper Interface를 구현하는 XML 파일을 작성하고, 이를 스프링 설정 파일에서 등록하는 방식을 사용합니다. 이러한 과정을 거쳐야 Mapper Interface를 사용하여 데이터베이스와 상호작용할 수 있습니다.</p>
<h3 id="프로젝트의-구성">프로젝트의 구성</h3>
<ul>
<li><p>일반적인 웹 프로젝트의 구조는 3-Tier의 구조를 활용
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9e871da0-f6e1-44e3-a277-0ba3370db6c9/image.png" alt=""></p>
</li>
<li><p>스프링의 MVC를 이용하는 예제의 구성
<img src="https://velog.velcdn.com/images/jjinny_0609/post/667d6e82-5c17-43a9-b4ed-f3a55130ea98/image.png" alt=""></p>
</li>
</ul>
<hr>

<h3 id="로그인">로그인</h3>
<p>a태그로도 가능하다
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c92b67ba-03f5-4ff1-b871-c9330fe2c345/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/6673db47-8e1e-4158-ad62-74a149194a35/image.png" alt=""></p>
<p>로그인 과정
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e092ca8c-e3a8-4a11-95bf-8a0dd0e76d8d/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/d8001a5e-71f8-4e84-bcdb-54f2dd5079a4/image.png" alt=""></p>
<hr>

<p>아이디값이 없으면 null이니까 login페이지를 리턴하도록
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c8dc7361-00a0-4d03-96ec-df7ea9d3411a/image.png" alt="">
아래와 같이 변경해줌 else일때 세션에 저장하도록
<img src="https://velog.velcdn.com/images/jjinny_0609/post/27836336-9208-4d9d-a73f-b7d3fcb0fb2a/image.png" alt=""></p>
<p>작성(59~63)
<img src="https://velog.velcdn.com/images/jjinny_0609/post/18a8901d-ea13-47d8-afe3-ee6e6627917a/image.png" alt=""></p>
<p>이제 데이터베이스 값을 화면으로 넘겨주기 위한 작업을 해보자.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2d528dd8-9b3b-47a9-9ac7-6fa0b6c994af/image.png" alt=""></p>
<p>list.jsp 생성
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a517c63a-a1b7-437a-bf7a-854d53f22450/image.png" alt=""></p>
<p>*<em>list.jsp *</em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri =&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;table border=&quot;1&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;ID&lt;/td&gt;&lt;td&gt;이름&lt;/td&gt;&lt;td&gt;생년월일&lt;/td&gt;&lt;td&gt;이메일&lt;/td&gt;&lt;td&gt;휴대폰&lt;/td&gt;
        &lt;/tr&gt;
        &lt;c:forEach items=&quot;${memlist}&quot; var=&quot;list&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;&lt;a href=&quot;&quot;&gt;${list.id}&lt;/a&gt;&lt;/td&gt;
            &lt;td&gt;${list.name}&lt;/td&gt;
            &lt;td&gt;${list.age}&lt;/td&gt;
            &lt;td&gt;${list.email}&lt;/td&gt;
            &lt;td&gt;${list.phone}&lt;/td&gt;
        &lt;/tr&gt;
        &lt;/c:forEach&gt;
    &lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/2394b1fd-2df5-4800-8478-b890d2d77631/image.png" alt=""></p>
<p><strong>LoginService.java</strong></p>
<pre><code>package org.hj.service;

import java.util.ArrayList;

import org.hj.model.LoginVO;

public interface LoginService {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
    public ArrayList&lt;LoginVO&gt; memlist();
}</code></pre><p><strong>LoginServicelmpl.java</strong></p>
<pre><code>package org.hj.service;

import java.util.ArrayList;

import org.hj.mapper.LoginMapper;
import org.hj.model.LoginVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class LoginServiceImpl implements LoginService {

    @Autowired
    LoginMapper lm;

    public void memreg(LoginVO member) {
        lm.memreg(member);
    }

    public LoginVO login (LoginVO member) {
        System.out.println(&quot;service=&quot;+member);
        System.out.println(&quot;service return=&quot;+lm.login(member));
        return lm.login(member);
    }

    public ArrayList&lt;LoginVO&gt; memlist(){
        return lm.memlist();
    }
}</code></pre><p><strong>LoginMapper.java</strong></p>
<pre><code>package org.hj.mapper;

import java.util.ArrayList;

import org.hj.model.LoginVO;

public interface LoginMapper {
    public void memreg(LoginVO member);
    public LoginVO login(LoginVO member);
    public ArrayList&lt;LoginVO&gt; memlist();
}</code></pre><p><strong>LoginMapper.xml</strong></p>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;

&lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&gt;

  &lt;mapper namespace=&quot;org.hj.mapper.LoginMapper&quot;&gt;

      &lt;insert id=&quot;memreg&quot;&gt;
          insert into member(id, password, name, gender, phonenum)
          value(#{id},#{password},#{name},&quot;f&quot;, &quot;0101&quot;);
      &lt;/insert&gt;

      &lt;select id=&quot;login&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
          select id, password
          from member
          where id=#{id} and password=#{password}
      &lt;/select&gt;

      &lt;select id=&quot;memlist&quot; resultType=&quot;org.hj.model.LoginVO&quot;&gt;
          select *
          from member
      &lt;/select&gt;
  &lt;/mapper&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[스프링(Spring) #2]]></title>
            <link>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-2</link>
            <guid>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-2</guid>
            <pubDate>Tue, 28 Mar 2023 07:02:47 GMT</pubDate>
            <description><![CDATA[<h3 id="mvcmodel-view-controller">MVC(Model-View-Controller)</h3>
<p>대부분의 서블릿 기반 프레임워크들이 사용하는 방식
데이터와 처리, 화면을 분리하는 방식
웹에서는 Model2 방식으로 표현
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c57eda50-6f5f-4559-9396-5f18b63e29ad/image.png" alt="">
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4b1b861c-8ae7-4250-84f4-270b857dc78b/image.png" alt=""></p>
<h3 id="mvc-중에서-모델을-사용해야-하는-이유">MVC 중에서 모델을 사용해야 하는 이유</h3>
<p>접근제어자, 메모리 사용량의 차이
<img src="https://velog.velcdn.com/images/jjinny_0609/post/73ced7b3-13fc-444e-8ec5-f5b662393c15/image.png" alt=""></p>
<p><strong>데이터 관리</strong>: Model은 애플리케이션에서 사용되는 데이터를 관리하고, 데이터에 대한 적절한 유효성 검사 및 처리를 수행합니다. 이를 통해 데이터 일관성과 안정성을 보장할 수 있습니다.</p>
<p><strong>비즈니스 로직 처리</strong>: Model은 비즈니스 로직을 처리하고 데이터 처리를 위한 알고리즘을 구현합니다. 이를 통해 데이터 처리에 대한 일관성과 안정성을 유지할 수 있으며, 애플리케이션의 기능을 확장하기 쉽습니다.</p>
<p><strong>뷰와 분리</strong>: Model은 뷰와 분리되어 있기 때문에, 데이터의 변경이나 비즈니스 로직의 변경에 대해 뷰와 컨트롤러의 변경이 필요하지 않습니다. 이를 통해 애플리케이션의 유지보수성과 확장성을 높일 수 있습니다.</p>
<p><strong>재사용성</strong>: Model은 다른 컨트롤러와 뷰에서도 사용할 수 있습니다. 이를 통해 코드의 재사용성이 높아지며, 코드의 중복을 피할 수 있습니다.</p>
<p>따라서 Model을 사용하는 것은 애플리케이션의 유지보수성, 확장성, 일관성, 안정성 등을 보장하는데 큰 역할을 합니다.</p>
<hr>

<h3 id="스프링-mvc의-기본-흐름">스프링 MVC의 기본 흐름</h3>
<p>스프링 MVC의 기본 흐름은 다음과 같습니다.</p>
<p>1.클라이언트의 요청: 클라이언트가 HTTP 요청을 보냅니다.</p>
<ol start="2">
<li><p>DispatcherServlet: 요청이 DispatcherServlet에 도착합니다. DispatcherServlet은 요청을 처리하기 위해 HandlerMapping을 사용하여 요청에 대한 적절한 컨트롤러를 찾습니다.</p>
</li>
<li><p>컨트롤러: 적절한 컨트롤러가 선택되면, 해당 컨트롤러는 요청을 처리합니다. 컨트롤러는 모델을 생성하고, 모델에 데이터를 추가합니다.</p>
</li>
<li><p>ViewResolver: 컨트롤러는 뷰 이름을 반환합니다. 이 뷰 이름은 ViewResolver를 사용하여 실제 뷰 객체와 매핑됩니다.</p>
</li>
<li><p>View: 뷰는 모델 데이터를 사용하여 응답을 생성합니다. 뷰는 보통 JSP, Thymeleaf, Freemarker 등의 템플릿 엔진을 사용하여 HTML을 생성합니다.</p>
</li>
<li><p>응답: 뷰가 생성한 응답은 DispatcherServlet에 반환됩니다. DispatcherServlet은 응답을 클라이언트에게 보내기 전에 필터 체인을 통해 추가적인 처리를 수행합니다.</p>
</li>
<li><p>클라이언트 응답: DispatcherServlet이 클라이언트에게 응답을 반환합니다.</p>
</li>
</ol>
<p>이러한 기본적인 흐름을 따르면서, 스프링 MVC는 다양한 기능과 설정을 제공하여 유연한 웹 애플리케이션 개발을 지원합니다.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/7891906b-f18b-4aad-9805-c75b4bc0435a/image.png" alt=""></p>
<hr>

<h3 id="controller">Controller</h3>
<ul>
<li>HttpServletRequest, HttpServletResponse를 거의 사용할 필요 없이 필요
한 기능 구현</li>
<li>다양한 타입의 파라미터 처리, 다양한 타입의 리턴 타입 사용 가능</li>
<li>GET 방식, POST 방식 등 전송 방식에 대한 처리를 어노테이션으로 처리
가능</li>
<li>상속/인터페이스 방식 대신에 어노테이션만으로도 필요한 설정 가능</li>
</ul>
<h3 id="어노테이션">어노테이션(@)</h3>
<p>스프링 프레임워크에서 사용되는 어노테이션은 크게 세 가지로 구분할 수 있습니다.</p>
<ul>
<li><p>스프링 프레임워크 어노테이션: 스프링 프레임워크에서 기본적으로 제공되는 어노테이션입니다. 대표적으로 @Autowired, @Component, @Controller, @Service, @Repository 등이 있습니다.</p>
</li>
<li><p>자바 표준 어노테이션: 자바에서 제공하는 어노테이션으로, 스프링 프레임워크에서도 사용할 수 있습니다. 대표적으로 @Override, @Deprecated, @SuppressWarnings 등이 있습니다.</p>
</li>
<li><p>JPA 어노테이션: JPA(Java Persistence API)에서 사용하는 어노테이션입니다. 스프링에서는 데이터베이스 연동을 위해 JPA를 사용하는 경우가 많기 때문에, 이러한 어노테이션을 함께 사용합니다. 대표적으로 @Entity, @Id, @GeneratedValue, @Column 등이 있습니다.</p>
</li>
</ul>
<p>이러한 어노테이션을 사용하여 스프링 프레임워크에서는 빠르고 쉽게 빈 객체를 생성하고 의존성을 관리할 수 있습니다. 이 외에도 스프링부트에서는 다양한 어노테이션을 제공하여 개발자의 생산성을 높이는데 기여하고 있습니다.</p>
<hr>

<h3 id="controller-requestmapping">@Controller, @RequestMapping</h3>
<p>• @Controller – 해당 클래스의 인스턴스를 스프링의 빈으로 등록하고 컨트롤러로 사용</p>
<pre><code>• &lt;component-scan&gt; 과 같이 활용</code></pre><p>• @RequestMapping – 특정한 URI에 대한 처리를 해당 컨트롤러나 메서드에서 처리</p>
<pre><code>package org.hj.controller

@Controller
@RuquestMapping(value =&quot;sample&quot;)
public class A{    // 클래스 - controller역할을 하는 클래스

        @RuquestMapping(value =&quot;aaa&quot;, method = RequestMethod.Get)
        public String home(Locale locale, Model model){
            return &quot;home&quot;;    // /WEB-INF/views/home.jsp
        }
}

@Controller
public class A{    // 클래스 - controller역할을 하는 클래스

        @RuquestMapping(value =&quot;sample/aaa&quot;, method = RequestMethod.Get)
        public String home(Locale locale, Model model){
            return &quot;home&quot;;    // /WEB-INF/views/home.jsp
        }
}</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3840af12-65bd-4cd7-8451-3cb6b14ec8a0/image.png" alt=""></p>
<h3 id="requestmapping의-변화">RequestMapping의 변화</h3>
<p>• 스프링 4.3 전까지는 @RequestMapping( method =‘get’) 방식으로 사용
• 스프링 4.3이후에는 @GetMapping, @PostMapping등으로 간단히 표현 가능</p>
<pre><code>@Controller
public class A{    // 클래스 - controller역할을 하는 클래스
        // @RuquestMapping(value =&quot;sample/aaa&quot;, method = RequestMethod.POST)
        @POSTMapping(value=&quot;aaa&quot;)
        public String home(Locale locale, Model model){
            return &quot;home&quot;;    // /WEB-INF/views/home.jsp
        }
}</code></pre><hr>

<h3 id="컨트롤러의-파라미터-수집">컨트롤러의 파라미터 수집</h3>
<ul>
<li>스프링 MVC의 컨트롤러는 메서드의 파라미터를 자동  으로 수집, 변환하는 편리한 기능을 제공</li>
<li>Java Beans 규칙에 맞게 작성되어야 한다.
 • 생성자가 없거나 빈 생성자
 • 올바른 규칙으로 만들어진 Getter/Setter</li>
</ul>
<p>메서드를 통해 간접적으로 불러와 사용
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a6ccf287-ebb9-4915-a2d7-6085df0b1985/image.png" alt=""></p>
<p>리스트/배열을 사용
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5a2534cd-037f-4d1c-a531-55d1fb173b77/image.png" alt=""></p>
<h4 id="자바-배열의-종류">자바 배열의 종류</h4>
<ul>
<li><p>고정배별
int[] score = new int[5];
단점 : 메모리의 낭비, 데이터를 추가하려면 값을 변경해주어야한다.</p>
</li>
<li><p>가변배열
defalut로 10칸을 만들어준다.</p>
</li>
<li><p><em>장점*</em> : 메모리 낭비를 줄여줌. (3칸을 사용하면 나머지는 버려준다)
새로운 값이 들어오더라도 배열의 크기를 알아서 바꿔주기 때문에 편함.</p>
</li>
<li><p><em>단점*</em> : 자동정렬이기 때문에 검색에 이용하기엔 적합하지 않다.</p>
<pre><code>ArrayList&lt;Integer&gt; score = new ArrayList&lt;Integer&gt;</code></pre></li>
</ul>
<h3 id="model이라는-데이터전달자">Model이라는 데이터전달자</h3>
<p>• Model 객체는 JSP에 컨트롤러에서 생성된 데이터를 담아서 전달하는 역할을 하는 존재
• 모델 2 방식에서 사용하는 equest.setAttribute( )와 유사한 역할</p>
<p><strong>[클래스를 이용해 전달]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/21ffbf82-c3ca-46ab-bef2-e5886b29e205/image.png" alt=""></p>
<h3 id="modelattribute">@ModelAttribute</h3>
<p>• 컨트롤러에서 메서드의 파라미터는 기본자료형을 제외한 객체형 타입은 다시 화면으로 전달
• @ModelAttribute는 명시적으로 화면에 전달되도록 지정</p>
<p><strong>[어노테이션을 이용해 전달]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/784a824e-08c5-4aa9-a724-b0b8afc13da0/image.png" alt=""></p>
<p>SampleDTO에 대한 정보는 위의 스크린샷에 선언해둔걸 참고.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a05b9100-45ec-4039-9d64-bb110130b2c6/image.png" alt=""></p>
<h3 id="redirectattribute">RedirectAttribute</h3>
<p>• 화면에 한번만 전달되는 파라미터를 처리하는 용도
• 내부적으로 HttpSession객체에 담아서 한번만 사용되고, 폐기</p>
<ul>
<li>RedirectAttributes를 이용한 Redirect: RedirectAttributes 객체를 이용하여 Redirect할 URL과 함께 필요한 데이터를 전달합니다. 이후 스프링은 해당 URL로 Redirect합니다. 이 방법은 ModelAndView 객체를 반환하는 방법보다 간결하고 편리합니다.<pre><code>@RequestMapping(value = &quot;/redirect&quot;, method = RequestMethod.POST)
public String redirectExample(@ModelAttribute(&quot;exampleForm&quot;) ExampleForm exampleForm, RedirectAttributes redirectAttributes) {
  redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;Redirect Example&quot;);
  return &quot;redirect:/redirected&quot;;
}</code></pre>위의 예시 코드에서는 /redirect 경로에 POST 요청이 들어오면, redirectAttributes 객체를 이용하여 &quot;message&quot;라는 이름의 속성을 추가합니다. 이후 &quot;redirect:/redirected&quot; URL로 Redirect합니다. Redirect 된 이후, /redirected 경로에 대한 처리가 이루어지며, 해당 경로에서는 edirectAttributes 객체를 이용하여 추가한 속성을 사용할 수 있습니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/99409a82-c281-4125-9dbe-c703eda8c7f9/image.png" alt=""></li>
</ul>
<h3 id="redirect">Redirect</h3>
<p>서버가 클라이언트에게 새로운 URL로 요청을 재전송하도록 요청을 만들어 전송하는 것을 의미합니다. Redirect는 사용자가 다른 페이지로 이동할 때 주로 사용되며, 주로 POST 요청을 받았을 때 다른 페이지로 Redirect 하는 경우가 많습니다.</p>
<p>스프링에서 Redirect를 사용하기 위해서는 다음과 같은 방법을 사용합니다.</p>
<ul>
<li>ModelAndView 객체를 이용한 Redirect: ModelAndView 객체를 생성하고 setViewName() 메서드를 사용하여 Redirect할 URL을 설정한 후, ModelAndView 객체를 반환합니다. 이후 스프링은 해당 URL로 Redirect합니다.</li>
</ul>
<pre><code>@RequestMapping(value = &quot;/redirect&quot;, method = RequestMethod.POST)
public ModelAndView redirectExample(@ModelAttribute(&quot;exampleForm&quot;) ExampleForm exampleForm, RedirectAttributes redirectAttributes) {
    redirectAttributes.addFlashAttribute(&quot;message&quot;, &quot;Redirect Example&quot;);
    ModelAndView mav = new ModelAndView();
    mav.setViewName(&quot;redirect:/redirected&quot;);
    return mav;
}
</code></pre><hr>

<h3 id="forward">forward</h3>
<p>Forward는 클라이언트의 요청을 그대로 유지한 채, 서버에서 페이지를 처리하고 결과를 클라이언트에게 반환하는 방식입니다. 즉, 서버는 클라이언트에게 새로운 요청을 보내지 않고, 현재 요청에 대한 처리 결과를 바로 반환합니다. 따라서 Forward는 URL이 변경되지 않으며, 클라이언트는 기존의 요청 정보를 그대로 유지하게 됩니다.</p>
<p>Forward는 사용자의 요청에 대한 추가적인 처리가 필요한 경우에 유용합니다. 예를 들어, 로그인 정보를 체크한 후 로그인 처리를 하는 경우에는 Forward 방식으로 다음 페이지로 이동할 수 있습니다.</p>
<p>다음은 Redirect와 Forward의 차이점을 요약한 내용입니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d6cb6503-86b2-4724-b09f-bb105670ff1c/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/84a3476c-209d-4936-b530-1bf36c3204c7/image.png" alt=""></p>
<hr>

<h3 id="controller의-리턴타입">Controller의 리턴타입</h3>
<p>• String: jsp를 이용하는 경우에는 jsp 파일의 경로와 파일이름을 나타내기 위해서 사용
• void: 호출하는 URL과 동일한 이름의 jsp를 의미
• VO, DTO 타입: 주로 JSON 타입의 데이터를 만들어서 반환하는 용도로 사용 (추가적인 라이브러리 필요).
• ResponseEntity 타입: response할 때 Http 헤더 정보와 내용을 가공하는 용도로 사용 (추가적인 라이브러리 필요).
• Model, ModelAndView: Model로 데이터를 반환하거나 화면까지 같이 지정하는 경우에 사용 (최근에는 많이 사용하지 않습니다.).
• HttpHeaders: 응답에 내용 없이 Http 헤더 메시지만 전달하는 용도로 사용</p>
<hr>

<h3 id="void-타입">Void 타입</h3>
<p>• 호출하는 URL과 동일한 이름의 jsp타입</p>
<pre><code>@GetMappin(&quot;/ex05&quot;)
public void ex05(){
 log.info(&quot;/ex05..........&quot;);
}</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/45fe997a-4810-400a-ae8e-e6c8815a0db5/image.png" alt=""></p>
<hr>

<h3 id="string-타입">String 타입</h3>
<ul>
<li>상황에 따라 다른 화면을 보여줄 필요가 있을 경우에 유용하게
사용</li>
<li>String 타입에는 다음과 같은 특별한 키워드를 붙여서 사용할 수 있음
• redirect: 리다이렉트 방식으로 처리하는 경우
• forward: 포워드 방식으로 처리하는 경우</li>
</ul>
<hr>

<h3 id="객체-타입">객체 타입</h3>
<ul>
<li>XML이나 JSON으로 처리</li>
<li>@RepsoneBody어노테이션과 같이 사용
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5fc93671-b00f-4981-bfa7-dfa2f0967840/image.png" alt=""></li>
</ul>
<hr>

<h3 id="responseentity">ResponseEntity</h3>
<ul>
<li>통신 상태 확인할때 사용</li>
<li>HTTP헤더 정보와 추가적인 데이터를 전달할 때 사용
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5a4f501c-1683-4982-870f-8c34d53c2353/image.png" alt=""></li>
</ul>
<hr>

<h3 id="파일업로드-처리">파일업로드 처리</h3>
<p>• Servlet 3.0이후(Tomcat 7.0)에는 기본적으로 업로드 되는 파일을 처리할 수 있는 기능이 추가
• 별도로 commons-fileupload 라이브러리 등을 사용
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ec24f6af-6205-40c7-b328-d58d9e450898/image.png" alt=""></p>
<hr>

<h3 id="파일-업로드를-위한-servlet-contextxml">파일 업로드를 위한 servlet-context.xml</h3>
<p>• multipartResolver라는 이름으로 스프링 빈 설정
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d3006085-113c-4f06-aad1-98315cbfd02e/image.png" alt=""></p>
<hr>

<h3 id="파일업로드를-위한-html">파일업로드를 위한 HTML</h3>
<pre><code>• &lt;form&gt;태그내 enctype=‘multipart</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3ec673e3-d146-4075-b453-32f4e1376070/image.png" alt=""></p>
<hr>

<h3 id="업로드되는-파일의-처리">업로드되는 파일의 처리</h3>
<p>• MultipartFile을 이용해서 처리
<img src="https://velog.velcdn.com/images/jjinny_0609/post/18de4e58-23b7-4e5a-8287-1ff3d9b8fdc3/image.png" alt=""></p>
<hr>

<h3 id="springex-예제파일">SpringEx 예제파일</h3>
<h4 id="homecontrollerjava">HomeController.java</h4>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/840b8821-67ef-4172-a592-1f4ffd1ee54b/image.png" alt=""></p>
<h4 id="membercontrollerjava">MemberController.java</h4>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/ea976cf5-33a5-4466-bf05-2e57efa8fc8d/image.png" alt="">
서버를 실행시키고 주소창에 localhost:8080/member를 치면 MemberController.java에서 아래와 같이 파일을 불러와서 화면을 출력하게 된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/608c3f87-3e8e-4077-83d2-c451f80d2c18/image.png" alt="">
화면이 출력 된 모습
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c3747157-e16e-4abf-ae62-860a160e7954/image.png" alt=""></p>
<p><strong>값이 똑같더라도 Method값이 다르면 상관없다.</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/08195a23-88a5-4a47-bef9-bfe66ad15450/image.png" alt=""></p>
<p>회원가입을 눌러보면
<img src="https://velog.velcdn.com/images/jjinny_0609/post/7acf52a5-4cc9-4228-bce4-2555157dfa52/image.png" alt="">
form action의 method값이 =&quot;post&quot;이므로 가입하기(submit)를 누르면 board/list로 이동한다. 즉 파란색 상자에 있는 method = RequestMethod.POST값과 일치해서 board/list로 이동하게 되는 것이다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/730e872c-5c6b-4617-9344-57c041363a9c/image.png" alt="">
값들은 LoginVo로 받아와서 값을 저장하게 된다.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/f68365c2-fbaf-432a-a39b-da559d51c129/image.png" alt="">
Console창에서 값을 받아온것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/1d46c14d-7f8a-4f8e-a496-7d1a57ac46f8/image.png" alt=""></p>
<hr>

<h3 id="object-클래스의-tostring-메서드">Object 클래스의 toString 메서드</h3>
<p>모든 클래스는 Object 클래스를 상속하므로, 모든 객체는 toString 메서드를 사용할 수 있습니다. 하지만 Object 클래스의 toString 메서드는 단순히 객체의 클래스 이름과 객체의 해시 코드를 문자열로 반환하기 때문에, 실제 사용에 적합하지 않을 수 있습니다.</p>
<p>따라서, 보다 구체적인 문자열 표현이 필요한 경우, toString 메서드를 오버라이딩하여 사용할 수 있습니다. 이 때, toString 메서드는 객체의 속성들을 적절한 포맷으로 문자열로 변환하여 반환합니다.</p>
<p>예를 들어, 다음과 같이 Person 클래스가 있다고 가정해 봅시다.</p>
<pre><code>public class Person {
    private String name;
    private int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return &quot;Person{name=&#39;&quot; + name + &quot;&#39;, age=&quot; + age + &quot;}&quot;;
    }
}
</code></pre><p>위 코드에서는 toString 메서드를 오버라이딩하여 Person 객체의 이름과 나이를 문자열로 반환하도록 구현했습니다. 이제, Person 객체를 생성하고 해당 객체의 toString 메서드를 호출하면 다음과 같은 결과를 얻을 수 있습니다.</p>
<pre><code>Person person = new Person(&quot;John&quot;, 30);
System.out.println(person.toString());
// 출력 결과: Person{name=&#39;John&#39;, age=30}</code></pre><p>toString 메서드를 오버라이딩하면, 객체의 디버깅이나 로깅 등에서 유용하게 사용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/7c3616da-44f3-47ec-b751-ee6ca5ffd937/image.png" alt=""></p>
<p>// 새로고침 할때마다 값이 계속 뜨는 이유는 상속에 대해서 정의를 안하면 오브젝트 클래스를 상속받게 되어있음
// 지금 상속을 받지 않아서 해당되는 toString은 객체의 주소값을 출력하라고 되어있음
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6ba67e80-71c9-438b-b05b-7b494e17f94f/image.png" alt=""></p>
<hr>

<h3 id="로그인--회원가입-구조">로그인 / 회원가입 구조</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/457afa0c-130f-4be9-b704-78940c237a51/image.png" alt=""></p>
<hr>

<h3 id="springex-예제-회원가입-해보기">SpringEx 예제 회원가입 해보기</h3>
<p>해당하는 폴더에 코드 값을 수정해주고 실행
<img src="https://velog.velcdn.com/images/jjinny_0609/post/648d1bb8-08ab-4759-8d3f-2db69c72f47c/image.png" alt="">
아이디와 비밀번호를 별명을 입력하고 회원가입을 누르면 아래와 같이 나오면 정상적으로 회원가입 된것이다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e6a8c178-63f1-4e98-96b2-76a5f68fa25d/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[스프링(Spring) #1]]></title>
            <link>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-1</link>
            <guid>https://velog.io/@jjinny_0609/%EC%8A%A4%ED%94%84%EB%A7%81Spring-1</guid>
            <pubDate>Mon, 27 Mar 2023 07:07:59 GMT</pubDate>
            <description><![CDATA[<h1 id="스프링spring">스프링(Spring)</h1>
<p>자바 언어를 기반으로 한 오픈소스 프레임워크입니다. 스프링은 자바 엔터프라이즈 개발에 필요한 기능을 제공하며, IoC(Inversion of Control) 컨테이너와 AOP(Aspect Oriented Programming) 등의 기능을 포함하고 있습니다. 스프링을 사용하면 자바 언어로 웹 어플리케이션을 개발할 때 많은 부분을 자동화할 수 있습니다.</p>
<p>스프링은 다양한 모듈로 구성되어 있으며, 각 모듈은 다음과 같은 기능을 제공합니다.</p>
<ol>
<li>스프링 컨테이너: 객체의 생명주기를 관리하는 IoC 컨테이너를 제공합니다.</li>
<li>스프링 MVC: 웹 어플리케이션을 개발하기 위한 MVC 패턴을 구현하는 기능을 제공합니다.</li>
<li>스프링 데이터: 데이터베이스 연동을 쉽게 할 수 있는 기능을 제공합니다.</li>
<li>스프링 시큐리티: 인증과 권한을 관리하는 보안 기능을 제공합니다.</li>
<li>스프링 부트: 스프링 어플리케이션을 빠르고 쉽게 개발할 수 있도록 도와주는 기능을 제공합니다.</li>
</ol>
<p>스프링의 주요 특징은 다음과 같습니다.</p>
<ol>
<li>경량성: 스프링은 경량 프레임워크로서 불필요한 기능이나 라이브러리를 배제하여 빠르고 가벼운 어플리케이션을 구현할 수 있습니다.</li>
<li>모듈성: 스프링은 다양한 모듈로 구성되어 있어 필요한 기능만 사용할 수 있습니다.</li>
<li>유연성: 스프링은 객체 지향적인 개발 방식을 지원하며, 다양한 라이브러리와 연동하여 사용할 수 있습니다.</li>
<li>테스트 지원: 스프링은 자동화된 테스트 환경을 제공하여 개발 및 테스트를 용이하게 할 수 있습니다.</li>
</ol>
<p>따라서, 스프링은 자바 언어로 웹 어플리케이션을 개발하기 위한 필수적인 기술 중 하나로, 많은 개발자들이 사용하고 있습니다.</p>
<h2 id="스프링-설치방법">스프링 설치방법</h2>
<p><strong>※ 자바가 설치되어 있어야함.</strong></p>
<ul>
<li><p>스프링 설치방법 두가지
Eclipse or STS</p>
</li>
<li><p>Eclipse 
STS 플로그인 추가 설치 후 사용</p>
</li>
<li><p>STS
Eclipse와 별도로 다운로드 및 압축 해제</p>
</li>
</ul>
<h3 id="설치-진행">설치 진행</h3>
<p>About Eclipse IDE(버전 확인)
<img src="https://velog.velcdn.com/images/jjinny_0609/post/0cb245b2-3dd7-4f0e-8643-ca94161269c4/image.png" alt=""></p>
<p>관리자 권한으로 이클립스 재실행후 설치 진행
현재 버전 확인(4.8)
<img src="https://velog.velcdn.com/images/jjinny_0609/post/125c83ea-1ded-4f94-bfa0-ba41b97c1a2a/image.png" alt=""></p>
<p>Help - Install New Software...
<img src="https://velog.velcdn.com/images/jjinny_0609/post/be0a0073-bdcb-4f8a-a45b-988cfdf81d43/image.png" alt=""></p>
<p>Add... - Add Repository 아래 스크린샷과 같이 작성 후 Add</p>
<p>name은 본인이 임의로 작성
Location에 복사해서 넣기</p>
<pre><code>http://download.springsource.com/release/TOOLS/update/e4.8</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/0c05d634-92e7-426a-91f2-a5679f57464c/image.png" alt=""></p>
<p>Select All - Next &gt;
<img src="https://velog.velcdn.com/images/jjinny_0609/post/45b63e38-ee46-4d71-b67b-b409a954f508/image.png" alt=""></p>
<p>Next를 누르면 설치가 진행된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e7fe9756-d15f-4245-ae32-f0c9649c984b/image.png" alt=""></p>
<p>동의후 Finish
<img src="https://velog.velcdn.com/images/jjinny_0609/post/29cd3a17-06b1-40a6-97be-ebac03e25ebc/image.png" alt=""></p>
<p>하단에 Installing Software 설치되고 있다고 알려줌.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c33de2c4-38d0-472a-996d-d81b69a7511a/image.png" alt=""></p>
<p>어쨋든 설치 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/178c354d-9c53-4e5b-b1b0-230a2ba3d316/image.png" alt=""></p>
<p>Select All 후
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b8f63e7f-eb64-421f-9295-968fb069fa9b/image.png" alt=""></p>
<p>Restart Now 클릭 하면 재시작하면서 설치가 완료된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6f5cb29a-310c-4218-9b53-b63d311654db/image.png" alt=""></p>
<p>설치가 완료된 모습
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c95bf802-05d8-4d3e-b13e-6a34fb370238/image.png" alt=""></p>
<hr>

<h4 id="스프링-예제파일-추가하기">스프링 예제파일 추가하기</h4>
<p>File - Open Projects from File System... 클릭</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/7bd7b22e-ef3a-40e7-8e79-cfd93e152941/image.png" alt=""></p>
<p>Directory... 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6171a33a-21df-4425-9c24-bc01781364d4/image.png" alt=""></p>
<p>Spring 예제 파일을 추가
<img src="https://velog.velcdn.com/images/jjinny_0609/post/70cda3f6-f135-4438-ad7f-2b20451f9000/image.png" alt=""></p>
<p>파일이 추가된 것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/38fb64c5-b77d-4d22-852c-4cc08365e88f/image.png" alt=""></p>
<hr>

<h3 id="spring-예제-폴더-설명">Spring 예제 폴더 설명</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/555c4510-48d5-4d20-b913-225a4e728467/image.png" alt=""></p>
<p>main : 구현하는 곳</p>
<ul>
<li>test : 테스트 하는 곳(없어도 됨)\</li>
<li>views : 사용자에게 보여주는 부분(.jsp 파일을 저장)</li>
</ul>
<p>resources</p>
<ul>
<li>META-INF :  Java Archive(JAR) 파일, Java Web Archive(WAR) 파일, Java Enterprise Archive(EAR) 파일 등 Java 애플리케이션에서 사용되는 압축 파일들의 메타 데이터를 포함하는 특별한 폴더입니다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/59523a0b-8592-4046-9f1e-bd8947bee8db/image.png" alt=""></p>
<p>src/main/java/org/hj/controller : controller가 있는 위치 controller는 진입점</p>
<p>src/main/java/org/hj/model : model의 위치</p>
<p>MVC패턴을 사용해 업무분담을 위해서 위와 같이 폴더를 구성하고 사용한다.</p>
<h3 id="spring-legacy-project">Spring Legacy Project</h3>
<p>스프링 프로젝트 생성
File-New-Spring Legacy Project
<img src="https://velog.velcdn.com/images/jjinny_0609/post/47ad6176-4515-4f57-ac74-dd5e68548eaa/image.png" alt="">
프로젝트명 작성(팀으로 작업하는 경우 프로젝트 명을 통일시켜줘야 한다.),
현재는 projectEx로 예제를 보는 중
<img src="https://velog.velcdn.com/images/jjinny_0609/post/aafc5599-6c96-4fad-975a-5c675c7fa24f/image.png" alt=""></p>
<p>패키지명 생성
ex) org.hj.controller
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9c31c573-ed6b-4ce2-b46b-a6bd93f145f9/image.png" alt=""></p>
<p>만들게 되면 아래와 같이 생성된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9fc1ef03-7161-4920-a89e-c5a3ac330f97/image.png" alt=""></p>
<p>기본적으로 HomeController.java가 생성되며,
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bc926a95-6ec8-4058-834f-0dfa2805f178/image.png" alt=""></p>
<p>패키지를 더 만들어서 작업이 필요하다면 생성하는 것도 가능하다.</p>
<hr>

<h3 id="스프링에서-실행하기">스프링에서 실행하기</h3>
<p>Controller(진입점)을 반드시 거쳐서 실행해야한다.</p>
<p>프로젝트를 선택후 우클릭 Run As - Run On Server
<img src="https://velog.velcdn.com/images/jjinny_0609/post/de397a87-863a-4315-ba47-da78a87c7307/image.png" alt="">
Next
<img src="https://velog.velcdn.com/images/jjinny_0609/post/dcbd6fb8-46c2-4af0-bb38-bfd51aa3a72e/image.png" alt=""></p>
<p>아래와 같은 화면이 나타날것이다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e56e87a6-dd49-4486-9100-844c7ce212eb/image.png" alt=""></p>
<p>실행할 작업영역을 ADD를 누르거나 더블클릭으로 오른쪽으로 이동시켜주자.</p>
<p>실행했을때 다음과 같은 오류가 발생한다면
<img src="https://velog.velcdn.com/images/jjinny_0609/post/393ed6bb-c4e6-461f-ae0d-598cf4f2729d/image.png" alt="">
src/main/webapp/WEB-INF/spring/root-context.xml 파일 실행
<img src="https://velog.velcdn.com/images/jjinny_0609/post/75cbdde3-2a4d-489e-af0b-481313a5e618/image.png" alt="">
url 경로와 Username과 password를 확인해주자
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6b998918-d674-4c3f-ab68-7c753b49cbd9/image.png" alt="">
확인했다면 수정하고 저장</p>
<p>그래도 오류가 터진다면
C:\Users\GR.m2\repository
경로에 있는 파일을 다 지워주고 이클립스 재시작하면 파일을 자동으로 다시 받게된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/722fccd9-734a-426a-adcd-9daf8d7dedb3/image.png" alt=""></p>
<p>jstl을 workspace에 넣고 Maven update(갱신)를 해주자</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/c82c88c0-0038-4d1b-bedf-a2e9fbacab81/image.png" alt=""></p>
<p>마지막으로 Clean눌러주고
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b1605388-86f0-4b2b-a4b4-744bd1516f04/image.png" alt=""></p>
<hr>

<p><a href="http://localhost:8080/%EC%84%9C%EB%B2%84%EC%9D%B4%EB%A6%84(%EB%8F%84%EB%A9%94%EC%9D%B8)">http://localhost:8080/서버이름(도메인)</a>
더블클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2808d280-8c0b-447a-bff0-1cc75b35740a/image.png" alt=""></p>
<p>Edit을 눌러서 Path를 수정할 수 있습니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bc92d981-6ba9-495c-b6a7-dc02e0053102/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3d21e2b0-f7a0-4987-8b87-a18f6cc60003/image.png" alt="">
/ 만 넣어서 localhost:8080 으로 변경 , localhost:8080뒤만 수정 할 수 있다.</p>
<hr>

<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/37aed257-a186-4694-b470-a6aa8a5519f1/image.png" alt=""></p>
<pre><code>servlet-context.xml // 서버 역할을 하는 파일
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;beans:beans xmlns=&quot;http://www.springframework.org/schema/mvc&quot;
    xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
    xmlns:beans=&quot;http://www.springframework.org/schema/beans&quot;
    xmlns:context=&quot;http://www.springframework.org/schema/context&quot;
    xsi:schemaLocation=&quot;http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd
        http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd&quot;&gt;

    &lt;!-- DispatcherServlet Context: defines this servlet&#39;s request-processing infrastructure --&gt;

    &lt;!-- Enables the Spring MVC @Controller programming model --&gt;
    &lt;annotation-driven /&gt;

    &lt;!-- Handles HTTP GET requests for /resources/** by efficiently serving up static resources in the ${webappRoot}/resources directory --&gt;
    &lt;resources mapping=&quot;/resources/**&quot; location=&quot;/resources/&quot; /&gt;

    &lt;!-- Resolves views selected for rendering by @Controllers to .jsp resources in the /WEB-INF/views directory --&gt;
    &lt;beans:bean class=&quot;org.springframework.web.servlet.view.InternalResourceViewResolver&quot;&gt;
        &lt;beans:property name=&quot;prefix&quot; value=&quot;/WEB-INF/views/&quot; /&gt;
        &lt;beans:property name=&quot;suffix&quot; value=&quot;.jsp&quot; /&gt;
    &lt;/beans:bean&gt;

    &lt;context:component-scan base-package=&quot;org.hj.controller&quot; /&gt;

    &lt;beans:bean id=&quot;multipartResolver&quot; class=&quot;org.springframework.web.multipart.support.StandardServletMultipartResolver&quot;&gt;
    &lt;/beans:bean&gt;

&lt;/beans:beans&gt;
</code></pre><hr>

<h3 id="controller-와-jsp의-관계">Controller 와 jsp의 관계</h3>
<p>Controller는 Spring MVC에서 요청을 받아들이고, 처리할 Service와 DAO를 호출한 후, 결과를 Model에 담아 View에 전달하는 역할을 합니다. View는 일반적으로 JSP 페이지로 구성되며, Controller가 전달한 Model 객체의 데이터를 화면에 표시합니다.</p>
<p>따라서, Controller와 JSP는 서로 밀접한 관계가 있습니다. Controller는 사용자가 요청한 URI를 분석하고, 해당 요청을 처리하기 위한 비즈니스 로직을 실행한 후, 결과를 Model에 담아 JSP에 전달합니다. JSP는 Model 객체의 데이터를 화면에 표시하고, 사용자에게 결과를 제공합니다.</p>
<p>이러한 관계에서, JSP는 HTML과 Java 코드를 함께 사용할 수 있는 동적인 페이지로 작성됩니다. JSP는 HTML과 같은 정적인 페이지와 달리, Java 코드를 사용하여 동적으로 데이터를 생성하고, 화면에 표시할 수 있습니다. JSP는 일반적으로 View를 담당하는 역할을 하지만, Controller와 Model 객체와 함께 작동하여 전체 Spring MVC 애플리케이션에서 중요한 역할을 합니다.</p>
<p>즉, Controller와 JSP는 Spring MVC에서 함께 동작하여 사용자의 요청을 처리하고, 데이터를 화면에 표시하는 데 중요한 역할을 합니다. 이를 통해 사용자가 애플리케이션을 사용하는 데 있어서 좀 더 직관적이고 편리한 환경을 제공할 수 있습니다.</p>
<hr>

<h3 id="spring-mvc에서-url-규칙">Spring MVC에서 URL 규칙</h3>
<p>Spring MVC에서 URL 규칙은 일반적으로 다음과 같습니다.</p>
<p>요청 URL이 들어오면, DispatcherServlet이 해당 요청을 처리합니다.</p>
<p>DispatcherServlet은 HandlerMapping을 사용하여 적절한 Controller를 찾습니다.</p>
<p>Controller는 요청을 처리하고, 결과를 Model 객체에 담아 View 이름을 반환합니다.</p>
<p>DispatcherServlet은 ViewResolver를 사용하여 View를 찾습니다.</p>
<p>View는 Model 객체를 사용하여 요청 결과를 생성하고, 클라이언트에게 전송합니다.</p>
<p>URL 규칙은 다음과 같이 정의될 수 있습니다.</p>
<p>요청 URL은 일반적으로 다음과 같은 형식으로 구성됩니다.</p>
<pre><code>http://&lt;hostname&gt;:&lt;port&gt;/&lt;context&gt;/&lt;servlet&gt;/&lt;path&gt;
</code></pre><p>context는 애플리케이션 이름이며, web.xml 파일에서 설정할 수 있습니다.</p>
<p>servlet은 DispatcherServlet의 이름이며, web.xml 파일에서 설정할 수 있습니다.</p>
<p>path는 Controller에서 처리할 요청 경로입니다. 예를 들어, /board/list는 BoardController에서 list() 메서드를 호출하여 요청을 처리합니다.</p>
<p>Controller에서 반환하는 View 이름은 일반적으로 다음과 같은 형식으로 구성됩니다.</p>
<pre><code>&lt;prefix&gt;&lt;viewName&gt;&lt;suffix&gt;</code></pre><p>prefix는 ViewResolver에서 사용하는 접두어입니다. 일반적으로 &quot;/WEB-INF/views/&quot;를 사용합니다.</p>
<p>viewName은 Controller에서 반환하는 View 이름입니다.</p>
<p>suffix는 ViewResolver에서 사용하는 접미어입니다. 일반적으로 &quot;.jsp&quot;를 사용합니다.</p>
<p>예를 들어, &quot;/board/list&quot;라는 요청 URL이 들어오면, DispatcherServlet은 BoardController의 list() 메서드를 호출하여 요청을 처리합니다. list() 메서드는 Model 객체에 게시글 목록을 저장하고, &quot;board/list&quot;라는 View 이름을 반환합니다. DispatcherServlet은 ViewResolver를 사용하여 &quot;/WEB-INF/views/board/list.jsp&quot;를 찾고, 이를 사용하여 요청 결과를 생성합니다.</p>
<p><strong>[예제]</strong></p>
<p>실제 실행되는 파일은 빨간색 밑줄로 표시했습니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b4cc4c49-622d-4661-b6d6-bef63a007d8a/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/50594d6c-1812-4886-959c-e1a4b6931837/image.png" alt=""></p>
<hr>

<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/540ff0c4-3e7b-4997-b146-4fc78d5c7aa2/image.png" alt=""></p>
<p>pom.xml에 작성되는 코드는 본인이 임의로 작성하지말고 아래의 링크에서 필요한것만 가져와서 복사해서 사용하면 된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/652ebe76-68da-4ce6-b14c-583d4172a30b/image.png" alt=""></p>
<p><a href="https://mvnrepository.com/">https://mvnrepository.com/</a> 으로 접속</p>
<p>mysql에 필요한 한것이 있다면 mysql로 검색
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f2aa50ae-bbe2-4fc9-98b7-f54c2bb5dc7d/image.png" alt=""></p>
<p>해당하는 버전클릭후 아래의 Maven을 복사해서 코드를 붙여넣자
<img src="https://velog.velcdn.com/images/jjinny_0609/post/0896ab1d-9371-40c4-af31-0b2d24a14727/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSP #6]]></title>
            <link>https://velog.io/@jjinny_0609/JSP-6</link>
            <guid>https://velog.io/@jjinny_0609/JSP-6</guid>
            <pubDate>Mon, 27 Mar 2023 00:36:32 GMT</pubDate>
            <description><![CDATA[<h3 id="커넥션-풀">커넥션 풀</h3>
<p>커넥션 풀(Connection Pool)은 데이터베이스와 연결된 커넥션(Connection)을 미리 생성해 놓고, 필요할 때마다 커넥션을 가져다 쓰고 반납하는 방식으로 데이터베이스 연결을 관리하는 기술입니다.</p>
<p>일반적으로 데이터베이스 연결은 매번 새로운 연결을 생성하고 연결을 종료하는 과정이 필요합니다. 하지만 이 방식은 매번 연결을 생성하고 종료하기 때문에 불필요한 자원 낭비가 발생할 수 있습니다. 또한, 많은 사용자가 동시에 데이터베이스에 접근하는 경우에는 연결을 생성하는 데에 많은 시간이 소요될 수 있습니다.</p>
<p>커넥션 풀을 사용하면 데이터베이스 연결을 미리 생성해 놓고 필요할 때마다 커넥션을 가져다 쓰고 반납하는 방식으로 데이터베이스 연결을 관리합니다. 이렇게 함으로써 불필요한 자원 낭비를 줄이고, 데이터베이스 연결을 더욱 효율적으로 관리할 수 있습니다.</p>
<p>JSP에서 커넥션 풀을 구현하기 위해서는 일반적으로 JDBC(Java Database Connectivity) API를 사용합니다. JDBC API를 사용하여 데이터베이스와 연결된 커넥션을 생성하고, 커넥션 풀에서 관리합니다. JSP에서는 보통 커넥션 풀 라이브러리인 Apache Tomcat JDBC Connection Pool, HikariCP, c3p0 등을 사용합니다. 이러한 라이브러리를 사용하면 커넥션 풀을 더욱 편리하게 구현할 수 있습니다.</p>
<h3 id="dbcp">DBCP</h3>
<p>DBCP(Apache Commons DBCP)는 Apache Commons 프로젝트에서 제공하는 커넥션 풀 라이브러리 중 하나로, JSP에서 데이터베이스 연결을 관리하기 위해 자주 사용됩니다.</p>
<p>DBCP는 JDBC 드라이버를 로드하고, 데이터베이스와 연결된 커넥션을 생성하고, 커넥션 풀에 관리하는 기능을 제공합니다. 또한, DBCP는 커넥션 풀 내의 커넥션 개수를 제한하고, 사용하지 않는 커넥션을 반환하도록 설정할 수 있어서, 데이터베이스 연결에 필요한 자원을 효율적으로 관리할 수 있습니다.</p>
<p>DBCP는 기본적으로 Apache Tomcat에 내장되어 있어서, Tomcat 환경에서는 별도의 설정 없이 바로 사용할 수 있습니다. 또한, DBCP는 XML 파일이나 소스 코드를 이용하여 간단하게 설정할 수 있습니다.</p>
<p>아래는 DBCP를 사용하여 JSP에서 MySQL 데이터베이스와 연결하는 간단한 코드 예시입니다.</p>
<pre><code>import java.sql.*;
import org.apache.commons.dbcp.BasicDataSource;

public class DBConnect {
   private static BasicDataSource dataSource;
   static {
      dataSource = new BasicDataSource();
      dataSource.setDriverClassName(&quot;com.mysql.jdbc.Driver&quot;);
      dataSource.setUrl(&quot;jdbc:mysql://localhost:3306/mydatabase&quot;);
      dataSource.setUsername(&quot;myusername&quot;);
      dataSource.setPassword(&quot;mypassword&quot;);
      dataSource.setInitialSize(5);
      dataSource.setMaxIdle(10);
      dataSource.setMaxTotal(20);
   }

   public static Connection getConnection() throws SQLException {
      return dataSource.getConnection();
   }
}</code></pre><p>위 코드에서는 BasicDataSource 클래스를 사용하여 데이터베이스 연결 정보와 커넥션 풀 설정 정보를 설정하고, getConnection() 메서드를 통해 커넥션을 가져옵니다. 이렇게 설정된 DBCP를 사용하면, JSP에서 데이터베이스 연결을 쉽게 관리할 수 있습니다.
(Apache Tomcat 8버전 이후로는 내장되어있어서 다운받을 필요는 없습니다.)</p>
<h3 id="mvc-패턴">MVC 패턴</h3>
<p>MVC(Model-View-Controller) 패턴은 소프트웨어 디자인 패턴 중 하나로, 소프트웨어의 구조를 세 가지 역할(Model, View, Controller)로 분리하여 개발하는 방법론입니다.</p>
<p>MVC 패턴에서 Model은 애플리케이션의 데이터와 비즈니스 로직을 담당하며, View는 데이터를 시각적으로 표현하는 UI(User Interface)를 담당합니다. Controller는 사용자의 입력에 따라 Model과 View를 제어하고, 사용자와 Model 사이의 상호작용을 담당합니다.</p>
<p>이러한 역할 분담을 통해, 소프트웨어의 구조가 단순하고 유연해지며, 코드의 재사용성과 유지보수성이 향상됩니다. 또한, Model과 View가 분리되어 있어서, 동일한 데이터를 다양한 형식으로 표현하는 다양한 View를 개발할 수 있습니다.</p>
<p>MVC 패턴을 사용하면, 소프트웨어의 각 구성 요소를 독립적으로 테스트할 수 있으므로, 소프트웨어의 품질을 향상시킬 수 있습니다. 또한, 각 역할이 분리되어 있기 때문에, 대규모 프로젝트에서 여러 명의 개발자들이 동시에 작업할 수 있도록 협업이 용이해집니다.</p>
<p>MVC 패턴은 웹 개발에서도 많이 사용됩니다. 예를 들어, Model은 데이터베이스와 상호작용하여 데이터를 처리하고, View는 HTML, CSS, JavaScript 등을 사용하여 UI를 표현하며, Controller는 사용자의 요청을 받아 Model과 View를 조작하여 응답을 생성합니다. 대표적인 MVC 웹 프레임워크로는 Spring MVC, Django 등이 있습니다.</p>
<p>이때, MVC 패턴은 대개 Model2 구조와 Model1 구조 두 가지 형태로 구현됩니다.</p>
<p><strong>Model1 구조</strong>
Model1 구조는 JSP(JavaServer Pages) 페이지에서 비즈니스 로직을 처리하고, 데이터베이스와 연동하여 데이터를 처리하는 방식입니다. 이 구조에서 JSP 페이지는 View와 Controller 역할을 모두 수행하게 됩니다. JSP 페이지에서 데이터베이스 연동과 같은 비즈니스 로직을 처리하게 되므로, 코드가 간단하고 빠르게 개발할 수 있습니다. 그러나, 코드의 유지보수성이 떨어지며, 확장성도 낮아지는 단점이 있습니다. 따라서 대규모 프로젝트에서는 권장되지 않습니다.</p>
<p><strong>Model2 구조</strong>
Model2 구조는 Model1 구조의 단점을 보완하여 만들어진 구조로, 각 역할이 분리되어 있습니다. Model은 비즈니스 로직을 처리하고, 데이터베이스와 연동하여 데이터를 처리합니다. View는 HTML, CSS 등을 사용하여 UI를 구성합니다. Controller는 사용자의 요청을 받아 Model과 View를 연결하여 결과를 반환합니다. 이러한 역할 분담을 통해, 코드의 유지보수성이 높아지고, 확장성도 좋아집니다. 대표적인 Model2 구조의 프레임워크로는 Spring MVC, Struts 등이 있습니다.</p>
<ul>
<li>MVC 패턴의 구조
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9b283e87-6694-495b-ae80-b72f75f4901a/image.png" alt=""></li>
</ul>
<h4 id="mvc의-컨트롤러--서블릿">MVC의 컨트롤러 : 서블릿</h4>
<p>MVC 패턴에서 컨트롤러는 모델과 뷰를 연결해주는 역할을 합니다. 웹 어플리케이션에서는 주로 서블릿(Servlet)을 사용하여 컨트롤러를 구현합니다.</p>
<p>서블릿은 자바로 작성된 웹 어플리케이션의 구성 요소 중 하나로, 클라이언트의 요청을 받아서 처리하고, 그 결과를 다시 클라이언트에게 전송하는 역할을 합니다.</p>
<p>서블릿을 이용하여 MVC 패턴의 컨트롤러를 구현할 때는, 주로 다음과 같은 방식으로 구현합니다.</p>
<ol>
<li>서블릿 클래스에서 클라이언트의 요청을 받아서 처리합니다.</li>
<li>모델 클래스를 이용하여 요청에 대한 데이터를 처리합니다.</li>
<li>뷰 클래스를 이용하여 처리 결과를 클라이언트에게 전달합니다.</li>
</ol>
<p>즉, 서블릿은 클라이언트의 요청을 받아서 모델과 뷰를 연결해주는 역할을 수행합니다. 이를 통해 웹 어플리케이션의 비즈니스 로직과 사용자 인터페이스를 분리하여 관리할 수 있습니다.</p>
<p>서블릿을 이용한 MVC 패턴의 장점은 다음과 같습니다.</p>
<ol>
<li>코드의 재사용성이 높습니다.</li>
<li>유지보수가 용이합니다.</li>
<li>비즈니스 로직과 사용자 인터페이스를 분리하여 개발할 수 있습니다.</li>
</ol>
<p>따라서, 서블릿은 MVC 패턴에서 컨트롤러를 구현하는 데 가장 많이 사용되는 기술 중 하나입니다.</p>
<ul>
<li>컨트롤러 서블릿 내부 동작 방식
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d5383082-165a-4671-84a5-f6f7d6249880/image.png" alt=""></li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSP #5]]></title>
            <link>https://velog.io/@jjinny_0609/JSP-5</link>
            <guid>https://velog.io/@jjinny_0609/JSP-5</guid>
            <pubDate>Fri, 24 Mar 2023 07:46:39 GMT</pubDate>
            <description><![CDATA[<h4 id="form태그">form태그</h4>
<p>기본값(get)
<img src="https://velog.velcdn.com/images/jjinny_0609/post/0fb4496a-7b35-4e52-899d-74da57ded9ef/image.png" alt=""></p>
<p>post는 값이 주소창에 표시되지 않는걸 확인할 수 있다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d569f963-280b-4f67-959e-864485001c08/image.png" alt=""></p>
<h4 id="게시판-내용을-db에-넘기기">게시판 내용을 DB에 넘기기</h4>
<p>[예제<em>게시판]
_<strong>insertBoard.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form action=&quot;insertBoardServer.jsp&quot; method=&quot;post&quot;&gt;
    &lt;table border=&quot;1&quot;&gt;
        &lt;tr&gt;
            &lt;td&gt;제목&lt;/td&gt;
            &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;title&quot;&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;내용&lt;/td&gt;
            &lt;td&gt;&lt;textarea rows=&quot;10&quot; cols=&quot;30&quot; name=&quot;content&quot;&gt;&lt;/textarea&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td colspan=&quot;2&quot;&gt;&lt;input type=&quot;submit&quot; value=&quot;글쓰기&quot;&gt;&lt;/td&gt;
        &lt;/tr&gt;
    &lt;/table&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><em><strong>insertBoardServer.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    request.setCharacterEncoding(&quot;utf-8&quot;);    // 값을 받아온걸 post로 받았기 때문에 그걸 풀어주는 코드  

    String title = request.getParameter(&quot;title&quot;);
    String content = request.getParameter(&quot;content&quot;);

    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
    // java api에 db를 연결하기 위한 객체
    Connection conn = null;

    // workbench에서 sql을 작성한 후 (ctrl+enter)
    // sql문장을 작성을 하고, 그 sql문장을 실행을 위한 객체
    PreparedStatement pstmt = null;

    // select의 결과를 DBMS에서 java로 저장하기 위한 객체
    ResultSet rs = null;

    try{
        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        String query = &quot;insert into board(title,content) values(?,?)&quot;;

        pstmt = conn.prepareStatement(query);
        pstmt.setString(1,title);    // 첫번째 물음표에는 title을 넣어라
        pstmt.setString(2,content);    // 두번째 물음표에는 content값을 넣어라.

        pstmt.executeUpdate();    // insert가 정상적으로 처리
        out.println(&quot;DB 연결 성공&quot;);

        // insert 한 후 게시판 목록 리스트 화면(viewBoardList.jsp)으로 이동하라고 응답
        response.sendRedirect(&quot;viewBoardlist.jsp&quot;);


        // 데이터가 있을때까지 반복 -&gt; 데이터가 있으면(true), 데이터가 없으면(false)값을 리턴하기 때문에
        // = 값이 있으면 넘겨줌
    }catch(SQLException ex){
//             out.println(ex);
            out.println(&quot;DB 연결 실패&quot;);
    }finally{
        if(conn!=null){conn.close();}
    }    
%&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre><p>값을 입력하고
<img src="https://velog.velcdn.com/images/jjinny_0609/post/876f47f9-8389-409b-b7e5-7ca244c25fba/image.png" alt=""></p>
<p>DB 연결된 것 까지 확인
<img src="https://velog.velcdn.com/images/jjinny_0609/post/99a8844a-b280-4d08-b01e-dd2a32cc1768/image.png" alt=""></p>
<p>mysql에서 select * from board;를 해보면
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e537b9ff-65e0-43a3-b6b5-6b5fa21ce659/image.png" alt=""></p>
<h4 id="methodpost-사용으로-mysql에-한글이-깨지는-경우">method=&quot;post&quot; 사용으로 mysql에 한글이 깨지는 경우</h4>
<p>11~14까지 글씨가 깨진것을 확인 할 수있는데
post방식으로 받아오면 기존 적용해둔 utf-8이 적용이 안되기 때문에 한글이 깨지는걸 방지하기 위해선</p>
<pre><code>request.setCharacterEncoding(&quot;utf-8&quot;);    </code></pre><p>아래 코드를 꼭 작성해주어야 한다.</p>
<hr> 

<h4 id="입력후-화면으로-넘어가기">입력후 화면으로 넘어가기</h4>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/24e0d8df-8517-42dc-b305-baa4a05691bc/image.png" alt=""></p>
<pre><code>// insert 한 후 게시판 목록 리스트 화면(viewBoardList.jsp)으로 이동하라고 응답
        response.sendRedirect(&quot;viewBoardlist.jsp&quot;);</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/7946810b-3315-4e21-a1a4-7a29781397ca/image.png" alt=""></p>
<hr>

<h3 id="한개의-form에서-여러개의-submit-사용하기">한개의 Form에서 여러개의 Submit 사용하기</h3>
<p><a href="https://kutar37.tistory.com/entry/%ED%95%9C%EA%B0%9C%EC%9D%98-Form%EC%97%90%EC%84%9C-%EC%97%AC%EB%9F%AC%EA%B0%9C-Submit-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0">https://kutar37.tistory.com/entry/%ED%95%9C%EA%B0%9C%EC%9D%98-Form%EC%97%90%EC%84%9C-%EC%97%AC%EB%9F%AC%EA%B0%9C-Submit-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0</a>
위 링크를 참고</p>
<hr>

<h3 id="글-수정">글 수정</h3>
<p><em><strong>게시판 메인(viewboradlist.jsp)</strong></em>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/158bf893-faee-4e29-9953-ee868541422d/image.png" alt=""></p>
<p><em><strong>게시판 내용을 보기위한 페이지(viewBoardDetail.jsp)</strong></em>
[예제 코드_viewBoardDetail.jsp]</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form&gt;
&lt;!-- 게시판 윗 부분은 반복하지 않아도 되므로 밖으로 빼줘서 처리해줌 --&gt;
&lt;%
    int no = Integer.parseInt(request.getParameter(&quot;no&quot;));
    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
    // java api에 db를 연결하기 위한 객체
    Connection conn = null;

    // workbench에서 sql을 작성한 후 (ctrl+enter)
    // sql문장을 작성을 하고, 그 sql문장을 실행을 위한 객체
    PreparedStatement pstmt = null;

    // select의 결과를 DBMS에서 java로 저장하기 위한 객체
    ResultSet rs = null;

    // 연결하기
    // 드라이버 매니저에게 Connection 객체를 달라고 요청한다.
    // Connection을 얻기 위해 필요한 데이터(url,아이디,비밀번호)
    try{
        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        String query = &quot;select * from board where no = ?&quot;;    // excuteQuery

        pstmt = conn.prepareStatement(query);
        pstmt.setInt(1, no);    //첫번째 물음표에는 no값을 넣어라

        rs = pstmt.executeQuery();

        if(rs.next()){        
%&gt;
&lt;table border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td colspan=&quot;2&quot;&gt;
&lt;%--         번 호 : &lt;input type=&quot;text&quot; name=&quot;no&quot; value=&quot;&lt;%=rs.getInt(&quot;no&quot;) %&gt; readonly&gt; --%&gt;
            번 호 : &lt;%=rs.getInt(&quot;no&quot;) %&gt;&lt;input type=&quot;hidden&quot; name=&quot;no&quot; value=&quot;&lt;%=rs.getInt(&quot;no&quot;) %&gt;&quot;&gt;
            조회수 : &lt;%=rs.getInt(&quot;count&quot;) %&gt;
            좋아요 : &lt;%=rs.getInt(&quot;good&quot;) %&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;제목&lt;/td&gt;
        &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;title&quot; value=&quot;&lt;%=rs.getString(&quot;title&quot;) %&gt;&quot;&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;내용&lt;/td&gt;
        &lt;td&gt;&lt;textarea rows=&quot;10&quot; name=&quot;content&quot; cols=&quot;30&quot;&gt;&lt;%=rs.getString(&quot;content&quot;) %&gt;&lt;/textarea&gt;

        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td colspan=&quot;2&quot;&gt;
            &lt;input type=&quot;submit&quot; value=&quot;수정&quot; formaction=&quot;modifyBoard.jsp&quot;&gt;
            &lt;input type=&quot;submit&quot; value=&quot;삭제&quot; formaction=&quot;removeBoard.jsp&quot;&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
&lt;%
    }
    out.println(&quot;DB 연결 성공&quot;);
        }catch(SQLException ex){
             out.println(&quot;DB 연결 실패&quot;);
        }finally{
            if(conn!=null){conn.close();}
    }
%&gt;
&lt;/table&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><em><strong>modifyBoard.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
    &lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;%    // request한 데이터가 한글일 때 깨지는 현상 방지 ( post 방식으로 보낼 경우 필요함 )
        request.setCharacterEncoding(&quot;utf-8&quot;);

        // input에서 받아온 데이터를 저장
        int no = Integer.parseInt(request.getParameter(&quot;no&quot;));
        String title = request.getParameter(&quot;title&quot;);
        String content = request.getParameter(&quot;content&quot;);


        Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
        Connection conn = null;
        ResultSet rs = null;
        PreparedStatement pstmt = null;

    try {

        String jdbcDriver = &quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        String query = &quot;update board set title=?, content=? where no = ?&quot;;

        pstmt = conn.prepareStatement(query);
        pstmt.setString(1,title);
        pstmt.setString(2,content);
        pstmt.setInt(3,no);

        pstmt.executeUpdate();

        response.sendRedirect(&quot;viewBoardDetail.jsp?no=&quot;+no);

    } catch(SQLException ex){
        out.println(ex);
        out.println(&quot;DB 연결 실패&quot;);

    } finally {
        if(conn != null){
            conn.close();
        }
    }

%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>14번 수정후 수정버튼 눌러보기
<img src="https://velog.velcdn.com/images/jjinny_0609/post/09845df1-b490-4dbf-8934-60b88d340114/image.png" alt="">
14번 수정된 모습
<img src="https://velog.velcdn.com/images/jjinny_0609/post/99fb39d5-f511-4b2a-8113-095f89531f46/image.png" alt=""></p>
<hr>

<h3 id="글-삭제-예제">글 삭제 예제</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/66115777-60bc-4234-83da-125b2c2fb530/image.png" alt="">
viewBoardDetail 게시판 제목을 눌러서 들어가 8번을 삭제</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/f20af265-cd91-4ad9-bfac-b9bd3e61b3ea/image.png" alt="">
삭제된 모습</p>
<p><em><strong>remove.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;%    // request한 데이터가 한글일 때 깨지는 현상 방지 ( post 방식으로 보낼 경우 필요함 )
        request.setCharacterEncoding(&quot;utf-8&quot;);

        // input에서 받아온 데이터를 저장
        int no = Integer.parseInt(request.getParameter(&quot;no&quot;));

        Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
        Connection conn = null;

//         ResultSet rs = null;

        PreparedStatement pstmt = null;

    try {

        String jdbcDriver = &quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        String query = &quot;delete from board where no = ?&quot;;

        pstmt = conn.prepareStatement(query);
        pstmt.setInt(1,no);

        pstmt.executeUpdate();

        response.sendRedirect(&quot;viewBoardlist.jsp&quot;);    //+no

    } catch(SQLException ex){
        out.println(ex);
        out.println(&quot;DB 연결 실패&quot;);

    } finally {
        if(conn != null){
            conn.close();
        }
    }

%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><hr>

<p>위까지 만든 내용 정리
<img src="https://velog.velcdn.com/images/jjinny_0609/post/74637f05-a300-4b8a-abbf-80e63da61aa1/image.png" alt=""></p>
<hr>

<h3 id="회원가입-페이지-구현하기">회원가입 페이지 구현하기</h3>
<p><em><strong>insertMember.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form action=&quot;insertMemberServer.jsp&quot; method=&quot;post&quot;&gt;
    &lt;table&gt;
    &lt;tr&gt;&lt;td&gt;아이디&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;id&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;비밀번호&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;input type=&quot;password&quot; name=&quot;pswd&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;이름&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;name&quot;&gt;&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;&lt;td&gt;생년월일&lt;/td&gt;&lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;input type=&quot;text&quot; name=&quot;year&quot; placeholder=&quot;년(4자)&quot;&gt;
            &lt;select name=&quot;month&quot;&gt;
                &lt;option value=&quot;&quot;&gt;월&lt;/option&gt;
                &lt;option value=&quot;01&quot;&gt;1&lt;/option&gt;
                &lt;option value=&quot;02&quot;&gt;2&lt;/option&gt;
                &lt;option value=&quot;03&quot;&gt;3&lt;/option&gt;
            &lt;/select&gt;
            &lt;input type=&quot;text&quot; name=&quot;day&quot; placeholder=&quot;일&quot;&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;성별&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;select name=&quot;gender&quot;&gt;
                    &lt;option value=&quot;&quot;&gt;성별&lt;/option&gt;
                    &lt;option value=&quot;m&quot;&gt;남자&lt;/option&gt;
                    &lt;option value=&quot;f&quot;&gt;여자&lt;/option&gt;
                    &lt;option&gt;선택안함&lt;/option&gt;
            &lt;/select&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;이메일&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;input type=&quot;text&quot; name=&quot;email&quot;&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;연락처&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;input type=&quot;text&quot; name=&quot;phone&quot;&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;input type=&quot;submit&quot; value=&quot;가입하기&quot;&gt;&lt;/td&gt;
    &lt;/tr&gt;
    &lt;/table&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><em><strong>insertMemberServer.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    //한글 깨짐 방지(post방식 일때)
    request.setCharacterEncoding(&quot;utf-8&quot;);  

    // 아이디 
    String id = request.getParameter(&quot;id&quot;);
    // 비밀번호
    String password = request.getParameter(&quot;password&quot;);
    // 이름
    String name = request.getParameter(&quot;name&quot;);
    // 생년월일
    String birthday = request.getParameter(&quot;year&quot;)+request.getParameter(&quot;month&quot;)+request.getParameter(&quot;day&quot;);
    // 성별
    String gender = request.getParameter(&quot;gender&quot;);
    // 이메일
    String email = request.getParameter(&quot;email&quot;);
    // 연락처
    String phone = request.getParameter(&quot;phone&quot;);

    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
    // java api에 db를 연결하기 위한 객체
    Connection conn = null;

    // workbench에서 sql을 작성한 후 (ctrl+enter)
    // sql문장을 작성을 하고, 그 sql문장을 실행을 위한 객체
    PreparedStatement pstmt = null;

    // select의 결과를 DBMS에서 java로 저장하기 위한 객체
    ResultSet rs = null;

    try{
        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        String query = &quot;insert into member values(? ,? ,? ,? ,? ,?, ?);&quot;;

        pstmt = conn.prepareStatement(query);
        pstmt.setString(1,id);    // 첫번째 물음표에는 id값을 넣어라
        pstmt.setString(2,password);    // 두번째 물음표에는 password값을 넣어라.
        pstmt.setString(3,name); // 세번째 물음표에는 name 값을 넣어라
        pstmt.setString(4,birthday); // 네번째 물음표에는 birthday 값을 넣어라.
        pstmt.setString(5,gender); // 다섯번째 물음표에는 gender 값을 넣어라.
        pstmt.setString(6,email); // 여섯번째 물음표에는 email 값을 넣어라.
        pstmt.setString(7 ,phone); // 일곱번째 물음표에는 phone 값을 넣어라.
        pstmt.executeUpdate();    // insert가 정상적으로 처리
        out.println(&quot;DB 연결 성공&quot;);

        // insert 한 후 게시판 목록 리스트 화면(viewBoardList.jsp)으로 이동하라고 응답
        // response.sendRedirect(&quot;viewBoardlist.jsp&quot;);

        // 데이터가 있을때까지 반복 -&gt; 데이터가 있으면(true), 데이터가 없으면(false)값을 리턴하기 때문에
        // = 값이 있으면 넘겨줌
    }catch(SQLException ex){
                out.println(ex);
            out.println(&quot;DB 연결 실패&quot;);
    }finally{
        if(conn!=null){conn.close();}
    }    
%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/dd7c28c3-4b0a-4c17-9b88-b5c9ea6ec53e/image.png" alt=""></p>
<p>가입하기를 하면 db에 값이 들어감.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/7982ad60-45de-4ce2-abe3-7336f9bb5bea/image.png" alt=""></p>
<p><em><strong>loginServer.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;%
    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
    // java api에 db를 연결하기 위한 객체
    Connection conn = null;

    // workbench에서 sql을 작성한 후 (ctrl+enter)
    // sql문장을 작성을 하고, 그 sql문장을 실행을 위한 객체
    PreparedStatement pstmt = null;

    // select의 결과를 DBMS에서 java로 저장하기 위한 객체
    ResultSet rs = null;

    // 연결하기
    // 드라이버 매니저에게 Connection 객체를 달라고 요청한다.
    // Connection을 얻기 위해 필요한 데이터(url,아이디,비밀번호)
    try{
        String id = request.getParameter(&quot;id&quot;);
        String password = request.getParameter(&quot;password&quot;);

        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        String query = &quot;select * from member where id = ? and pswd= ? &quot;;    // excuteQuery

        pstmt = conn.prepareStatement(query);
        pstmt.setString(1, id);    //첫번째 물음표에는 id값을 넣어라
        pstmt.setString(2, password);

        rs = pstmt.executeQuery();

        if(rs.next()){    // select 결과가 1건 있음(로그인 해도 됨)        
            // session영역에 user_id변수에 id값을 저장
            session.setAttribute(&quot;user_id&quot;,id);
            // 메인페이지로 이동(index.jsp)
            response.sendRedirect(&quot;index.jsp&quot;);    //index,jsp로 이동
        }else{    // select 결과 없음(로그인 하면 안됨)
            // 회원가입페이지로 이동(insertMember.jsp)
            response.sendRedirect(&quot;insertMebmer.jsp&quot;);
        }

    out.println(&quot;DB 연결 성공&quot;);
        }catch(SQLException ex){
             out.println(&quot;DB 연결 실패&quot;);
        }finally{
        if(rs!=null){conn.close();}
        if(conn!=null){conn.close();}
    }
%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>로그아웃을 위한 jsp
<em><strong>logOutServer.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;%
        session.invalidate();
    %&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[JSP #4]]></title>
            <link>https://velog.io/@jjinny_0609/JSP-4</link>
            <guid>https://velog.io/@jjinny_0609/JSP-4</guid>
            <pubDate>Thu, 23 Mar 2023 07:20:09 GMT</pubDate>
            <description><![CDATA[<h3 id="varstatus">varStatus</h3>
<p>varStatus는 일반적으로 JSTL(JSP Standard Tag Library)에서 사용되며, JSP 페이지에서 반복문을 수행할 때 사용됩니다. varStatus를 사용하면 반복문의 현재 상태를 나타내는 정보를 저장하고, 해당 정보를 활용하여 특정 작업을 수행할 수 있습니다.</p>
<p>예를 들어, varStatus를 사용하여 반복문에서 현재 반복 횟수를 추적하고, 특정 횟수마다 다른 작업을 수행하거나 특정 조건을 검사할 수 있습니다.</p>
<p>아래는 varStatus를 사용한 JSTL의 예시 코드입니다.</p>
<pre><code>&lt;c:forEach var=&quot;item&quot; items=&quot;${itemList}&quot; varStatus=&quot;loop&quot;&gt;
    &lt;c:out value=&quot;${item}&quot;/&gt;&lt;br&gt;
    &lt;c:if test=&quot;${loop.index % 2 == 0}&quot;&gt;
        &lt;c:out value=&quot;This is an even loop iteration&quot;/&gt;&lt;br&gt;
    &lt;/c:if&gt;
&lt;/c:forEach&gt;</code></pre><p>위 코드에서 varStatus를 사용하여 현재 반복 상태를 나타내는 loop 변수를 선언하였습니다. loop 변수를 사용하여 현재 반복 횟수(loop.index), 현재 반복이 처음인지 여부(loop.first), 현재 반복이 마지막인지 여부(loop.last) 등을 알 수 있습니다.</p>
<p>위 코드에서는 loop.index가 짝수일 때 &quot;This is an even loop iteration&quot;을 출력하도록 설정하였습니다.</p>
<hr>

<p><strong>[예제_formatNumber]</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;fmt&quot; uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; %&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;c:set var=&quot;price&quot; value=&quot;10000&quot; /&gt;

${price}
&lt;fmt:formatNumber value=&quot;${price}&quot; type=&quot;number&quot; var=&quot;numberType&quot; /&gt;
&lt;br /&gt;
통화: &lt;fmt:formatNumber value=&quot;${price}&quot; type=&quot;currency&quot; currencySymbol=&quot;원&quot; /&gt;
&lt;br/&gt;
퍼센트: &lt;fmt:formatNumber value=&quot;${price}&quot; type=&quot;percent&quot; groupingUsed=&quot;false&quot; /&gt;
&lt;br/&gt;
숫자: ${numberType}
&lt;br/&gt;
패턴 : &lt;fmt:formatNumber value=&quot;${price}&quot; pattern=&quot;00000000.00&quot; /&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/74d20844-54d2-4a71-b0c2-ab36f3bfc62d/image.png" alt=""></p>
<p><strong>[예제_formatDate]</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;fmt&quot; uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; %&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;c:set var=&quot;now&quot; value=&quot;&lt;%= new java.util.Date() %&gt;&quot; /&gt;    
${now}

&lt;fmt:formatDate value=&quot;${now}&quot; type=&quot;date&quot; dateStyle=&quot;full&quot; /&gt;
&lt;br&gt;
&lt;fmt:formatDate value=&quot;${now}&quot; type=&quot;date&quot; dateStyle=&quot;short&quot; /&gt;
&lt;br&gt;
&lt;fmt:formatDate value=&quot;${now}&quot; type=&quot;time&quot; /&gt;
&lt;br&gt;
&lt;fmt:formatDate value=&quot;${now}&quot; type=&quot;both&quot; dateStyle=&quot;full&quot; timeStyle=&quot;full&quot;/&gt;
&lt;br&gt;
&lt;fmt:formatDate value=&quot;${now}&quot; pattern=&quot;yyyy-MM-dd hh:mm:ss&quot; /&gt;    &lt;!-- 소문자는 분을 나타내는 miniute 대문자M이 Month의 월 --&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/f479ccec-6a33-4a67-bd84-731752c2f83d/image.png" alt=""></p>
<hr>

<h2 id="jdbc">JDBC</h2>
<p>JDBC(Java Database Connectivity)는 자바 프로그램에서 데이터베이스에 접속하여 데이터를 다룰 수 있게 해주는 API(Application Programming Interface)입니다. ODBC(Open Database Connectivity)는 Microsoft에서 개발한 데이터베이스 접속 API로, 다양한 데이터베이스 시스템에 접속할 수 있는 표준 인터페이스입니다.</p>
<p>JDBC ODBC 브릿지(bridge)는 JDBC API를 사용하여 ODBC 데이터베이스 드라이버를 호출하도록 구현된 드라이버입니다. 이를 사용하면 ODBC를 지원하는 데이터베이스 시스템에 대해서도 JDBC API를 이용하여 데이터베이스에 접속하고 데이터를 다룰 수 있습니다.</p>
<p>JDBC ODBC 브릿지를 사용하면 자바 애플리케이션에서 ODBC 드라이버를 로드하고 데이터베이스에 연결하는 과정을 JDBC API를 통해 처리할 수 있습니다. JDBC ODBC 브릿지를 사용하여 ODBC 드라이버를 호출하면, ODBC 드라이버가 데이터베이스에 대한 연결을 생성하고 SQL 질의문을 실행하여 결과를 반환합니다.</p>
<p>하지만, 최신 버전의 자바에서는 JDBC 드라이버들이 직접적으로 데이터베이스에 접속하는 것을 권장하고 있으며, JDBC ODBC 브릿지는 지원하지 않는 경우도 있습니다. 이러한 이유로, 최신 버전의 자바에서는 JDBC 드라이버를 직접 사용하여 데이터베이스에 접속하고 데이터를 다루는 것이 일반적입니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/dc8803fc-6a28-48d9-bd35-ff1fe52a51fa/image.png" alt=""></p>
<h3 id="이클립스와-mysql연결하기">[이클립스와 mysql연결하기]</h3>
<p><a href="https://www.mysql.com/">https://www.mysql.com/</a>   로 이동</p>
<p>download
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c360ab9f-5243-42cf-a652-68ca9dcac1cc/image.png" alt="">
MySQL community (GPL) download 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b01d8a52-aeca-48da-970f-fab8215c3bce/image.png" alt="">
Connector/J 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c6cb76a4-4972-4c55-a601-431773ef34d3/image.png" alt="">
Platform Independent 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ddfdfbeb-2972-4ae2-aea3-65c9ca009742/image.png" alt="">
Download 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c10ca98a-ad52-41eb-a490-5d938b46057c/image.png" alt="">
No thanks, ~ 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2162a09e-18e2-418f-b916-9400043c387f/image.png" alt="">
압축풀고 mysql-connector-j-(버전) 파일을 복사해서
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4e53deb9-9402-4f88-af04-99efa53776a2/image.png" alt="">
WEB-INF -&gt; lib 폴더에 복사
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6a2f704d-5fc6-41c4-b4db-61af86b3744d/image.png" alt="">
그럼 라이브러리에도 추가된 것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d9fcddcf-0105-4729-ab36-a1423830ba56/image.png" alt=""></p>
<hr>

<p><strong>[예제_자바로 DB연결하기(JDBC)]</strong></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/f2dd5fa6-d64b-401d-947a-da233ab5fef8/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/79ec01c2-e0e8-462f-a28a-0bc88b7f6351/image.png" alt=""></p>
<p><strong>연결을 위한 전체 코드</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);

    // 연결하기
    Connection conn = null;

    // 드라이버 매니저에게 Connection 객체를 달라고 요청한다.

    // Connection을 얻기 위해 필요한 데이터(jdbcDriver,아이디,비밀번호)
    try{
        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/sample?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        out.println(&quot;DB 연결 성공&quot;);
    }catch(SQLException ex){
        out.println(&quot;DB 연결 실패&quot;);
    }finally{
        if(conn!=null){conn.close();}
    }
%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>연결 안되면 아래와 같이 뜨고
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d03592d8-b0c1-45c9-bce1-a5078d13df5f/image.png" alt=""></p>
<p>정상적으로 연결될 시 아래와 같이 출력된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/daa3b51b-15c6-4367-ac2d-f747fb9d27d3/image.png" alt=""></p>
<hr>

<h4 id="resultsetsql">ResultSetSQL</h4>
<p>쿼리를 실행한 결과 데이터 집합을 나타내는 Java 인터페이스입니다. ResultSet은 데이터베이스의 테이블이나 뷰와 같은 데이터 집합에서 검색한 결과를 포함하며, 이를 사용하여 데이터를 읽고 조작할 수 있습니다.</p>
<p>ResultSet 인터페이스는 일련의 컬럼이 있는 데이터 집합을 나타내며, 데이터베이스에서 가져온 데이터를 순회할 수 있는 메서드를 제공합니다. ResultSet 객체는 SQL 쿼리를 실행하는 Statement, PreparedStatement 또는 CallableStatement 객체에서 생성됩니다.</p>
<p>ResultSet은 데이터베이스에서 데이터를 가져오는 방법을 제어하는데 사용되는 메서드를 제공합니다. ResultSet 객체는 데이터를 한 번에 한 행씩 가져올 수 있으며, 다음 행으로 이동하기 위해 next() 메서드를 사용합니다. ResultSet은 열 인덱스 또는 열 이름을 사용하여 특정 열의 데이터를 가져오는 메서드도 제공합니다.</p>
<p>ResultSet 인터페이스는 데이터의 유형과 크기, 행 및 열 인덱스 등과 같은 다양한 속성을 제공합니다. 이러한 속성을 사용하여 ResultSet에서 가져온 데이터를 처리하고 분석할 수 있습니다. 예를 들어, ResultSetMetaData 클래스를 사용하여 ResultSet에 대한 메타데이터를 검색하고, ResultSet의 데이터를 자바 객체에 매핑하는 ORM 프레임워크와 같은 라이브러리를 사용할 수도 있습니다.</p>
<h4 id="executequery">executeQuery</h4>
<p>Java에서 JDBC API를 사용하여 데이터베이스와 상호작용할 때 executeQuery 메서드는 주어진 SQL 쿼리를 실행하고 그 결과를 ResultSet 객체에 저장합니다. 이 ResultSet 객체는 테이블의 행과 열을 나타내며, 애플리케이션에서는 이 객체를 통해 데이터베이스에서 가져온 데이터를 처리할 수 있습니다.</p>
<p>예를 들어, 다음과 같은 SQL 쿼리문을 실행하고 그 결과를 ResultSet 객체에 저장할 수 있습니다.</p>
<pre><code>String query = &quot;SELECT * FROM customers&quot;;
Statement statement = connection.createStatement();
ResultSet resultSet = statement.executeQuery(query);</code></pre><p>위의 코드에서 connection은 데이터베이스와의 연결을 나타내는 객체입니다. Statement 객체는 SQL 문을 실행할 수 있으며, executeQuery 메서드를 사용하여 데이터베이스에서 결과를 검색합니다. ResultSet 객체는 executeQuery 메서드가 반환한 결과를 저장하며, 애플리케이션에서 이 객체를 사용하여 데이터를 처리할 수 있습니다.</p>
<p>중요한 점은 executeQuery 메서드가 SELECT 문을 실행할 때만 사용해야 한다는 것입니다. INSERT, UPDATE, DELETE 문을 실행할 때는 executeUpdate 메서드를 사용해야 합니다. 또한, executeQuery 메서드는 읽기 전용 ResultSet 객체를 반환하므로 결과를 수정할 수 없습니다. 결과를 수정해야 하는 경우, executeUpdate 메서드를 사용해야 합니다.</p>
<p><strong>[예제_게시판을 만들어보기(mysql db값을 불러오기)]</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td&gt;게시판번호&lt;/td&gt;&lt;td&gt;제목&lt;/td&gt;&lt;td&gt;작성자&lt;/td&gt;&lt;td&gt;작성일&lt;/td&gt;&lt;td&gt;조회&lt;/td&gt;&lt;td&gt;좋아요&lt;/td&gt;
    &lt;/tr&gt;
&lt;!-- 게시판 윗 부분은 반복하지 않아도 되므로 밖으로 빼줘서 처리해줌 --&gt;
&lt;%
    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
    // java api에 db를 연결하기 위한 객체
    Connection conn = null;

    // workbench에서 sql을 작성한 후 (ctrl+enter)
    // sql문장을 작성을 하고, 그 sql문장을 실행을 위한 객체
    Statement stmt = null;

    // select의 결과를 DBMS에서 java로 저장하기 위한 객체
    ResultSet rs = null;

    // 연결하기
    // 드라이버 매니저에게 Connection 객체를 달라고 요청한다.
    // Connection을 얻기 위해 필요한 데이터(url,아이디,비밀번호)
    try{
        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        String query = &quot;select * from board&quot;;    //executeQuery    - select만 다르다..
        // String query = &quot;update board set title=&#39;가나다&#39; where no = 1&quot;;    //executeUpdate
        // String query = &quot;insert into board(title, content) values(&#39;제목입니다.&#39;,&#39;내용은 여기에...&#39;)&quot;;    // excuteUpdate
        // String query = &quot;delete from board where no = 1&quot;;    //excuteUpdate

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        stmt = conn.createStatement();
        // workbench ctrl+enter(쿼리문장을 실행)를 통해 도출된 select 결과를 ResultSet에 저장 ↓
        rs = stmt.executeQuery(query);

        // 데이터가 있을때까지 반복 -&gt; 데이터가 있으면(true), 데이터가 없으면(false)값을 리턴하기 때문에
        // = 값이 있으면 넘겨줌
        while(rs.next()){        
%&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;%=rs.getInt(&quot;no&quot;) %&gt;
        &lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;title&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;id&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;regdate&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getInt(&quot;count&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getInt(&quot;good&quot;) %&gt;&lt;/td&gt;
    &lt;/tr&gt;    
&lt;%
    }
    out.println(&quot;DB 연결 성공&quot;);
        }catch(SQLException ex){
            out.println(&quot;DB 연결 실패&quot;);
        }finally{
            if(conn!=null){conn.close();}
    }
%&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><em><strong>mysql의 값</strong></em>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d0d3ca61-d71a-4ad9-9c58-9f3899ec6641/image.png" alt=""></p>
<p><em><strong>연결완료</strong></em>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c1a62ae6-3453-4411-9e15-a7e9feec76ef/image.png" alt=""></p>
<p><strong>[오류_게시판 윗 부분을 밖으로 빼줘서 처리해준 이유]</strong>
아래와 같이 입력하면 게시판 윗부분이 값이 있는 만큼 반복되어서 출력되기 때문에 아래와 같은 결과를 볼 수 있게된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/61dd42e7-c1e4-4e34-b769-ab8b5a243dbb/image.png" alt="">
<em>게시판 윗 부분을 밖으로 빼줘서 처리해준 이유.jpg</em>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ea945612-0c3d-45a2-b3ff-e94c8a9c15a2/image.png" alt=""></p>
<hr>

<h4 id="preparedstatement">PreparedStatement</h4>
<p>PreparedStatement는 JDBC API를 사용하여 SQL 쿼리문을 실행할 때 사용하는 인터페이스 중 하나입니다. 이 인터페이스를 사용하면 SQL 쿼리문을 미리 컴파일하여 사용자 입력 값을 동적으로 바인딩할 수 있습니다.</p>
<p>PreparedStatement를 사용하면 SQL 쿼리문에서 사용되는 변수를 ?로 표시할 수 있습니다. 그리고 이 ?에 대한 값을 나중에 동적으로 할당할 수 있습니다. 이 방식은 SQL Injection 공격을 막아주며, 실행 속도를 높이는 데에도 도움을 줍니다.</p>
<p>예를 들어, 다음과 같은 SQL 쿼리문을 실행하는 경우 PreparedStatement를 사용할 수 있습니다.</p>
<pre><code>String name = &quot;John&quot;;
String query = &quot;SELECT * FROM customers WHERE name = ?&quot;;
PreparedStatement statement = connection.prepareStatement(query);
statement.setString(1, name);
ResultSet resultSet = statement.executeQuery();</code></pre><p>위의 코드에서는 SQL 쿼리문에서 name 변수를 ?로 대체하고, PreparedStatement 객체의 setString 메서드를 사용하여 이 변수에 대한 값을 설정합니다. 이후 executeQuery 메서드를 호출하여 SQL 쿼리문을 실행하고 결과를 ResultSet 객체에 저장합니다.</p>
<p>PreparedStatement를 사용하면 매번 SQL 쿼리문을 실행하기 전에 쿼리문을 미리 컴파일할 수 있으므로 실행 속도가 빨라집니다. 또한, 사용자 입력 값을 동적으로 할당할 수 있으므로 SQL Injection 공격을 방지할 수 있습니다. 따라서 PreparedStatement는 보안과 성능 측면에서 모두 유용한 인터페이스입니다.</p>
<h4 id="preparedstatement-클래스가-제공하는-set-메서드">PreparedStatement 클래스가 제공하는 set 메서드</h4>
<p>set 메서드는 SQL 쿼리문에서 ?로 표시된 변수에 값을 할당하는 데 사용됩니다. 다음은 PreparedStatement 클래스에서 제공하는 일부 set 메서드의 예시입니다.</p>
<ul>
<li><p>setString(int parameterIndex, String x)
SQL 쿼리문에서 ?로 표시된 문자열 변수에 값을 할당합니다.</p>
</li>
<li><p>setInt(int parameterIndex, int x)
SQL 쿼리문에서 ?로 표시된 정수형 변수에 값을 할당합니다.</p>
</li>
<li><p>setDouble(int parameterIndex, double x)
SQL 쿼리문에서 ?로 표시된 실수형 변수에 값을 할당합니다.</p>
</li>
<li><p>setDate(int parameterIndex, Date x)
SQL 쿼리문에서 ?로 표시된 날짜 변수에 값을 할당합니다.</p>
</li>
<li><p>setTime(int parameterIndex, Time x)
SQL 쿼리문에서 ?로 표시된 시간 변수에 값을 할당합니다.</p>
</li>
<li><p>setObject(int parameterIndex, Object x)
SQL 쿼리문에서 ?로 표시된 변수에 값을 할당할 때, 값의 데이터 형식을 명시하지 않고 Object로 할당할 수 있습니다.</p>
</li>
</ul>
<p>이 외에도 PreparedStatement 클래스는 다양한 set 메서드를 제공합니다. set 메서드를 사용하여 SQL 쿼리문에서 ?로 표시된 변수에 값을 할당할 때는 변수의 데이터 형식에 맞는 set 메서드를 사용해야 합니다. 그렇지 않으면 예기치 않은 결과가 발생할 수 있습니다.</p>
<h3 id="prepagedstatement-예제-특정-게시물-조회">PrepagedStatement 예제 (특정 게시물 조회)</h3>
<p><em><strong>viewBoardlist.jsp (실행)</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td&gt;게시판번호&lt;/td&gt;&lt;td&gt;제목&lt;/td&gt;&lt;td&gt;작성자&lt;/td&gt;&lt;td&gt;작성일&lt;/td&gt;&lt;td&gt;조회&lt;/td&gt;&lt;td&gt;좋아요&lt;/td&gt;
    &lt;/tr&gt;
&lt;!-- 게시판 윗 부분은 반복하지 않아도 되므로 밖으로 빼줘서 처리해줌 --&gt;
&lt;%
    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
    // java api에 db를 연결하기 위한 객체
    Connection conn = null;

    // workbench에서 sql을 작성한 후 (ctrl+enter)
    // sql문장을 작성을 하고, 그 sql문장을 실행을 위한 객체
    Statement stmt = null;

    // select의 결과를 DBMS에서 java로 저장하기 위한 객체
    ResultSet rs = null;

    // 연결하기
    // 드라이버 매니저에게 Connection 객체를 달라고 요청한다.
    // Connection을 얻기 위해 필요한 데이터(url,아이디,비밀번호)
    try{
        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        String query = &quot;select * from board&quot;;    //executeQuery    - select만 다르다..
        // String query = &quot;update board set title=&#39;가나다&#39; where no = 1&quot;;    //executeUpdate
        // String query = &quot;insert into board(title, content) values(&#39;제목입니다.&#39;,&#39;내용은 여기에...&#39;)&quot;;    // excuteUpdate
        // String query = &quot;delete from board where no = 1&quot;;    //excuteUpdate

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        stmt = conn.createStatement();
        // workbench ctrl+enter(쿼리문장을 실행)를 통해 도출된 select 결과를 ResultSet에 저장 ↓
        rs = stmt.executeQuery(query);

        // 데이터가 있을때까지 반복 -&gt; 데이터가 있으면(true), 데이터가 없으면(false)값을 리턴하기 때문에
        // = 값이 있으면 넘겨줌
        while(rs.next()){        
%&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;%=rs.getInt(&quot;no&quot;) %&gt;
        &lt;/td&gt;
        &lt;td&gt;&lt;a href=&quot;viewBoardDetail.jsp?no=&lt;%= rs.getInt(&quot;no&quot;)%&gt;&quot;&gt;&lt;%=rs.getString(&quot;title&quot;) %&gt;&lt;/a&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;id&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;regdate&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getInt(&quot;count&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getInt(&quot;good&quot;) %&gt;&lt;/td&gt;
    &lt;/tr&gt;    
&lt;%
    }
    out.println(&quot;DB 연결 성공&quot;);
        }catch(SQLException ex){
            out.println(&quot;DB 연결 실패&quot;);
        }finally{
            if(conn!=null){conn.close();}
    }
%&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><em><strong>viewBoardDetail.jsp</strong></em></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.sql.*&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td&gt;게시판번호&lt;/td&gt;
        &lt;td&gt;제목&lt;/td&gt;
        &lt;td&gt;내용&lt;/td&gt;
        &lt;td&gt;작성자&lt;/td&gt;
        &lt;td&gt;작성일&lt;/td&gt;
        &lt;td&gt;조회&lt;/td&gt;
        &lt;td&gt;좋아요&lt;/td&gt;
    &lt;/tr&gt;
&lt;!-- 게시판 윗 부분은 반복하지 않아도 되므로 밖으로 빼줘서 처리해줌 --&gt;
&lt;%
    int no = Integer.parseInt(request.getParameter(&quot;no&quot;));
    // JDBC 드라이버 로딩(mysql)
    Class.forName(&quot;com.mysql.jdbc.Driver&quot;);
    // java api에 db를 연결하기 위한 객체
    Connection conn = null;

    // workbench에서 sql을 작성한 후 (ctrl+enter)
    // sql문장을 작성을 하고, 그 sql문장을 실행을 위한 객체
    PreparedStatement pstmt = null;

    // select의 결과를 DBMS에서 java로 저장하기 위한 객체
    ResultSet rs = null;

    // 연결하기
    // 드라이버 매니저에게 Connection 객체를 달라고 요청한다.
    // Connection을 얻기 위해 필요한 데이터(url,아이디,비밀번호)
    try{
        String jdbcDriver =&quot;jdbc:mysql://localhost:3306/naver_1?serverTimezone=Asia/Seoul&quot;;
        String dbUser = &quot;root&quot;;
        String dbPass = &quot;1234&quot;;

        conn = DriverManager.getConnection(jdbcDriver,dbUser,dbPass);

        String query = &quot;select * from board where no = ?&quot;;    // excuteQuery

        pstmt = conn.prepareStatement(query);
        pstmt.setInt(1, no);    //첫번째 물음표에는 no값을 넣어라

        rs = pstmt.executeQuery();

        if(rs.next()){        
%&gt;
    &lt;tr&gt;
        &lt;td&gt;
            &lt;%=rs.getInt(&quot;no&quot;) %&gt;
        &lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;title&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;id&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;content&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getString(&quot;regdate&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getInt(&quot;count&quot;) %&gt;&lt;/td&gt;
        &lt;td&gt;&lt;%=rs.getInt(&quot;good&quot;) %&gt;&lt;/td&gt;
    &lt;/tr&gt;    
&lt;%
    }
    out.println(&quot;DB 연결 성공&quot;);
        }catch(SQLException ex){
            out.println(&quot;DB 연결 실패&quot;);
        }finally{
            if(conn!=null){conn.close();}
    }
%&gt;
&lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>viewBoardlist.jsp를 실행 -&gt; 아무 게시판 제목을 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b70b5372-2174-4e8e-af76-01ab0908802d/image.png" alt=""></p>
<p>클릭한 게시판 제목의 번호와 정보를 가지고 온다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9e2035f1-822a-4fc1-a263-7b1ffd5e9656/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSP #3]]></title>
            <link>https://velog.io/@jjinny_0609/JSP-3</link>
            <guid>https://velog.io/@jjinny_0609/JSP-3</guid>
            <pubDate>Wed, 22 Mar 2023 07:09:22 GMT</pubDate>
            <description><![CDATA[<h2 id="jspusebean-액션-태그">jsp:useBean 액션 태그</h2>
<p>JavaBean은 자바 객체를 설계하는 규약 중 하나로, getter/setter 메서드를 포함하는 특별한 클래스입니다. JavaBean은 다른 Java 클래스에서 사용될 수 있도록 속성 값을 캡슐화하고, 재사용성을 높이며, 자바 빈 규약을 따르는 도구들이 이를 적극적으로 활용하며, 자바 기반의 웹 프로그래밍에서 많이 사용됩니다.</p>
<p>JSP에서 자바빈은 주로 웹 페이지에서 사용되는 데이터 모델을 정의하고, 비즈니스 로직을 처리하는 데 사용됩니다. 예를 들어, 회원 정보를 저장하는 자바빈 클래스를 작성하면, JSP에서 이를 활용하여 회원 가입 폼, 로그인 폼 등에서 사용자 입력 값을 저장하고, 데이터베이스에 저장하는 등의 작업을 수행할 수 있습니다.</p>
<hr>

<p><strong>[예제]</strong>
(이클립스 자동완성기능 사용해보기)
<img src="https://velog.velcdn.com/images/jjinny_0609/post/8917d54d-be01-4109-8670-fb070cf36bd6/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/070a9811-442d-4389-ab83-9ea453c6bb09/image.png" alt="">
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6ba54b99-edd0-4a91-aed8-81f8fc223bb4/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/4001007d-7fd1-4c02-9a58-28093164c799/image.png" alt=""></p>
<hr>

<h3 id="jspusebean-액션태그를-사용하여-객체-생성하기"><a href="jsp:useBean">jsp:useBean</a> 액션태그를 사용하여 객체 생성하기</h3>
<p>useBean 액션 태그는 JavaBean 객체를 생성하고 초기화하는 데 사용됩니다. useBean 액션 태그에는 다음과 같은 속성들이 있습니다.</p>
<p><strong>id 속성</strong>: 생성된 JavaBean 객체를 참조하기 위한 고유 식별자를 지정합니다.</p>
<p><strong>class 속성</strong>: 생성할 JavaBean 객체의 클래스 이름을 지정합니다.</p>
<p><strong>scope 속성</strong>: JavaBean 객체의 범위를 지정합니다. JSP에서는 application, session, request, page 등의 범위를 지정할 수 있습니다. 각 범위는 객체의 생명 주기와 접근 권한이 다릅니다.</p>
<p><strong>type 속성</strong>: class 속성 대신 JavaBean 객체의 타입을 지정할 수 있습니다. 이 경우, JSP 컨테이너가 타입 정보를 이용하여 자동으로 적절한 클래스를 생성합니다.</p>
<p><strong>beanName 속성</strong>: JNDI(Java Naming and Directory Interface)를 이용하여 JavaBean 객체를 검색할 때 사용됩니다. 이 속성은 scope 속성이 지정된 경우 무시됩니다.</p>
<p>예를 들어, 다음과 같은 useBean 액션 태그를 사용하여 JavaBean 객체를 생성할 수 있습니다.</p>
<pre><code>&lt;jsp:useBean id=&quot;myBean&quot; class=&quot;com.example.MyBean&quot; scope=&quot;request&quot;/&gt;</code></pre><p>위 태그는 request 범위에서 com.example.MyBean 클래스의 인스턴스를 생성하고, 이를 myBean이라는 이름으로 참조할 수 있도록 합니다.</p>
<hr>

<p><strong>java Resource/ch08.member.jsp</strong>
getter setter 부분</p>
<pre><code>package ch08.member;

import java.util.Date;

public class MemberInfo {

    private String id; // id
    private String password; // password
    private String name; // name
    private String address;    // address
    private Date registerDate; // registerDate
    private String email; // email

    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
    public Date getRegisterDate() {
        return registerDate;
    }
    public void setRegisterDate(Date registerDate) {
        this.registerDate = registerDate;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
}</code></pre><p><strong>WebContent/ch08/makeObject.jsp</strong>
id와 name값을 적어둔 코드</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;jsp:useBean id=&quot;member&quot; class=&quot;ch08.member.MemberInfo&quot; scope=&quot;request&quot; /&gt;
&lt;%
    member.setId(&quot;madvirus&quot;);
    member.setName(&quot;최범균&quot;);
%&gt;
&lt;jsp:forward page=&quot;useObject.jsp&quot;&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>WebContent/ch08/useObject.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
 pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;jsp:useBean id=&quot;member&quot; class=&quot;ch08.member.MemberInfo&quot; scope=&quot;request&quot; /&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;%= member.getName() %&gt; (&lt;%=member.getId() %&gt;) 회원님
    안녕하세요.
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/90a6a5b4-6bfd-457e-9be9-b4b106fcad5a/image.png" alt=""></p>
<p>자 이제 실행해보자
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e07fbefe-86d9-4354-a62e-e26ad9940c98/image.png" alt="">
useObject.jsp를 직접 실행하면 request 기본 객체에 &quot;member&quot;속성이 존재하지 않으므로 새로운 MebmerInfo 클래스의 객체를 생성한다. 이 경우 useObject.jsp에서 생성 한 프로퍼티 값을 변경하지 않았기 때문에 위와같이 초기값(null)이 출력된다.</p>
<h3 id="jspsetproperty-액션-태그와-jspgetproperty-액션-태그"><a href="jsp:setProperty">jsp:setProperty</a> 액션 태그와 <a href="jsp:getProperty">jsp:getProperty</a> 액션 태그</h3>
<p>JSP에서 jsp:setProperty 액션 태그와 jsp:getProperty 액션 태그는 JavaBean 객체의 속성 값을 설정하고 가져오는 데 사용됩니다.</p>
<p>jsp:setProperty 액션 태그는 다음과 같은 속성을 가지며, JavaBean 객체의 속성 값을 설정할 때 사용됩니다.</p>
<p>name 속성: JavaBean 객체의 이름을 지정합니다.
property 속성: 설정할 속성의 이름을 지정합니다.
value 속성: 설정할 속성의 값을 지정합니다. 이 값을 표현식이나 EL(Expression Language)을 사용하여 동적으로 지정할 수도 있습니다.
param 속성: 설정할 속성의 값을 표현식이나 EL을 사용하여 동적으로 지정할 수 있습니다.
예를 들어, 다음과 같은 jsp:setProperty 액션 태그를 사용하여 JavaBean 객체의 속성 값을 설정할 수 있습니다.</p>
<pre><code>&lt;jsp:useBean id=&quot;myBean&quot; class=&quot;com.example.MyBean&quot; scope=&quot;request&quot;/&gt;
&lt;jsp:setProperty name=&quot;myBean&quot; property=&quot;name&quot; value=&quot;John&quot;/&gt;
&lt;jsp:setProperty name=&quot;myBean&quot; property=&quot;age&quot; param=&quot;request.age&quot;/&gt;</code></pre><p>위 태그는 request 범위에서 com.example.MyBean 클래스의 인스턴스를 생성하고, 이를 myBean이라는 이름으로 참조합니다. 그리고 myBean 객체의 name 속성 값을 &quot;John&quot;으로, age 속성 값을 request 객체의 &quot;age&quot; 파라미터 값으로 설정합니다.</p>
<p>jsp:getProperty 액션 태그는 다음과 같은 속성을 가지며, JavaBean 객체의 속성 값을 가져올 때 사용됩니다.</p>
<ol>
<li>name 속성: JavaBean 객체의 이름을 지정합니다.</li>
<li>property 속성: 가져올 속성의 이름을 지정합니다.</li>
<li>param 속성: 가져올 속성의 값을 표현식이나 EL을 사용하여 동적으로 지정할 수 있습니다.</li>
</ol>
<p>예를 들어, 다음과 같은 jsp:getProperty 액션 태그를 사용하여 JavaBean 객체의 속성 값을 가져올 수 있습니다.</p>
<pre><code>&lt;jsp:useBean id=&quot;myBean&quot; class=&quot;com.example.MyBean&quot; scope=&quot;request&quot;/&gt;
&lt;p&gt;Hello, ${myBean.name}!&lt;/p&gt;
&lt;p&gt;Your age is ${jsp:getProperty name=&quot;myBean&quot; property=&quot;age&quot;}.&lt;/p&gt;</code></pre><p>위 태그는 request 범위에서 com.example.MyBean 클래스의 인스턴스를 생성하고, 이를 myBean이라는 이름으로 참조합니다. 그리고 myBean 객체의 name 속성 값을 EL을 사용하여 출력하고, age 속성 값을 jsp:getProperty 액션 태그를 사용하여 EL을 통해 출력합니다.</p>
<p><strong>[예제]</strong>
<strong>membershipFrom.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;회원가입 입력 폼&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;form action=&quot;procssJoining.jsp&quot; method=&quot;post&quot;&gt;
    &lt;table&gt;
        &lt;tr&gt;
            &lt;td&gt;아이디&lt;/td&gt;
            &lt;td colspan=&quot;3&quot;&gt;&lt;input type=&quot;text&quot; name=&quot;id&quot;&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td&gt;이름&lt;/td&gt;
            &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;name&quot;&gt;&lt;/td&gt;
            &lt;td&gt;이메일&lt;/td&gt;
            &lt;td&gt;&lt;input type=&quot;text&quot; name=&quot;email&quot;&gt;&lt;/td&gt;
        &lt;/tr&gt;
        &lt;tr&gt;
            &lt;td colspan=&quot;4&quot;&gt;
            &lt;input type=&quot;submit&quot; value=&quot;회원가입&quot;&gt;
            &lt;/td&gt;
        &lt;/tr&gt;            
    &lt;/table&gt;
&lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>processJoining.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%
    request.setCharacterEncoding(&quot;utf-8&quot;);
%&gt;
&lt;jsp:useBean id=&quot;MemberInfo&quot; class=&quot;ch08.member.MemberInfo&quot; /&gt;
&lt;%-- 
&lt;&lt;jsp:setProperty property=&quot;id&quot; name=&quot;memberInfo&quot;/&gt;
&lt;&lt;jsp:setProperty property=&quot;password&quot; name=&quot;memberInfo&quot;/&gt;
&lt;&lt;jsp:setProperty property=&quot;name&quot; name=&quot;memberInfo&quot;/&gt;
&lt;&lt;jsp:setProperty property=&quot;address&quot; name=&quot;memberInfo&quot;/&gt;
&lt;&lt;jsp:setProperty property=&quot;registerDate&quot; name=&quot;memberInfo&quot;/&gt;
&lt;&lt;jsp:setProperty property=&quot;email&quot; name=&quot;memberInfo&quot;/&gt;
위의 setProperty를 아래의 코드 처럼 *을 통해 하나로 표현할 수도 있다! --%&gt;
&lt;jsp:setProperty property=&quot;*&quot; name=&quot;MemberInfo&quot;/&gt;
&lt;&lt;jsp:setProperty property=&quot;password&quot; name=&quot;memberInfo&quot; value=&quot;&lt;%=MemberInfo.getId()%&gt;&quot;/&gt;

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre><hr>

<h3 id="클라이언트와의-대화-1--쿠키">클라이언트와의 대화 1 : 쿠키</h3>
<p>쿠키(Cookie)는 클라이언트의 웹 브라우저에 저장되는 작은 데이터 조각입니다. 쿠키를 사용하면 클라이언트와 서버 간에 상태 정보를 유지하고 공유할 수 있습니다. JSP에서는 쿠키를 다루기 위해 Cookie 클래스를 제공합니다.</p>
<p>쿠키는 이름, 값, 유효 기간, 도메인, 경로 등의 속성으로 구성됩니다. JSP에서는 쿠키를 생성하고 응답에 추가하는 방법과, 클라이언트로부터 전송된 쿠키를 읽어오는 방법을 제공합니다.</p>
<p>쿠키를 생성하고 응답에 추가하는 방법은 다음과 같습니다.</p>
<pre><code>책
---------------------------------------
&lt;%
Cookie myCookie = new Cookie(&quot;cookieName&quot;, &quot;cookieValue&quot;);
response.addCookie(cookie);
%&gt;
---------------------------------------
&lt;%
Cookie myCookie = new Cookie(&quot;username&quot;, &quot;john&quot;);
myCookie.setMaxAge(60*60*24); // 쿠키의 유효 시간을 1일로 설정
response.addCookie(myCookie); // 응답에 쿠키 추가
%&gt;</code></pre><p>위 코드는 이름이 &quot;username&quot;이고 값이 &quot;john&quot;인 쿠키를 생성하고, 쿠키의 유효 시간을 1일로 설정하여 응답에 추가합니다.</p>
<p>클라이언트로부터 전송된 쿠키를 읽어오는 방법은 다음과 같습니다.</p>
<pre><code>책
---------------------------------------
&lt;%
Cookie[] cookies = request.getCookies();
%&gt;
---------------------------------------
&lt;%
Cookie[] cookies = request.getCookies(); // 모든 쿠키 가져오기
if (cookies != null) {
    for (Cookie cookie : cookies) {
        if (cookie.getName().equals(&quot;username&quot;)) {
            String username = cookie.getValue(); // 쿠키의 값 가져오기
            // ...
        }
    }
}
%&gt;</code></pre><p>위 코드는 모든 쿠키를 가져오고, 그 중에서 이름이 &quot;username&quot;인 쿠키의 값을 가져와서 변수에 저장합니다.</p>
<p>JSP에서 쿠키는 사용자의 로그인 정보, 쇼핑 카트 정보 등을 저장하고 유지하는 데 유용하게 사용됩니다. 그러나 보안에 민감한 정보를 저장하는 데에는 적합하지 않으므로 주의해야 합니다.</p>
<hr>

<h3 id="쿠키-생성해보기">쿠키 생성해보기</h3>
<p>[예제_쿠키 생성해보기]</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import = &quot;java.net.URLEncoder&quot; %&gt;
&lt;%
    Cookie cookie = new Cookie(&quot;name&quot;, URLEncoder.encode(&quot;최범균&quot;,&quot;utf-8&quot;));
    response.addCookie(cookie);
%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;쿠키생성&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%= cookie.getName() %&gt; 쿠키의 값 = &quot;&lt;%= cookie.getValue() %&gt;&quot;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/611c8471-ae26-44b2-8993-a688bd3ad9dc/image.png" alt=""></p>
<hr>
[예제]
**loginForm.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>

<form action="login.jsp" method="post">
    아이디<input type="text" name="id">
    비밀번호<input type="password" name="password">
    <input type="submit" value="로그인">
</form>
</body>
</html>
```

<p><strong>login.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import = &quot;java.net.URLEncoder&quot; %&gt;
&lt;%@ page import = &quot;util.Cookies&quot; %&gt;
&lt;%
    String id = request.getParameter(&quot;id&quot;);
    String password = request.getParameter(&quot;password&quot;);

    //ID와 암호가 같으면 로그인해라(쿠키에 값이 있으면)
    if(id.equals(password)){
        // Cookie 클래스 생성 또는 Cookies클래스 생성
//         Cookie cookie = new Cookie(&quot;id&quot;,URLEncoder.encode(id,&quot;utf-8&quot;));
//         response.addCookie(cookie);

        response.addCookie(
                Cookies.createCookie(&quot;AUTH&quot;, id, &quot;/&quot;, -1)
        );
        out.println(&quot;로그인 성공&quot;);
        }else{
            out.println(&quot;로그인 실패&quot;);
        }
%&gt;    
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

로그인에 성공했습니다.

&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>쿠키 확인하는법</strong>
개발자도구 - Application - Cookies 
<img src="https://velog.velcdn.com/images/jjinny_0609/post/fa794f36-29b6-4d32-9e12-d702833278ab/image.png" alt=""></p>
<hr>

<h3 id="세션을-사용한-로그인-상태-유지">세션을 사용한 로그인 상태 유지</h3>
<p>session.getAttribute는 object타입으로 받기 때문에 형변환을 해줘야하는걸 확인할 수 있습니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/7cf0a88f-25f0-4cab-9a12-bb5c6dd16078/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/ba90d0d3-f414-4f86-b528-c9184f8f5649/image.png" alt=""></p>
<hr>

<h2 id="표현-언어expression-language">표현 언어(Expression Language)</h2>
<p> JSP 표현 언어(EL, Expression Language)를 사용하여 Java 코드를 작성하지 않고도 변수나 객체의 값을 출력하거나, 연산을 수행할 수 있습니다. EL은 ${} 기호를 사용하여 값을 출력하거나, ${} 안에서 연산자나 메소드를 사용하여 값을 계산할 수 있습니다.</p>
<p>예를 들어, ${user.name}과 같이 작성하면 user 객체의 name 속성값을 출력할 수 있습니다. 또한, ${1 + 2}와 같이 작성하면 1과 2를 더한 결과를 출력할 수 있습니다.</p>
<p>JSP 표현 언어는 JSP 페이지에서 자주 사용되며, 코드를 간결하고 가독성이 높게 유지할 수 있도록 도와줍니다.</p>
<h3 id="jsp-elexpression-language">JSP EL(Expression Language)</h3>
<p>JSP EL(Expression Language)은 JSP 페이지에서 사용되는 표현 언어입니다. JSP EL은 ${} 기호를 사용하여 JSP 페이지에서 변수나 객체의 값을 출력하거나, 연산을 수행할 수 있습니다.</p>
<p>아래는 JSP EL의 기본 문법입니다.</p>
<p>변수 출력: ${변수명}
속성값 출력: ${객체.속성}
연산: ${식}
예를 들어, ${user.name}와 같이 작성하면 user 객체의 name 속성값을 출력할 수 있으며, ${1 + 2}와 같이 작성하면 1과 2를 더한 결과인 3을 출력할 수 있습니다.</p>
<p>JSP EL은 JSP 페이지에서 자주 사용되며, 코드를 간결하고 가독성이 높게 유지할 수 있도록 도와줍니다. JSP EL은 변수나 객체의 값을 출력하거나 연산을 수행하는데 유용하게 사용됩니다. 또한, JSP EL은 조건문과 반복문을 구현하는데도 사용될 수 있습니다.</p>
<p>JSP EL은 JSP 2.0부터 도입되었으며, 기존의 스크립트릿 코드를 대체하는 형태로 많이 사용되고 있습니다.</p>
<h3 id="jstljsp-standard-tag-library">JSTL(JSP Standard Tag Library)</h3>
<p> JSP 페이지에서 자주 사용되는 기능들을 태그 형태로 제공하여 개발자가 보다 쉽게 JSP 페이지를 작성할 수 있도록 도와주는 라이브러리입니다.</p>
<p>JSTL은 다음과 같은 기능들을 제공합니다.</p>
<p>Core Tags: 변수 선언, 조건문, 반복문 등의 기본적인 JSP 기능을 제공합니다.
Formatting Tags: 날짜, 시간, 숫자 등의 데이터 형식을 포맷팅할 때 사용합니다.
SQL Tags: SQL 질의를 수행할 때 사용합니다.
XML Tags: XML 데이터를 다룰 때 사용합니다.
각각의 기능은 태그 형태로 제공되며, 사용 방법도 간단합니다. 예를 들어, Core Tags 중 c:forEach 태그를 이용하면 반복문을 쉽게 구현할 수 있습니다.</p>
<pre><code>&lt;c:forEach var=&quot;item&quot; items=&quot;${items}&quot;&gt;
  &lt;li&gt;${item}&lt;/li&gt;
&lt;/c:forEach&gt;</code></pre><p>위 코드에서는 c:forEach 태그를 이용하여 items 변수에 담긴 리스트를 반복하여 각 항목을 출력하고 있습니다.</p>
<p>JSTL은 JSP 1.2부터 표준 라이브러리로 지정되어 있으며, 대부분의 JSP 컨테이너에서 기본적으로 제공됩니다. 따라서, JSTL을 이용하여 JSP 페이지를 작성하면 코드의 가독성이 높아지고, 생산성이 향상됩니다.</p>
<p><strong>JSTL 다운로드 링크 ↓</strong>
<a href="https://tomcat.apache.org/taglibs/standard/">https://tomcat.apache.org/taglibs/standard/</a></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3ff90015-adb5-4025-94fe-6a184c8b8f11/image.png" alt="">
1.2 download 클릭</p>
<p>해당 페이지에서는 JSTL 1.2 버전을 다운로드할 수 있으며, standard-1.2.5.zip 파일을 다운로드하여 압축을 해제하면 jstl.jar과 standard.jar 파일을 사용할 수 있습니다.</p>
<p>JSTL 라이브러리는 Maven, Gradle 등의 빌드 도구를 이용하여 다운로드할 수도 있습니다. 이 경우에는 해당 빌드 도구의 설정 파일에 JSTL 라이브러리를 추가하여 사용합니다.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/0f057e71-a7f8-412e-ad96-d434253f9966/image.png" alt=""></p>
<p>위에서 제공한 링크에서 제공하는 파일 중에서 mpl, Spec, EL, Compat은 각각 다음과 같은 차이가 있습니다.</p>
<p>mpl: JSTL(MPL)은 MultiPart parser를 이용한 파일 업로드를 처리하는 라이브러리입니다.</p>
<p>Spec: JSTL(Spec)은 JSP 페이지에서 자주 사용되는 기능을 제공하는 JSTL 핵심 기능을 포함하는 라이브러리입니다.</p>
<p>EL: JSTL(EL)은 JSTL에서 사용하는 EL(Expression Language)을 포함하는 라이브러리입니다. EL은 JSP 페이지에서 변수, 연산, 메소드 호출 등을 처리하는 데 사용됩니다.</p>
<p>Compat: JSTL(Compat)은 JSTL 1.1 버전 이전의 버전과의 호환성을 제공하는 라이브러리입니다.</p>
<p>따라서, mpl은 파일 업로드 기능을 제공하며, Spec은 JSTL의 핵심 기능을 포함하는 라이브러리이고, EL은 JSTL에서 사용하는 EL(Expression Language)을 포함하며, Compat은 JSTL 1.1 버전 이전과의 호환성을 제공하는 라이브러리입니다. 각각의 라이브러리는 필요에 따라 다운로드하여 사용할 수 있습니다.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/4bf8bdfc-6815-4958-ae7f-4faf2d4ad2d5/image.png" alt="">
다운받은 파일을 다음과 같은 경로에 넣어주자
WebContent - WEB-INF - lib</p>
<p>(스프링에서는 위 작업을 자동으로 처리해준다고 한다.. 나중에 배우면 또 알아보자)</p>
<hr>

<p>[예제_JSTL차이]</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;ul&gt;
  &lt;%-- JSP 표현 언어를 사용하여 for문 구현 --%&gt;
  &lt;c:forEach var=&quot;i&quot; begin=&quot;1&quot; end=&quot;10&quot;&gt;
    &lt;li&gt;${i}&lt;/li&gt;
  &lt;/c:forEach&gt;
&lt;/ul&gt;

&lt;%
    boolean a = true;
    if(a==true){
%&gt;
    무조건 실행&lt;br&gt;
&lt;%

    }
%&gt;

&lt;c:if test=&quot;true&quot;&gt;
무조건 수행
&lt;/c:if&gt;

&lt;/body&gt;
&lt;/html&gt;</code></pre><p>위 예제의 실행 결과
<img src="https://velog.velcdn.com/images/jjinny_0609/post/5c44c753-7d2d-43a9-9295-e8a79ab91dc7/image.png" alt=""></p>
<hr>

<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;ul&gt;
  &lt;%-- JSP 표현 언어를 사용하여 for문 구현 --%&gt;
  &lt;c:forEach var=&quot;i&quot; begin=&quot;1&quot; end=&quot;10&quot;&gt;
    &lt;li&gt;${i}&lt;/li&gt;
  &lt;/c:forEach&gt;
&lt;/ul&gt;

&lt;%
    boolean a = true;
    if(a==true){
%&gt;
    무조건 실행&lt;br&gt;
&lt;%
    }
%&gt;

&lt;c:if test=&quot;true&quot;&gt;
무조건 수행
&lt;/c:if&gt;

&lt;c:if test=&quot;${param.name == &#39;bk&#39;}&quot;&gt;
    name 파라미터의 값이 ${param.name} 입니다.&lt;br&gt;
&lt;/c:if&gt;


&lt;/body&gt;
&lt;/html&gt;</code></pre><p>주소창에 아래와 같이 입력하면 파라미터를 받아와 결과를 출력하게 된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/155f04b1-9a61-459e-ac3b-8fcd88bd5792/image.png" alt=""></p>
<hr>

<h3 id="cif-cchoose-cwhen-cotherwise-태그">c:if, c:choose, c:when, c:otherwise 태그</h3>
<p><strong>c:if 태그</strong>: 
지정한 조건식이 참(true)인 경우에만 지정한 내용을 출력합니다. 예를 들어, 다음과 같이 사용할 수 있습니다.</p>
<pre><code>&lt;c:if test=&quot;${조건식}&quot;&gt;
    실행할 코드
&lt;/c:if&gt;</code></pre><p><strong>c:choose, c:when, cLotherwise 태그</strong>:
여러 개의 조건을 비교하여 조건에 따라 다른 내용을 출력할 때 사용합니다. c:choose 태그로 시작하고, c:when 태그로 조건을 지정하며, cLotherwise 태그로 마무리합니다. 예를 들어, 다음과 같이 사용할 수 있습니다.</p>
<pre><code>&lt;c:choose&gt;
    &lt;c:when test=&quot;${조건식1}&quot;&gt;
        실행할 코드1
    &lt;/c:when&gt;
    &lt;c:when test=&quot;${조건식2}&quot;&gt;
        실행할 코드2
    &lt;/c:when&gt;
    &lt;c:otherwise&gt;
        실행할 코드3
    &lt;/c:otherwise&gt;
&lt;/c:choose&gt;</code></pre><p>위 코드에서는 age 변수의 값에 따라서 다른 내용을 출력합니다. age가 18 이상인 경우에는 &quot;성인입니다.&quot;라는 내용을 출력하고, 13 이상인 경우에는 &quot;청소년입니다.&quot;라는 내용을 출력하며, 그 외의 경우에는 &quot;미성년입니다.&quot;라는 내용을 출력합니다.</p>
<p>즉, c:choose, c:when, c:otherwise 태그는 if-else if-else 구문과 유사한 구조를 가지고 있습니다.</p>
<p>다음 코드는 score 변수의 값에 따라 등급을 출력하는 예제입니다.</p>
<pre><code>&lt;c:set var=&quot;score&quot; value=&quot;${100}&quot; /&gt;
&lt;c:choose&gt;
    &lt;c:when test=&quot;${score &gt;= 90}&quot;&gt;
        &lt;p&gt;등급: A&lt;/p&gt;
    &lt;/c:when&gt;
    &lt;c:when test=&quot;${score &gt;= 80}&quot;&gt;
        &lt;p&gt;등급: B&lt;/p&gt;
    &lt;/c:when&gt;
    &lt;c:when test=&quot;${score &gt;= 70}&quot;&gt;
        &lt;p&gt;등급: C&lt;/p&gt;
    &lt;/c:when&gt;
    &lt;c:otherwise&gt;
        &lt;p&gt;등급: D&lt;/p&gt;
    &lt;/c:otherwise&gt;
&lt;/c:choose&gt;</code></pre><hr>

<h3 id="cforeach">c:forEach</h3>
<p>반복문을 구현하는 태그입니다. c:forEach 태그를 사용하면 배열이나 컬렉션 등의 데이터를 반복하여 처리할 수 있습니다.</p>
<p>c:forEach 태그는 다음과 같은 속성을 가집니다.</p>
<p>var: 반복문에서 현재 요소를 저장할 변수의 이름을 지정합니다.
items: 반복할 데이터를 지정합니다. 배열, List, Map, Set 등의 컬렉션 객체를 사용할 수 있습니다.
begin: 반복문 시작 인덱스를 지정합니다. 기본값은 0입니다.
end: 반복문 종료 인덱스를 지정합니다. 기본값은 items의 크기-1입니다.
step: 반복문의 증감값을 지정합니다. 기본값은 1입니다.
c:forEach 태그는 다음과 같이 사용됩니다.</p>
<pre><code>&lt;c:forEach var=&quot;element&quot; items=&quot;${list}&quot;&gt;
    반복할 코드
&lt;/c:forEach&gt;
</code></pre><p>위의 코드는 list 변수에 저장된 컬렉션 객체의 모든 요소를 순회하면서, 각 요소에 대해 element라는 변수에 값을 저장하고 내부의 코드를 실행합니다. var 속성으로 지정한 변수를 이용하여 반복문 안에서 현재 요소에 접근할 수 있습니다.</p>
<p>예를 들어, 다음 코드는 배열의 모든 요소를 출력하는 예제입니다.</p>
<pre><code>&lt;%@ taglib prefix=&quot;c&quot; uri=&quot;http://java.sun.com/jsp/jstl/core&quot; %&gt;

&lt;c:set var=&quot;numbers&quot; value=&quot;${[1, 2, 3, 4, 5]}&quot; /&gt;

&lt;c:forEach var=&quot;num&quot; items=&quot;${numbers}&quot;&gt;
    ${num} 
&lt;/c:forEach&gt;</code></pre><p>위 코드에서 c:set 태그를 사용하여 numbers 변수에 배열을 저장하고, c:forEach 태그를 사용하여 배열의 모든 요소를 출력합니다. 출력 결과는 다음과 같습니다.</p>
<pre><code>1 2 3 4 5
</code></pre><hr>

<p>[예제]</p>
<pre><code>&lt;c:forEach var=&quot;i&quot; begin=&quot;1&quot; end=&quot;10&quot;&gt;
    ${i} 사용
&lt;/c:forEach&gt;

for(int i = 1; i&lt;=10; i++){
}</code></pre><hr>

<pre><code>&lt;c:forEach var=&quot;i&quot; items=&quot;${intArray}&quot;&gt;

&lt;/c:forEach&gt;

int[] intArray = new int[3];

for(int i = 1; i&lt;=10; i++){}            // 일반적인 for문

for(int i : intArray){}                // 향상된 for(배열에서만)</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[JSP #2]]></title>
            <link>https://velog.io/@jjinny_0609/JSP-2</link>
            <guid>https://velog.io/@jjinny_0609/JSP-2</guid>
            <pubDate>Tue, 21 Mar 2023 07:03:59 GMT</pubDate>
            <description><![CDATA[<h3 id="리다이렉트를-이용해서-페이지-이동하기">리다이렉트를 이용해서 페이지 이동하기</h3>
<p>리다이렉트는 서버 측에서 페이지 이동을 처리하는 방법 중 하나입니다. 이 방법을 사용하면 클라이언트가 요청한 페이지를 서버에서 다른 페이지로 이동시킬 수 있습니다.</p>
<p>JSP 리다이렉트를 수행하는 방법은 다음과 같습니다.</p>
<ul>
<li>클라이언트가 요청한 페이지에서 리다이렉트를 수행하는 경우, HttpServletResponse 객체의 sendRedirect() 메서드를 사용합니다.</li>
</ul>
<pre><code>response.sendRedirect(&quot;이동할페이지의 URL&quot;);</code></pre><ul>
<li>서블릿(서버 측 프로그램 혹은 그 사양)에서 리다이렉트를 수행하는 경우, HttpServletResponse 객체를 이용하여 리다이렉트를 수행합니다.<pre><code>response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);
response.setHeader(&quot;Location&quot;, &quot;이동할페이지의 URL&quot;);</code></pre>위의 코드에서 &quot;이동할페이지의 URL&quot;은 이동할 대상 페이지의 URL을 입력하면 됩니다.</li>
</ul>
<p>리다이렉트는 클라이언트가 요청한 페이지의 URL이 변경되는 것을 의미합니다. 따라서, 클라이언트는 새로운 URL로 요청을 보내게 되며, 이 때 HTTP 상태 코드 302가 반환됩니다.</p>
<p>리다이렉트를 이용하여 페이지 이동을 처리하는 경우, 클라이언트가 새로운 페이지를 요청하므로, 이전 페이지에서 사용자가 입력한 데이터는 유지되지 않습니다. 따라서, 이전 페이지에서 입력한 데이터를 새로운 페이지에서 사용해야 하는 경우, 세션 객체나 쿠키를 이용하여 데이터를 전달해야 합니다.</p>
<p><strong>[예제]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/fec5a79a-2e47-4b5d-9dec-621aee3ef2de/image.png" alt="">
member id가 &#39;madovirus&#39;인지 비교</p>
<p>값 이 &#39;madovirus&#39; 이면
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a4f56194-e3f7-4261-9ebb-52f76fb9dd6f/image.png" alt=""></p>
<p>값 이 &#39;madovirus&#39; 아니면
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a128f72d-a1f2-4f72-be36-a08fd78730e3/image.png" alt="">
를 출력한다.</p>
<hr>

<h3 id="jsp-처리과정">JSP 처리과정</h3>
<p>JSP(Java Server Pages)는 동적인 웹 페이지를 생성하기 위한 기술로, 서블릿 기술을 기반으로 하고 있습니다. JSP 페이지는 일반적인 HTML 페이지와 같은 모습으로 구성되어 있지만, &lt;% %&gt;와 같은 특수한 태그를 사용하여 자바 코드를 삽입할 수 있습니다.</p>
<p><strong>JSP 페이지가 처리되는 과정은 다음과 같습니다.</strong></p>
<ol>
<li>클라이언트가 JSP 페이지를 요청합니다.</li>
<li>웹 서버는 요청을 받아서 JSP 페이지를 처리하기 위해 JSP 엔진에게 제어권을 넘깁니다.</li>
<li>JSP 엔진은 JSP 페이지를 서블릿 클래스로 변환합니다. 이때, JSP 페이지의 코드와 태그가 서블릿 코드로 변환되며, 변환된 서블릿 클래스는 .java 파일로 생성됩니다.</li>
<li>서블릿 클래스는 자바 컴파일러를 사용하여 .class 파일로 컴파일됩니다.</li>
<li>컴파일된 서블릿 클래스는 서블릿 컨테이너에 의해 실행됩니다.</li>
<li>실행된 서블릿 클래스는 요청을 처리하고, HTML 코드를 생성하여 클라이언트로 응답합니다.</li>
</ol>
<p>즉, JSP 페이지가 클라이언트에게 보여지기 위해서는 서블릿으로 변환되고, 서블릿 클래스가 실행되어야 합니다. 이 과정에서 서블릿 컨테이너는 JSP 페이지를 처리하고, 서블릿 클래스를 생성하고, 실행하여 요청을 처리하게 됩니다.</p>
<ul>
<li>JSP의 처리과정 
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e0fadaf3-d36a-4041-ad98-1416dd4e654c/image.png" alt=""></li>
</ul>
<hr>

<h3 id="웹-에플리케이션-폴더-구성과-url-매핑">웹 에플리케이션 폴더 구성과 URL 매핑</h3>
<h4 id="jsp-폴더-구성">JSP 폴더 구성</h4>
<p>JSP 페이지를 포함하는 폴더 구조는 다음과 같은 구성 요소를 가질 수 있습니다.</p>
<ul>
<li><p>WebContent 폴더
JSP 페이지와 웹 애플리케이션에서 사용되는 다른 자원(이미지, CSS 파일 등)을 포함하는 폴더입니다.
JSP 페이지는 WebContent 폴더의 하위 폴더에 위치할 수 있습니다.</p>
</li>
<li><p>WEB-INF 폴더
웹 애플리케이션의 구성 정보와 자원을 포함하는 폴더입니다.
WEB-INF 폴더의 lib 폴더에는 웹 애플리케이션에서 사용되는 라이브러리 파일(.jar 파일)이 위치할 수 있습니다.
WEB-INF 폴더의 web.xml 파일은 웹 애플리케이션의 구성 정보를 정의합니다.</p>
</li>
<li><p>META-INF 폴더
JAR 파일에서 사용되는 메타데이터를 포함하는 폴더입니다.
웹 애플리케이션에서는 사용되지 않는 폴더입니다.</p>
</li>
</ul>
<p>JSP 페이지는 일반적으로 WebContent 폴더의 하위 폴더에 위치합니다. 예를 들어, /WebContent/index.jsp와 같은 경로로 JSP 페이지를 배치할 수 있습니다.</p>
<p>또한, JSP 페이지에서 사용하는 자바 클래스 파일이나 라이브러리 파일은 WEB-INF/lib 폴더에 위치할 수 있습니다. 이렇게 함으로써, JSP 페이지에서 사용하는 자바 클래스나 라이브러리를 직접적으로 웹 브라우저에서 접근할 수 없게 되어 보안상의 이점을 가질 수 있습니다.</p>
<h4 id="jsp폴더와-url관계">JSP폴더와 URL관계</h4>
<p>폴더와 URL의 관계는 웹 애플리케이션의 폴더 구조와 밀접한 관련이 있습니다. JSP 페이지를 포함하는 폴더의 위치에 따라서 URL의 경로도 달라지기 때문입니다.</p>
<p>보통 JSP 페이지는 웹 애플리케이션의 WebContent 폴더 안에 위치하며, URL의 경로는 WebContent 폴더를 루트로 하는 상대 경로로 지정됩니다. 예를 들어, WebContent 폴더 안에 login.jsp라는 파일이 있다면, 이 파일을 호출하기 위한 URL은 &quot;/login.jsp&quot;가 됩니다.</p>
<p>만약 WebContent 폴더 안에 하위 폴더를 더 추가했다면, URL에서는 하위 폴더를 경로에 추가하여 접근할 수 있습니다. 예를 들어, WebContent 폴더 안에 board라는 하위 폴더가 있고, 그 안에 list.jsp라는 파일이 있다면, 이 파일을 호출하기 위한 URL은 &quot;/board/list.jsp&quot;가 됩니다.</p>
<p>또한, JSP 페이지에서 서블릿 코드를 사용하여 동적인 웹 페이지를 생성할 때는, 서블릿 클래스의 URL 경로를 정의해야 합니다. 서블릿 클래스의 URL 경로는 @WebServlet 어노테이션을 사용하여 지정할 수 있습니다. 예를 들어, @WebServlet(&quot;/example&quot;) 어노테이션이 있다면, &quot;/example&quot; 경로를 사용하여 이 서블릿 클래스를 호출할 수 있습니다.</p>
<p>따라서, JSP 페이지와 URL은 웹 애플리케이션의 폴더 구조에 따라 관계가 결정되며, URL은 JSP 페이지나 서블릿 클래스를 호출하기 위한 경로로 사용됩니다.</p>
<h3 id="웹-애플리케이션-배포">웹 애플리케이션 배포</h3>
<ul>
<li><p>대상 폴더에 파일을 직접 복사</p>
</li>
<li><p>가장 일반적인 방법은 WAR(Web Application Archive) 파일을 생성하여 웹 서버에 배포하는 것입니다. 
(WAR 파일은 압축된 웹 애플리케이션 파일로, 웹 애플리케이션을 실행하는 데 필요한 모든 파일과 설정 정보를 포함합니다.)</p>
</li>
</ul>
<p><em>JSP 웹 애플리케이션을 배포하는 방법은 다음과 같습니다.</em></p>
<ol>
<li>WAR 파일 생성</li>
</ol>
<ul>
<li>웹 애플리케이션의 모든 파일과 설정 정보를 포함하는 WAR 파일을 생성합니다.</li>
<li>보통 이 작업은 IDE(통합 개발 환경)에서 지원해 주는 기능을 사용하여 수행합니다.</li>
</ul>
<ol start="2">
<li>WAR 파일을 웹 서버에 배포</li>
</ol>
<ul>
<li>WAR 파일을 웹 서버에 업로드하여 배포합니다.</li>
<li>대부분의 웹 서버는 관리자 콘솔을 통해 파일 업로드 및 배포를 지원합니다.</li>
</ul>
<ol start="3">
<li>웹 서버 구성 변경</li>
</ol>
<ul>
<li>배포한 웹 애플리케이션을 실행하기 위해 웹 서버의 구성 정보를 변경해야 할 수도 있습니다.</li>
<li>예를 들어, 웹 서버의 context.xml 파일에 웹 애플리케이션의 컨텍스트 경로를 설정해야 할 수도 있습니다.</li>
</ul>
<ol start="4">
<li>웹 애플리케이션 테스트</li>
</ol>
<ul>
<li>웹 서버에 배포한 웹 애플리케이션이 정상적으로 동작하는지 테스트합니다.</li>
<li>웹 브라우저에서 웹 애플리케이션의 URL을 입력하여 접속할 수 있습니다.</li>
</ul>
<p>JSP 웹 애플리케이션을 배포할 때는, 웹 서버와 호환되는 버전의 Java 및 JSP 컨테이너가 설치되어 있어야 합니다. 또한, 웹 애플리케이션을 개발하는 환경과 웹 서버의 환경이 다르면, 환경 설정 문제로 인해 문제가 발생할 수 있으므로, 가능하면 개발 환경과 동일한 환경에서 배포하는 것이 좋습니다.</p>
<h4 id="war파일">war파일</h4>
<p>프로젝트 선택 - 우클릭 - Export - WAR file 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/139f6f27-e5e0-4c82-9247-21ac11b2e856/image.png" alt="">
Browse...클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6bddb368-ef43-430c-afc1-a26c8f92caa1/image.png" alt="">
톰캣 경로에 webapps에 저장 - finish
<img src="https://velog.velcdn.com/images/jjinny_0609/post/b5e8a558-ac06-40de-b15e-6891b1dc3981/image.png" alt="">
(프로젝트명).war 파일이 생성된것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/007af972-8ac3-44c5-9285-2fd04db81aa6/image.png" alt=""></p>
<p>배포할땐 이클립스에 있는 톰캣을 끄고 윈도우즈에 (apache-tomcat-8.5.87\bin 경로) 있는 startup.bat 실행시키면 .war 파일이 있다면 톰캣은 그 파일을 압축해제하면서 실행한다.</p>
<p>두개의 톰캣(이클립스와 startup으로 실행)을 동시에 실행하는건 불가능(같이 켜면 충돌하므로)</p>
<p>bin에서 startup 배치파일을 클릭하면 war파일이 압축해제 되는것을 확인할 수 있다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bfb89014-37d8-4702-ab79-327e7e44b73e/image.png" alt=""></p>
<p>\apache-tomcat-8.5.87\conf에 server.xml설정과
web.xml에 맨 아래 welcom-file-list를 기본 index.html로 되어있는걸 수정</p>
<hr>

<h2 id="기본-객체와-영역">기본 객체와 영역</h2>
<h3 id="기본-객체">기본 객체</h3>
<ul>
<li><p>request: 
클라이언트가 서버에 요청한 정보를 담고 있는 객체입니다. HttpServletRequest 인터페이스를 구현한 객체로서, 클라이언트가 전송한 파라미터나 헤더 정보 등을 가져올 수 있습니다.</p>
</li>
<li><p>response: 
서버가 클라이언트에게 응답할 정보를 담고 있는 객체입니다. HttpServletResponse 인터페이스를 구현한 객체로서, 클라이언트에게 전송할 데이터를 설정하거나 리다이렉트를 수행하는 등의 작업을 할 수 있습니다.</p>
</li>
<li><p>page : JSP 페이지 내에서 자동으로 생성되므로, 별도의 객체 생성 없이 바로 사용할 수 있습니다. 주로 JSP 페이지에서 contentType, isErrorPage 등의 속성을 설정하거나, exception 메소드를 사용하여 예외 처리를 수행하는 데 사용됩니다.</p>
</li>
<li><p>pageContext: 
JSP 페이지의 컨텍스트 정보를 담고 있는 객체입니다. PageContext 클래스를 구현한 객체로서, 현재 JSP 페이지의 다른 객체들을 참조할 수 있습니다.</p>
</li>
<li><p>session: 클라이언트와 서버 사이의 상태 정보를 유지하기 위한 객체입니다. HttpSession 인터페이스를 구현한 객체로서, 클라이언트가 로그인한 사용자인지 등을 판단할 때 사용됩니다.</p>
</li>
<li><p>application:
웹 어플리케이션 전체에서 공유되는 객체입니다. ServletContext 인터페이스를 구현한 객체로서, 서버가 시작될 때 생성되고 서버가 종료될 때까지 유지됩니다. 보통 웹 어플리케이션에서 설정 정보나 공유 데이터 등을 저장하기 위해 사용됩니다.</p>
</li>
<li><p>out: 
응답 결과를 출력하기 위한 출력 스트림 객체입니다. JspWriter 클래스를 구현한 객체로서, HTML 코드나 텍스트 데이터를 출력할 때 사용됩니다.</p>
</li>
<li><p>config: JSP 페이지의 설정 정보를 담고 있는 객체입니다. ServletConfig 인터페이스를 구현한 객체로서, JSP 페이지에서 설정 정보를 읽어올 수 있습니다.</p>
</li>
<li><p>exception: JSP 페이지에서 발생한 예외 정보를 담고 있는 객체입니다. Exception 클래스를 구현한 객체로서, JSP 페이지에서 예외가 발생한 경우 이 객체를 이용하여 예외 정보를 처리할 수 있습니다.</p>
</li>
</ul>
<hr>

<p>[예제]</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    out.println(&quot;안녕하세요&quot;);
%&gt;
// &lt;br&gt;을 안넣으면 줄바꿈을 안한다.
out 기본 객체를 사용하여
&lt;%
    out.println(&quot;출력한 결과입니다.&quot;);
%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/9ff759c8-ef41-4b25-bc83-d7c4186a1dbe/image.png" alt=""></p>
<p>br을 추가한 결과
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d5c8059a-8e36-43cf-afa2-d74658676c46/image.png" alt=""></p>
<hr>

<h3 id="jsp-기본-객체와-영역">JSP 기본 객체와 영역</h3>
<p>웹 애플리케이션의 네 가지 영역(scope)은 다음과 같습니다.</p>
<ul>
<li><p><strong>Request 영역</strong> : 클라이언트로부터 들어온 요청(request) 정보를 담고 있는 영역입니다. 즉, 클라이언트가 요청한 페이지에서만 유효한 데이터를 저장하고 공유할 수 있습니다. 이 데이터는 서버가 클라이언트의 요청을 처리하는 동안에만 유효하며, 다른 페이지로 이동하면 데이터가 사라집니다.</p>
</li>
<li><p><strong>Session 영역</strong> : 웹 애플리케이션 내에서 특정 세션(session)에 대한 데이터를 저장하고 공유할 수 있는 영역입니다. 즉, 클라이언트와 서버 간에 연결이 유지되는 동안 계속해서 유효한 데이터를 저장하고 공유할 수 있습니다. 이 데이터는 같은 세션 내에서 모든 페이지에서 유효합니다.</p>
</li>
<li><p><strong>Context 영역</strong> : 웹 애플리케이션 내에서 모든 클라이언트에 대한 데이터를 저장하고 공유할 수 있는 영역입니다. 이 데이터는 웹 애플리케이션이 실행되는 동안 계속해서 유효하며, 모든 페이지에서 접근할 수 있습니다.</p>
</li>
<li><p><strong>Application 영역</strong> : 웹 애플리케이션 내에서 전역적으로 사용할 수 있는 데이터를 저장하고 공유할 수 있는 영역입니다. 이 데이터는 웹 애플리케이션이 실행되는 동안 계속해서 유효하며, 모든 클라이언트에서 접근할 수 있습니다.</p>
</li>
</ul>
<p>이 네 가지 영역은 각각의 특성에 따라 사용되는 데이터의 유효 범위와 생명 주기가 다르기 때문에, 적절한 용도에 따라 선택하여 사용해야 합니다.</p>
<hr>

<h2 id="에러-처리">에러 처리</h2>
<ul>
<li>익셉션 처리</li>
<li>에러 페이지
&lt;%@ page errorPage = &quot;에러페이지.jsp&quot; %&gt;</li>
<li>상태 코드와 익셉션 타입별 에러 페이지 지정<h3 id="익셉션-직접-처리하기">익셉션 직접 처리하기</h3>
JSP 페이지에서는 try-catch 블록을 사용하여 예외 처리를 할 수 있습니다. 예외가 발생할 가능성이 있는 코드를 try 블록 안에 작성하고, 예외가 발생하면 catch 블록에서 처리합니다.</li>
</ul>
<p>예를 들어, 다음과 같이 NullPointerException이 발생할 가능성이 있는 코드를 예외 처리합니다.</p>
<pre><code>&lt;%@ page language=&quot;java&quot; %&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Exception Handling in JSP&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
try {
    String str = null;
    str.length();
} catch (NullPointerException e) {
    out.println(&quot;NullPointerException occurred: &quot; + e.getMessage());
}
%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>위 코드에서는 try 블록에서 NullPointerException이 발생할 가능성이 있는 str.length(); 코드를 작성하고, catch 블록에서 NullPointerException을 처리합니다. 이렇게 예외가 발생할 가능성이 있는 코드를 try 블록에 작성하고, 예외가 발생하면 catch 블록에서 예외를 처리합니다.</p>
<p>또한, JSP에서는 에러 페이지(error page)를 설정하여 예외 처리를 할 수도 있습니다. 에러 페이지를 설정하면, 예외가 발생했을 때 해당 페이지로 자동으로 이동하게 됩니다. 이를 위해서는 &lt;%@ page isErrorPage=&quot;true&quot; %&gt; 디렉티브를 설정해야 하며, 에러 페이지에서는 exception 내장 객체를 사용하여 예외 정보를 출력할 수 있습니다.</p>
<pre><code>&lt;%@ page language=&quot;java&quot; isErrorPage=&quot;true&quot; %&gt;
&lt;html&gt;
&lt;head&gt;
&lt;title&gt;Error Page&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
An error occurred:
&lt;%= exception.getMessage() %&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>위 코드에서는 &lt;%@ page language=&quot;java&quot; isErrorPage=&quot;true&quot; %&gt; 디렉티브를 설정하여 이 페이지가 에러 페이지임을 나타내고, exception 내장 객체를 사용하여 예외 정보를 출력합니다. 이렇게 설정된 에러 페이지는 예외가 발생하면 자동으로 호출되어 예외 처리를 수행합니다.</p>
<hr>

<p><strong>[익셉션 예제]</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

name 파라미터 값 : &lt;%= request.getParameter(&quot;name&quot;).toUpperCase() %&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/752e44d6-bd2d-4e4a-a266-51f1ab08705b/image.png" alt=""></p>
<p>name을 요청한게 없어서 에러가 발생한다.</p>
<p>익셉션을 이용해 처리해보자</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

name 파라미터 값 : 
&lt;% try { %&gt;
&lt;%= request.getParameter(&quot;name&quot;).toUpperCase() %&gt;
&lt;% } catch(Exception ex) { %&gt;
name 파라미터가 올바르지 않습니다.
&lt;% } %&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/015b446b-268e-44fe-a7a6-8d9c365478ae/image.png" alt=""></p>
<hr>

<h3 id="에러-페이지-지정하기--작성하기">에러 페이지 지정하기 &amp; 작성하기</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/5424e379-780d-4c56-8ccc-a03baaabcc60/image.png" alt=""></p>
<h3 id="응답-상태-코드별로-에러페이지-지정하기">응답 상태 코드별로 에러페이지 지정하기</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/d99178f8-8ceb-4e57-a8a3-bdd20d03ff77/image.png" alt="">
<web-app> 과 </web-app> 사이에 아래의 404 에러코드를 처리하는 설정 추가
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e65a80be-8f6a-4d7d-b1b6-5b044b40a9e7/image.png" alt=""></p>
<hr>

<h3 id="페이지-모듈화의-요청-흐름-제어">페이지 모듈화의 요청 흐름 제어</h3>
<h4 id="jspinclude-액션-태그를-이용한-공통-영역-작성">jsp:include 액션 태그를 이용한 공통 영역 작성</h4>
<p>jsp:include 디렉티브는 JSP 페이지에서 다른 JSP 페이지나 HTML 파일을 포함하는 데 사용됩니다.</p>
<p>사용 방법은 다음과 같습니다.</p>
<pre><code>&lt;jsp:include page=&quot;파일이름.jsp&quot; /&gt;</code></pre><p>위의 코드는 현재 JSP 페이지에 &quot;파일이름.jsp&quot; 파일을 포함합니다.</p>
<p>또한, 다른 JSP 페이지에 있는 변수나 메소드를 사용하고 싶은 경우, 아래와 같이 속성을 사용할 수 있습니다.</p>
<pre><code>&lt;jsp:include page=&quot;파일이름.jsp&quot;&gt;
    &lt;jsp:param name=&quot;변수명&quot; value=&quot;&lt;%=변수값%&gt;&quot;/&gt;
&lt;/jsp:include&gt;</code></pre><p>위의 코드는 &quot;파일이름.jsp&quot; 파일을 포함하고, &quot;변수명&quot;이라는 이름으로 변수를 전달합니다. 이 변수는 &lt;%=변수값%&gt;에 해당하는 값으로 설정됩니다.</p>
<p>주의할 점은 jsp:include 디렉티브를 사용하면 포함된 파일의 내용이 현재 JSP 페이지에 그대로 복사되므로, 포함된 파일에 있는 변수나 메소드는 현재 JSP 페이지에서 직접 사용할 수 있습니다. 따라서 포함된 파일에 중복되는 변수나 메소드가 있을 경우 충돌이 발생할 수 있으므로 주의해야 합니다.</p>
<p><strong>[예제]</strong>
코드 main.jsp , sub.jsp
<img src="https://velog.velcdn.com/images/jjinny_0609/post/fee9fed1-bb80-4b49-bd73-d8a3e830f1d3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/8f204f46-2409-4ead-96bc-ce85e1a1d01a/image.png" alt="">
결과 
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a68f291e-5054-46a7-9995-9cca05d2d3e3/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/84317a51-c232-428d-ba0a-a7f32ebc76b1/image.png" alt=""></p>
<hr>

<h3 id="액션태그를-이용한-중복-영역-처리">액션태그를 이용한 중복 영역 처리</h3>
<p>[예제]
<strong>layout.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;table border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td colspan=&quot;2&quot;&gt;
            &lt;jsp:include page = &quot;top.jsp&quot;/&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;&lt;jsp:include page = &quot;left.jsp&quot;/&gt;&lt;/td&gt;
        &lt;td&gt;중앙내용&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td colspan=&quot;2&quot;&gt;
            &lt;jsp:include page = &quot;bottom.jsp&quot;/&gt;
        &lt;/td&gt;
    &lt;/tr&gt;
    &lt;/table&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>top.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
상단 메뉴: &lt;a href=&quot;layout.jsp&quot;&gt;홈&lt;/a&gt; &lt;a href=&quot;layout.jsp&quot;&gt;정보&lt;/a&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>left.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
좌측 메뉴: 
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>bottom.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
하단 메뉴 : 소개 | 도움말 | 약관 | 사이트맵
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>결과 
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bebfbd9d-caba-40e6-9790-1e40c85069a9/image.png" alt=""></p>
<hr>

<h3 id="jspparam으로-포함할-페이지에-파라미터-추가하기">jsp:param으로 포함할 페이지에 파라미터 추가하기</h3>
<p><strong>info.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;table border=&quot;1&quot;&gt;
    &lt;tr&gt;
        &lt;td&gt;제품코드&lt;/td&gt;&lt;td&gt;xxxx&lt;/td&gt;
    &lt;/tr&gt;
    &lt;tr&gt;
        &lt;td&gt;가격&lt;/td&gt;&lt;td&gt;10,000원&lt;/td&gt;
    &lt;/tr&gt;
&lt;/table&gt;
&lt;jsp:include page=&quot;infosub.jsp&quot; flush=&quot;false&quot;&gt;
    &lt;jsp:param name=&quot;type&quot; value=&quot;A&quot; /&gt;
&lt;/jsp:include&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>infosub.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%
    String type = request.getParameter(&quot;type&quot;);
    if(type==null){
        return;
    }
%&gt;
&lt;br&gt;
&lt;table border=&quot;1&quot;&gt;
&lt;tr&gt;
    &lt;td&gt;타입&lt;/td&gt;
    &lt;td&gt;&lt;%=type %&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
    &lt;td&gt;특징&lt;/td&gt;
    &lt;td&gt;
        &lt;% if(type.equals(&quot;A&quot;)){ %&gt;
        강한 내구성
        &lt;%}else if(type.equals(&quot;B&quot;)){ %&gt;
        뛰어난 대처 능력
        &lt;%} %&gt;
    &lt;/td&gt;
&lt;/tr&gt;
&lt;/table&gt;</code></pre><p>[결과]
값이 A일때
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e889110e-8e41-4c18-b5b2-3b810dca1bc1/image.png" alt=""></p>
<p>값이 B일때
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ad57f59e-ca06-491a-ab66-c3810208f207/image.png" alt=""></p>
<hr>

<h3 id="include-디렉티브의-처리-방식과-사용법">include 디렉티브의 처리 방식과 사용법</h3>
<pre><code>&lt;%@ include file=&quot;포함할 파일&quot; %&gt;</code></pre><p>jspf 확장자를 가진 파일은 JSP fragment 파일이라고도 불리며, JSP 페이지에서 재사용 가능한 코드 조각을 분리하여 작성할 때 사용됩니다. 이 파일들은 일반적으로 JSP 페이지에서 자주 사용되는 HTML, Java 코드, JavaScript 등을 포함하고 있습니다.</p>
<p>jspf 파일을 include하는 방법은 다음과 같습니다.</p>
<pre><code>&lt;%@ include file=&quot;파일이름.jspf&quot; %&gt;</code></pre><p>위의 코드는 현재 JSP 페이지에 &quot;파일이름.jspf&quot; 파일을 포함합니다.</p>
<p>주의할 점은 include 디렉티브를 사용하면 포함된 파일의 내용이 현재 JSP 페이지에 그대로 복사되므로, 포함된 파일에 있는 변수나 메소드는 현재 JSP 페이지에서 직접 사용할 수 있습니다. 따라서 포함된 파일에 중복되는 변수나 메소드가 있을 경우 충돌이 발생할 수 있으므로 주의해야 합니다.</p>
<p><strong>[예제]</strong>
<strong>includer.jsp</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    int number = 10;
%&gt;

&lt;%@ include file=&quot;includee.jspf&quot; %&gt;

공통변수 DATAFOLDER &quot;&lt;%= dataFolder %&gt;&quot;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>incldee.jspf</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;

includer.jsp에서 지정한 번호 : &lt;%= number %&gt;
&lt;p&gt;
&lt;%
    String dataFolder = &quot;c:\\data&quot;;
%&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/df36318a-b986-43a5-bcbf-c7042b33ddfb/image.png" alt=""></p>
<hr>

<h3 id="jspforward-액션-태그의-사용법"><a href="jsp:forward">jsp:forward</a> 액션 태그의 사용법</h3>
<p>jsp:forward는 JSP 페이지에서 다른 JSP 페이지나 서블릿으로 제어를 전달하는 데 사용됩니다.</p>
<p>jsp:forward 사용법은 다음과 같습니다.</p>
<pre><code>&lt;jsp:forward page=&quot;이동할_페이지_이름&quot; /&gt;</code></pre><p>위의 코드에서 &quot;이동할_페이지_이름&quot;은 제어를 전달할 페이지의 이름이나 경로입니다.</p>
<p>jsp:forward는 현재 JSP 페이지의 출력 스트림을 비워주고, 제어를 전달할 페이지나 서블릿으로 이동합니다. 따라서 jsp:forward 태그 이후에 있는 코드는 실행되지 않습니다. 또한, 제어를 전달한 페이지에서는 다시 돌아올 수 없으므로 주의해야 합니다.</p>
<p>주의할 점은 jsp:forward를 사용하면 브라우저는 새로운 요청을 보내게 되므로, URL이 변경됩니다. 따라서 jsp:forward는 현재 페이지와 전달할 페이지가 같은 웹 어플리케이션 내에 있어야 합니다.</p>
<p>jsp:forward는 주로 조건에 따라 다른 페이지로 제어를 전달할 때 사용됩니다. 예를 들어, 로그인이 필요한 페이지에 접근하려는 경우 로그인 페이지로 제어를 전달할 수 있습니다.</p>
<p><strong>[예제_jsp:forward]</strong></p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
이 페이지는 from.jsp가 생성한 것입니다.
&lt;jsp:forward page=&quot;to.jsp&quot; /&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
이 페이지는 to.jsp가 생성한 것입니다.
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><strong>실행 결과</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e7575740-2893-419c-b679-324fb2e73959/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[JSP #1]]></title>
            <link>https://velog.io/@jjinny_0609/JSP-1</link>
            <guid>https://velog.io/@jjinny_0609/JSP-1</guid>
            <pubDate>Mon, 20 Mar 2023 07:20:01 GMT</pubDate>
            <description><![CDATA[<h1 id="jsp">JSP</h1>
<p>JSP(JavaServer Pages)는 서버 측 웹 애플리케이션 개발을 위한 Java 기반 웹 프로그래밍 기술입니다. JSP를 사용하면 HTML, CSS 및 JavaScript와 같은 프론트 엔드 기술을 사용하여 동적인 웹 페이지를 생성할 수 있습니다.</p>
<p>JSP는 Java 코드를 HTML 문서에 삽입할 수 있는 기능을 제공합니다. 이를 통해 Java 코드를 사용하여 데이터베이스 연결, 데이터 검색, 계산 등을 수행하고 결과를 HTML 페이지에 출력할 수 있습니다. JSP를 사용하면 동적 웹 페이지를 생성하고 웹 애플리케이션의 비즈니스 로직을 처리할 수 있습니다.</p>
<p>JSP는 Servlet 컨테이너에 의해 처리됩니다. Servlet 컨테이너는 JSP 파일을 Java Servlet으로 변환하고 실행합니다. JSP 파일은 Java Servlet으로 변환되어 Java 클래스로 컴파일되며, 이 Java 클래스는 실행 시 웹 애플리케이션에서 사용됩니다.</p>
<p>JSP는 Java EE(Enterprise Edition) 플랫폼의 일부이며, Java EE 애플리케이션 서버에서 실행됩니다. JSP를 사용하여 다양한 웹 애플리케이션을 구축할 수 있으며, 대규모 애플리케이션에서도 사용할 수 있습니다.</p>
<h3 id="--jsp를-사용하기-전-준비해야할-사항">- JSP를 사용하기 전 준비해야할 사항</h3>
<p>JDK 8
TOMCAT 8
MySQL
이클립스</p>
<ul>
<li>아파치 톰켓8 설치
<img src="https://velog.velcdn.com/images/jjinny_0609/post/705d9a59-51b5-4d27-99e9-b6b46fa2a59e/image.png" alt="">
압축파일을 받아도 되고, INSTALLER 설치파일을 받아도 된다.
작성시점 다운로드한 버전은 8.5.87이다.</li>
</ul>
<p>다운받은 폴더는 압축해제해서 C의 루트폴더에 이동시켰다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f55f41c8-2645-46fe-8db9-853ed93ce25a/image.png" alt=""></p>
<p>C:\apache-tomcat-8.5.87\bin 경로에 있는 startup을 실행해보자.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/06bd837a-9313-4f5c-ab3e-ef8fecf7e85f/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/1d92071a-634b-4e17-8807-47bbad5a8ef8/image.png" alt="">
org.apache.catalina.startup.Catalina.start Server startup in 530 ms
정상적으로 나오는지 메시지를 확인하자.</p>
<p>cmd 창을 열어 cd C:\apache-tomcat-8.5.87\bin경로로 이동한뒤 catalina.bat파일을 실행해보면 정상적으로 실행된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/78b9729f-7cde-4af3-addf-55c4f9113357/image.png" alt="">
실행이 안될경우 환경변수값을 수정해주면 해결된다.</p>
<p><a href="http://localhost:8080">http://localhost:8080</a> 으로 주소를 작성해 들어가면 아래와 같이 나타난다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f0521af9-c5c7-461b-9d8a-3ae3d08fc8b7/image.png" alt=""></p>
<hr>

<h3 id="url">URL</h3>
<p>URL(Uniform Resource Locator)은 인터넷에서 리소스(웹 페이지, 이미지, 동영상 등)의 위치를 지정하는 문자열입니다. URL은 일반적으로 다음과 같은 구성 요소로 구성됩니다.</p>
<p>프로토콜(Protocol): URL의 첫 번째 요소로, 서버와 클라이언트 간 통신 방식을 지정합니다. 가장 일반적으로 사용되는 프로토콜은 HTTP(HTTP Secure), FTP, HTTPS 등이 있습니다.</p>
<p>호스트(Host): URL의 두 번째 요소로, 서버의 이름이나 IP 주소를 지정합니다. 예를 들어, <a href="http://www.example.com">www.example.com</a> 또는 192.168.0.1과 같은 형식으로 지정됩니다.</p>
<p>포트(Port): URL의 세 번째 요소로, 서버에서 클라이언트로 통신할 때 사용하는 포트 번호를 지정합니다. 대부분의 프로토콜은 기본 포트 번호를 가지고 있으며, 명시적으로 포트 번호를 지정하지 않을 경우 기본 포트 번호를 사용합니다.</p>
<p>경로(Path): URL의 네 번째 요소로, 서버에서 제공하는 리소스의 경로를 지정합니다. 경로는 디렉토리와 파일 이름을 포함할 수 있으며, URL에서 가장 중요한 요소 중 하나입니다.</p>
<p>쿼리(Query): ?는 쿼리(Query) 문자열을 시작하는 기호이고, 쿼리 문자열은 URL의 일부로, 추가적인 매개변수를 서버로 전달할 때 사용됩니다. URL의 다섯 번째 요소로, 리소스를 요청할 때 서버에 전달되는 추가적인 매개변수를 지정합니다. 쿼리는 이름-값 쌍으로 구성되며, 각 쌍은 &amp; 기호로 구분됩니다.</p>
<p>프래그먼트(Fragment): URL의 여섯 번째 요소로, 리소스 내의 특정 위치(프래그먼트)를 가리키는 식별자를 지정합니다. 프래그먼트는 주로 HTML 페이지에서 사용되며, 이동하고자 하는 섹션의 ID를 지정하는 데 사용됩니다.</p>
<p>예를 들어, </p>
<pre><code>http://www.example.com:80/path/to/file.html?id=123#section1</code></pre><p>위 주소는 HTTP 프로토콜을 사용하여 호스트가 <a href="http://www.example.com%EC%9D%B8">www.example.com인</a> 서버의 80번 포트에서 /path/to/file.html 경로의 파일에 대한 쿼리 매개변수 id=123을 전달하고, 이 파일의 section1이라는 프래그먼트를 가리킵니다.</p>
<hr>

<h3 id="서버와-클라이언트">서버와 클라이언트</h3>
<p>서버와 클라이언트 간 통신은 요청(Request)과 응답(Response) 메시지를 주고 받는 방식으로 동작합니다. 일반적으로 클라이언트는 서버로 요청을 보내고, 서버는 이 요청에 대한 응답을 생성하여 다시 클라이언트로 보내는 방식으로 동작합니다.</p>
<p>클라이언트가 서버로 요청 보내기
클라이언트는 일반적으로 웹 브라우저를 사용하여 서버에 대한 요청을 보냅니다. 이 요청은 HTTP 메시지 형식으로 작성되며, HTTP 메서드(GET, POST, PUT, DELETE 등)와 URI(Uniform Resource Identifier)를 포함합니다. 또한 요청에는 추가적인 헤더와 바디 정보를 포함할 수도 있습니다.</p>
<p>서버가 요청을 처리하고 응답 보내기
서버는 클라이언트의 요청을 받으면, 해당 요청에 대한 처리를 시작합니다. 처리 결과로 응답(Response)을 생성하여 다시 클라이언트로 보냅니다. 이 응답은 마찬가지로 HTTP 메시지 형식으로 작성되며, HTTP 상태 코드(200 OK, 404 Not Found, 500 Internal Server Error 등), 헤더와 바디 정보를 포함합니다.</p>
<p>클라이언트가 서버의 응답 처리하기
클라이언트는 서버에서 보내온 응답을 받은 후, 해당 응답을 처리합니다. 응답 바디에 포함된 데이터는 클라이언트가 요청한 리소스와 관련된 정보를 포함합니다. 일반적으로 웹 브라우저는 응답으로 받은 데이터를 렌더링하여 사용자에게 보여줍니다.</p>
<p>이러한 방식으로 서버와 클라이언트 간 통신이 이루어집니다. 클라이언트가 요청을 보내면, 서버는 이 요청을 받아 처리하고 응답을 보내는 방식으로 동작합니다. 이 요청-응답 모델은 웹 어플리케이션에서 데이터를 교환하는 데 있어서 중요한 개념 중 하나입니다.</p>
<hr>

<h3 id="response와-request">Response와 Request</h3>
<p>Response(응답)와 Request(요청)는 웹 어플리케이션에서 서버와 클라이언트 간 통신을 위해 사용되는 개념입니다.</p>
<p>Request는 클라이언트가 서버로 보내는 메시지이며, 서버에게 어떤 작업을 요청하거나, 추가 정보를 제공하거나, 리소스를 요청하는 데 사용됩니다. Request는 HTTP 메서드(GET, POST, PUT, DELETE 등)와 URI(Uniform Resource Identifier)를 포함하며, 헤더와 바디에 추가 정보를 포함할 수도 있습니다.</p>
<p>Response는 서버가 클라이언트에게 보내는 메시지이며, 클라이언트 요청에 대한 응답으로, 요청된 리소스와 추가 정보를 포함할 수 있습니다. Response는 HTTP 상태 코드(200 OK, 404 Not Found, 500 Internal Server Error 등), 헤더와 바디를 포함합니다. 헤더는 클라이언트에게 전송되는 데이터의 메타데이터(예: 컨텐트 타입, 캐시 제어 등)를 포함하며, 바디는 클라이언트에게 전송되는 실제 데이터를 포함합니다.</p>
<p>요청(Request)과 응답(Response)은 서로 반대되는 개념이지만, 동일한 HTTP 메시지 형식을 사용합니다. 따라서 클라이언트가 요청을 보내면, 서버는 이 요청에 대한 응답을 생성하여 클라이언트에게 보내는 방식으로 동작합니다. 이러한 요청-응답 모델은 웹 어플리케이션에서 데이터를 교환하는 데 있어서 중요한 개념 중 하나입니다.</p>
<hr>

<h3 id="이클립스를-이용한-개발">이클립스를 이용한 개발</h3>
<p>[window] - [Preferences] 메뉴에서 
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ecab2255-74a6-4885-ba0d-60a42d35eaf8/image.png" alt="">
type filter text에 encoding 작성 후 enter
workspace, css files,html files, jsp, xml 저눕 
기본 인코딩을 utf-8로 변경해주자
(한글깨짐 방지)</p>
<p>ADD 클릭<img src="https://velog.velcdn.com/images/jjinny_0609/post/b89e7f9d-c099-484c-8fcd-8df3b5991fb1/image.png" alt=""></p>
<p>Apache Tomcat v8.5 체크후 Next &gt;<img src="https://velog.velcdn.com/images/jjinny_0609/post/9038c30a-0648-4d1f-99fa-93cadf1ccd81/image.png" alt="">
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2c5d9a2a-41dc-4a7f-8b03-638420b10e41/image.png" alt=""></p>
<p>톰캣8의 경로가 있는 해당 버전 폴더 지정 후 finish 버튼 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4f0fcf1c-0d83-42eb-973d-b4f044bc66eb/image.png" alt=""></p>
<p>추가 완료된 모습
<img src="https://velog.velcdn.com/images/jjinny_0609/post/a4208251-2c40-4452-8b88-234d0f8917cc/image.png" alt=""></p>
<hr>

<ul>
<li>dynamic web project 생성하기</li>
</ul>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/95038da8-df11-4699-9a2b-86088f6c0fa7/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3a2db07e-92b3-4320-8371-7e81dae50e09/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/223e260e-72ec-4f15-850c-919a024acd2b/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/a109b7ba-2fc1-4d4d-8979-d8e89877a6ab/image.png" alt="">
위 순서를 거치면 Dynamic Web project가 만들어진다.</p>
<hr>

<ul>
<li>JSP 파일 만들기
WebContent 폴더에서 마우스의 오른쪽 버튼을 클릭한 뒤 [New] -&gt; [JSP File] 메뉴를 실행한다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/dfb6675e-0808-422c-bd2a-f0e91123d36e/image.png" alt="">
파일명을 작성하고 Enter
<img src="https://velog.velcdn.com/images/jjinny_0609/post/543bfeb0-5b6c-4932-b62a-9d5b727eafb9/image.png" alt=""></li>
</ul>
<p>hello.jsp라는 파일이 만들어진 모습
<img src="https://velog.velcdn.com/images/jjinny_0609/post/3f18ca09-0dce-4338-9f50-5cec14e78ba6/image.png" alt=""></p>
<hr>

<h3 id="jsp에서-문서를-생성하는-기본-코드-구조">JSP에서 문서를 생성하는 기본 코드 구조</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/c4540e7a-ae1a-480b-8b3d-2f9c2386671f/image.png" alt="">
01<del>02행 : jsp에 페이지에 대한 설정 정보
03</del>16 : html코드 및 JSP 스크립트</p>
<h3 id="jsp-페이지의-구성요소">JSP 페이지의 구성요소</h3>
<p>JSP 페이지를 구성하는 7가지 구성요소는 다음과 같습니다.</p>
<p><strong>Directive(디렉티브)</strong>
JSP 페이지의 전체적인 속성을 지정하는 역할을 합니다.
주로 page, include, taglib 디렉티브를 사용합니다.
&lt;%@ 디렉티브 %&gt; 형식으로 작성합니다.</p>
<p><strong>Declaration(선언,선언부)</strong>
JSP 페이지에서 사용할 변수와 메서드를 선언하는 역할을 합니다.
&lt;%! 선언문 %&gt; 형식으로 작성합니다.</p>
<p><strong>Scriptlet(스크립트릿)</strong>
JSP 페이지에서 실행할 Java 코드를 작성하는 역할을 합니다.
&lt;% Java 코드 %&gt; 형식으로 작성합니다.</p>
<p><strong>Expression(표현식)</strong>
JSP 페이지에서 변수나 메서드의 결과를 출력하는 역할을 합니다.
&lt;%= 변수 또는 메서드 %&gt; 형식으로 작성합니다.</p>
<p><strong>Comment(주석)</strong>
JSP 페이지에서 주석을 작성하는 역할을 합니다.
&lt;%-- 주석 내용 --%&gt; 형식으로 작성합니다.</p>
<p><strong>Action Tag(액션 태그)</strong>
JSP 페이지에서 특정 기능을 수행하기 위한 태그를 사용하는 역할을 합니다.
jsp:forward, jsp:include, jsp:useBean, jsp:setProperty 등의 태그를 사용합니다.</p>
<p><strong>Expression Language(표현 언어)</strong>
JSP 페이지에서 변수나 메서드의 값을 출력하기 위한 단축 표현식을 제공하는 역할을 합니다.
${ 변수 또는 메서드 } 형식으로 작성합니다.</p>
<p>위의 7가지 구성요소는 JSP 페이지를 작성하는 데 필수적인 구성요소입니다. 이를 조합하여 동적인 웹 페이지를 생성할 수 있습니다.</p>
<hr>

<h4 id="session과-application">Session과 Application</h4>
<p>서버 측의 데이터 저장 및 공유를 위한 객체입니다.</p>
<p><strong>Session</strong>은 클라이언트가 웹 어플리케이션에 접속한 이후, 일정 기간 동안 정보를 저장하고 관리하기 위한 객체입니다. 즉, 동일한 클라이언트가 웹 어플리케이션에 접속해 있을 때, 해당 클라이언트에 대한 정보를 저장하고 유지할 수 있습니다. 예를 들어, 로그인 기능이 있는 웹 어플리케이션에서는 로그인을 한 이후, 해당 유저 정보를 Session 객체에 저장하고 유지함으로써, 웹 어플리케이션 내에서 이 유저의 정보를 계속해서 활용할 수 있습니다.</p>
<p><strong>Application</strong>은 웹 어플리케이션 전체에서 공유하는 정보를 저장하고 관리하기 위한 객체입니다. 즉, 여러 클라이언트가 동시에 접속하더라도, 웹 어플리케이션 전체에서 동일한 정보를 공유하고 유지할 수 있습니다. 예를 들어, 웹 어플리케이션에서 자주 사용되는 데이터나 설정 정보 등을 Application 객체에 저장하고 활용함으로써, 서버 리소스를 효율적으로 관리하고 어플리케이션 전체에서 일관된 기능을 제공할 수 있습니다.
(방문자 수 처리할때)</p>
<p>Session과 Application은 JSP에서 제공하는 내장 객체이며, 사용 방법은 각각 HttpSession과 ServletContext 객체를 활용하는 것입니다. 이들 객체를 통해 Session과 Application에 데이터를 저장하거나 불러올 수 있습니다.</p>
<hr>

<h4 id="jspjava-server-pages-페이지-디렉티브">JSP(Java Server Pages) 페이지 디렉티브</h4>
<p>는 JSP 페이지의 속성을 설정하는 지시자입니다. JSP 페이지 디렉티브는 JSP 페이지 상단에 위치하며 &quot;&lt;%&quot;와 &quot;%&gt;&quot; 사이에 위치합니다.</p>
<p>JSP 페이지 디렉티브는 다음과 같은 세 가지 속성을 가질 수 있습니다.</p>
<p>page: JSP 페이지와 관련된 속성을 설정합니다. 예를 들어, JSP 페이지의 언어, 스크립트 언어, 세션 설정 등을 설정할 수 있습니다.</p>
<p>include: JSP 페이지에서 다른 JSP 페이지를 포함할 때 사용됩니다. 이 속성을 사용하면 현재 페이지에 다른 페이지를 포함할 수 있습니다.</p>
<p>taglib: 사용자 정의 태그 라이브러리를 선언합니다. 이 속성을 사용하여 JSP 페이지에서 사용할 태그를 선언할 수 있습니다.</p>
<p>아래는 JSP 페이지 디렉티브의 예입니다.</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot; %&gt;
&lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot; %&gt;
&lt;%@ include file=&quot;header.jsp&quot; %&gt;</code></pre><p>위의 예에서 첫 번째 디렉티브는 JSP 페이지의 속성을 설정합니다. 두 번째 디렉티브는 JSTL(core) 태그 라이브러리를 선언하고, 세 번째 디렉티브는 &quot;header.jsp&quot; 파일을 포함합니다.</p>
<h4 id="jspjava-server-pages-페이지-디렉티브-속성">JSP(Java Server Pages) 페이지 디렉티브 속성</h4>
<p><strong>language</strong>
JSP 페이지에서 사용할 스크립트 언어를 지정합니다.
기본값은 Java이며, JavaScript 등 다른 언어도 사용 가능합니다.
예: &lt;%@ page language=&quot;java&quot; %&gt;</p>
<p><strong>contentType</strong>
JSP 페이지가 생성하는 컨텐츠의 MIME 타입을 지정합니다.
기본값은 &quot;text/html&quot;입니다.
예: &lt;%@ page contentType=&quot;text/html;charset=UTF-8&quot; %&gt;</p>
<p><strong>session</strong>
JSP 페이지에서 세션 사용 여부를 지정합니다.
기본값은 true입니다.
예: &lt;%@ page session=&quot;false&quot; %&gt;</p>
<p><strong>buffer</strong> 
buffer는 JSP 페이지가 출력에 사용하는 버퍼 크기를 바이트 단위로 나타냅니다. 기본적으로 버퍼 크기는 8KB입니다. JSP 페이지에서 출력하는 어떤 내용이 버퍼 크기를 초과하면 자동으로 클라이언트로 플러시됩니다.</p>
<p><strong>autoFlush</strong>
autoFlush는 버퍼가 가득 찼을 때 자동으로 버퍼를 플러시할 지 여부를 결정하는 부울 속성입니다. true로 설정하면 버퍼가 가득 차면 자동으로 플러시됩니다. false로 설정하면 버퍼가 자동으로 플러시되지 않으며, 개발자가 수동으로 플러시해야 합니다.</p>
<p><strong>info</strong>
info는 개발자가 JSP 페이지에 대한 정보를 제공할 수 있도록 하는 JSP 지시자입니다. 이 정보는 JSP 컨테이너에서 페이지에 대한 문서를 생성하는 데 사용됩니다. info 지시자의 구문은 다음과 같습니다.</p>
<pre><code>&lt;%@ page info=&quot;페이지에 대한 정보&quot; %&gt;</code></pre><p><strong>import</strong>
JSP 페이지에서 사용할 클래스나 패키지를 import합니다.
여러개를 지정할 수 있으며, 쉼표(,)로 구분합니다.
예: &lt;%@ page import=&quot;java.util., com.example.&quot; %&gt;</p>
<p><strong>extends</strong>
JSP 페이지에서 사용할 클래스를 상속받습니다.
예: &lt;%@ page extends=&quot;com.example.MyClass&quot; %&gt;</p>
<p><strong>errorPage</strong>
errorPage는 처리되지 않은 예외 또는 오류 발생 시 표시할 오류 페이지를 지정할 수 있는 다른 JSP 지시자입니다. errorPage 지시자의 구문은 다음과 같습니다.</p>
<pre><code>&lt;%@ page errorPage=&quot;errorPage.jsp&quot; %&gt;</code></pre><p>위의 예에서 errorPage.jsp는 오류 발생 시 표시할 오류 페이지의 이름입니다.</p>
<p><strong>isErrorPage</strong>
JSP 페이지가 에러 페이지로 사용될 것인지를 지정합니다.
기본값은 false입니다.
예: &lt;%@ page isErrorPage=&quot;true&quot; %&gt;</p>
<p>위의 속성들은 JSP 페이지의 전반적인 속성을 설정하는 데 사용됩니다. 이 외에도 다양한 속성들이 있으며, 필요에 따라 사용할 수 있습니다.</p>
<p><strong>pageEncoding</strong>
JSP 페이지의 문자 인코딩을 지정합니다.
기본값은 &quot;ISO-8859-1&quot;입니다.
예: &lt;%@ page pageEncoding=&quot;UTF-8&quot; %&gt;</p>
<p><strong>isELIgnored</strong>
isELIgnored는 EL (표현 언어) 식을 JSP 페이지에서 평가할 지 여부를 결정하는 부울 속성입니다. true로 설정하면 EL 식은 무시되어 일반 텍스트로 처리됩니다. false로 설정하면 EL 식이 평가되고 출력이 표시됩니다.</p>
<p><strong>deferredSyntaxAllowedAsLiteral</strong>
지연 구문을 문자열 리터럴로 사용할 수 있게 해주는 부울 속성입니다. true로 설정하면 지연 구문 (즉, ${}로 묶인 식)을 문자열 리터럴로 사용할 수 있습니다. false로 설정하면 지연 구문은 문자열 리터럴로 사용될 수 없습니다.</p>
<p><strong>trimDirectiveWhitespaces</strong>
JSP 지시자에서 공백 문자를 제거할 지 여부를 결정하는 부울 속성입니다. true로 설정하면 선행 및 후행 공백 문자가 JSP 지시자에서 제거됩니다. false로 설정하면 공백 문자가 보존됩니다.</p>
<hr>

<h3 id="예제-작성한걸-실행시켜보기">예제 작성한걸 실행시켜보기</h3>
<p>하단 탭에 servers 
안보인다면 Window-ShowView-other-Servers 검색해서 open
<img src="https://velog.velcdn.com/images/jjinny_0609/post/3ea1b1c5-c214-4602-84fb-bfb6f8f0097c/image.png" alt=""></p>
<p>servers 탭에 파란색 링크 클릭
<img src="https://velog.velcdn.com/images/jjinny_0609/post/316b3aa3-a50c-4f79-aa08-49c3d404a542/image.png" alt=""></p>
<p>내가 만든 폴더가 있다 이걸 오른쪽으로 시켜야한다. add눌러 이동시켜주자
<img src="https://velog.velcdn.com/images/jjinny_0609/post/d4138bf3-7db8-4435-a43b-9524f66250ed/image.png" alt=""></p>
<p>Finish
<img src="https://velog.velcdn.com/images/jjinny_0609/post/dbfd464b-a13c-4c1c-a1e7-831d34c1f1cd/image.png" alt=""></p>
<p>Run As를 눌러 실행
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2ef55c9f-3868-40d1-9040-1f71f6188c2d/image.png" alt=""></p>
<p>오류가 발생
<img src="https://velog.velcdn.com/images/jjinny_0609/post/72d02387-f32a-4951-bc8a-4e63ab645af8/image.png" alt=""></p>
<pre><code>Port 8081 required by Tomcat v8.5 Server at localhost is already in use. The server may already be running in another process, or a system process may be using the port. To start this server you will need to stop the other process or change the port number(s).
</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/b72b2b17-39ef-4d89-bb92-f34ea85c8d8c/image.png" alt="">
여기서 포트번호 안겹치게 변경해주고 저장해주자</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/73f14fb3-734c-4401-9927-86a3cc3fe150/image.png" alt=""></p>
<p>그럼 정상적으로 실행되는 모습
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c9505335-a30d-4a55-9bf0-de46fe35fcd1/image.png" alt=""></p>
<hr>

<h3 id="인코딩의-중요성">인코딩의 중요성</h3>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/42f53c21-056c-4c1b-96c6-90d85e1f643b/image.png" alt="">
utf-8을 iso8859-1로 바꿔보았다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f533797a-f110-400d-898d-2b436d725b79/image.png" alt="">
분명 현재시각을 입력했는데 한글이 깨져서나옴..
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2beaebb8-d4a2-4fc1-abdf-31012c6103bd/image.png" alt="">
utf-8로 바꿔주면 정상 실행되는 모습.</p>
<hr>

<h3 id="스크립트-요소">스크립트 요소</h3>
<p>스크립트릿 요소</p>
<ul>
<li>스크립트릿(Scriptlet) : &lt;%   %&gt;</li>
<li>표현식(Expression) : &lt;%= 값 %&gt;</li>
<li>선언부(Declaration) : &lt;%!   %&gt;</li>
</ul>
<h4 id="스크립트릿-사용-예제">스크립트릿 사용 예제</h4>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;1~10까지의 합&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;%
    int sum = 0;
    for(int i = 1; i&lt;=10; i++){
        sum = sum + i;
    }
%&gt;
1부터 10까지의 합은 &lt;%= sum %&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/7228af25-89cf-4aaf-baff-f594c7efd064/image.png" alt=""></p>
<hr>

<h4 id="스크립트릿-사용-예제2-선언부">스크립트릿 사용 예제2 (선언부)</h4>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%!
    public int multiply(int a, int b){
    int c = a*b;
    return c;
}
%&gt;    
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;선언부를 사용한 두 정수값의 곱&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
10 * 25 =&lt;%= multiply(10,25) %&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/032676eb-5065-4c57-b0ed-a17cbfa4479a/image.png" alt="">
<img src="https://velog.velcdn.com/images/jjinny_0609/post/6f99e468-81f6-4149-9c38-54c7c7d044b4/image.png" alt="">
3행부터 8행까지가 선언부이다.
16행이 선언부에서 정의한 multiply를 메서드를 호출(Call)한 결과값을 표현식을 사용하여 출력한다.</p>
<hr>

<h3 id="request-기본객체">request 기본객체</h3>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;

uri &lt;%=request.getRequestURI() %&gt;&lt;br&gt;
컨테스트 경로 &lt;%=request.getContextPath() %&gt;&lt;br&gt;
서버이름 &lt;%=request.getServerName() %&gt;&lt;br&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/4f2687a7-b5f0-4625-a17e-95292ac5dfc7/image.png" alt=""></p>
<p>본인의 컨텍스트의 경로를 확인
<img src="https://velog.velcdn.com/images/jjinny_0609/post/3fe32129-0755-4827-987e-07f2ab480c31/image.png" alt=""></p>
<p>경로를 수정하고 다시 실행시켜보자
<img src="https://velog.velcdn.com/images/jjinny_0609/post/9fc28437-0e80-43e5-a831-b4850e6eb453/image.png" alt=""></p>
<p>경로를 /로 변경시키니 나타나지 않는다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2d227fd8-17be-48ec-a97d-a3b8e51782f3/image.png" alt=""></p>
<hr>

<h3 id="요청-파라미터-처리">요청 파라미터 처리</h3>
<p>JSP 요청 파라미터는 클라이언트가 서버로 보내는 데이터입니다. 이 데이터는 HTML 폼(form) 요소나 AJAX 요청 등을 통해 전송됩니다. JSP에서는 요청 파라미터를 처리하기 위해 request 객체를 사용합니다.</p>
<p>request 객체는 JSP에서 기본적으로 제공되는 내장 객체 중 하나이며, 클라이언트의 요청과 관련된 정보를 제공합니다. request.getParameter() 메서드를 사용하여 요청 파라미터를 얻을 수 있습니다. 이 메서드는 파라미터 이름을 매개변수로 받아 해당하는 파라미터의 값을 문자열로 반환합니다.</p>
<p>예를 들어, name이라는 파라미터 이름으로 전송된 값에 접근하려면 다음과 같이 코드를 작성할 수 있습니다.</p>
<pre><code>&lt;%
String name = request.getParameter(&quot;name&quot;);
%&gt;</code></pre><p>이제 name 변수에는 name이라는 파라미터 이름으로 전송된 값이 저장됩니다. 이 값을 사용하여 동적인 웹 페이지를 생성할 수 있습니다.</p>
<p><strong>[예제_request 기본객체와 파라미터]</strong>
(사용자를 위한 폼)</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;form action=&quot;viewParameter.jsp&quot; method=&quot;post&quot;&gt;
        이름 : &lt;input type=&quot;text&quot; name = &quot;name&quot; size=&quot;10&quot;&gt;&lt;br&gt;
        주소 : &lt;input type=&quot;text&quot; name = &quot;address&quot; size=&quot;30&quot;&gt;&lt;br&gt;
        좋아하는 동물 : 
        &lt;input type=&quot;checkbox&quot; name=&quot;pet&quot; value=&quot;dog&quot;&gt;강아지
        &lt;input type=&quot;checkbox&quot; name=&quot;pet&quot; value=&quot;cat&quot;&gt;고양이
        &lt;input type=&quot;checkbox&quot; name=&quot;pet&quot; value=&quot;pig&quot;&gt;돼지&lt;br&gt;
        &lt;input type=&quot;submit&quot; value=&quot;전송&quot;&gt;
    &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/c29f85d6-453c-41b8-b7ee-bdf29de1c6c6/image.png" alt=""></p>
<p>(서버)</p>
<pre><code>&lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&gt;
&lt;%@ page import=&quot;java.util.Enumeration&quot; %&gt;
&lt;%@ page import=&quot;java.util.Map&quot; %&gt;
&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
&lt;meta charset=&quot;UTF-8&quot;&gt;
&lt;title&gt;Insert title here&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
name 파라미터 = &lt;%= request.getParameter(&quot;name&quot;) %&gt; &lt;br&gt;
address 파라미터 = &lt;%= request.getParameter(&quot;address&quot;) %&gt; &lt;br&gt;
&lt;b&gt;request.getParameter() 메서드 사용&lt;/b&gt;&lt;br&gt;
&lt;%
    String[] values = request.getParameterValues(&quot;pet&quot;);
    if(values != null){    
        for(int i = 0; i &lt; values.length; i++){
%&gt;
    &lt;%= values[i] %&gt;
&lt;%
        }
    }
%&gt;
&lt;p&gt;
&lt;b&gt;request.getParameterNames() 메서드 사용&lt;/b&gt;&lt;br&gt;
&lt;%
    Enumeration paramEnum = request.getParameterNames();
    while(paramEnum.hasMoreElements()){
        String name= (String)paramEnum.nextElement();
%&gt;
    &lt;%= name %&gt;
&lt;%
    }
%&gt;
&lt;p&gt;
&lt;b&gt;request.getParameterMap() 메서드 사용&lt;/b&gt;&lt;br&gt;
&lt;%
    Map parameterMap = request.getParameterMap();
    String[] nameParam = (String[])parameterMap.get(&quot;name&quot;);
    if(nameParam != null){
%&gt;        
name = &lt;%= nameParam[0] %&gt;
&lt;%
    }
%&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/e6833dcd-0e88-433d-89a3-0a169761074e/image.png" alt=""></p>
<p>아래 코드는 메서드 방식이 post 일때 
한글 깨짐방지를 위해 작성되는 코드입니다.</p>
<pre><code>name 파라미터 = &lt;%= request.getParameter(&quot;name&quot;) %&gt; &lt;br&gt;
address 파라미터 = &lt;%= request.getParameter(&quot;address&quot;) %&gt; &lt;br&gt;</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[(SQL 첫걸음) 데이터 베이스 #7]]></title>
            <link>https://velog.io/@jjinny_0609/SQL-%EC%B2%AB%EA%B1%B8%EC%9D%8C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B2%A0%EC%9D%B4%EC%8A%A4-7</link>
            <guid>https://velog.io/@jjinny_0609/SQL-%EC%B2%AB%EA%B1%B8%EC%9D%8C-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%B2%A0%EC%9D%B4%EC%8A%A4-7</guid>
            <pubDate>Fri, 17 Mar 2023 06:37:31 GMT</pubDate>
            <description><![CDATA[<h2 id="복수의-테이블-다루기">복수의 테이블 다루기</h2>
<h3 id="집합연산">집합연산</h3>
<ul>
<li>관계형 모델 : RDBMS의 창시자인 에드거 커드(Edgar F.Codd)가 고안한 모델이다.
데이터를 표 형태의 테이블로 표현하고, 각 테이블은 열(column)과 행(row)으로 이루어져 있습니다. 각 열은 데이터의 속성(attribute)을 나타내고, 각 행은 데이터의 인스턴스(instance)를 나타냅니다.</li>
</ul>
<h3 id="union으로-합집합-구하기">Union으로 합집합 구하기</h3>
<p>UNION 연산자는 두 개 이상의 SELECT 문의 결과를 결합하여 하나의 결과 집합으로 만들어줍니다. 각 SELECT 문은 같은 열 수와 데이터 형식을 가져야합니다.</p>
<p>UNION 연산자는 중복된 행을 제거하며, UNION ALL 연산자를 사용하면 중복된 행을 제거하지 않습니다.</p>
<p>또한, UNION 연산자는 각 SELECT 문에서 검색하는 열의 수와 데이터 형식이 동일해야하므로 동일한 수의 열을 반환하지 않는 SELECT 문을 결합할 수 없습니다. 이 경우 UNION ALL을 사용하여 결과 집합에 중복된 행을 포함시킬 수 있습니다.</p>
<p><strong>sample71_a</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/20415bcd-a240-4a2d-9927-d538109a50e5/image.png" alt="">
<strong>sample71_b</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/dea59040-3bd7-4f2d-962b-d3ab61d9bb4d/image.png" alt=""></p>
<pre><code>select * from sample71_a
union
select * from sample71_b;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3a035cd4-88c0-4f3b-89ae-e931cb3f6abd/image.png" alt=""></p>
<h4 id="열의-수가-맞지-않을때">열의 수가 맞지 않을때</h4>
<p>위의 예제에 sample31을 넣으려고한다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f01bd1d7-fc0c-42ff-b1bb-4add37ae7159/image.png" alt=""></p>
<pre><code>SELECT * FROM sample71_a
UNION
SELECT * FROM sample71_b
union
SELECT * FROM sample31;</code></pre><p>열의 수가 맞지않아서 오류가 발생한다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/484a01b8-e0c7-4eb9-97d5-ae255ed45e16/image.png" alt=""></p>
<p>아래와 같이 수정후 실행해보면</p>
<pre><code>SELECT * FROM sample71_a
UNION
SELECT * FROM sample71_b
union
SELECT name FROM sample31;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/96207d0f-fb01-4db3-a739-132a51257e03/image.png" alt="">
name의 값만 받아와서 실행하기 때문에 문제없이 실행되는 모습을 볼 수있다.</p>
<hr>

<h3 id="union-all">UNION ALL</h3>
<p>UNION ALL 연산자를 사용하면 중복된 행을 제거하지 않습니다.</p>
<pre><code>SELECT * FROM sample71_a
UNION ALL
SELECT * FROM sample71_b;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/53d2e698-277b-44bf-af17-a014c0591c17/image.png" alt=""></p>
<hr>

<h3 id="교집합과-차집합">교집합과 차집합</h3>
<h4 id="교집합">교집합</h4>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/bbe1cd93-89d3-44b2-85b9-1b35f62287e5/image.png" alt="">
<strong>SQL에서의 교집합</strong>
두 개 이상의 SELECT 문의 결과에서 공통된 행만 반환하는 연산자입니다. 각 SELECT 문은 같은 열 수와 데이터 형식을 가져야합니다.</p>
<p><strong>INTERSECT</strong> 연산자를 사용하여 두 개의 테이블에서 공통된 데이터를 찾는 예제를 살펴보겠습니다.</p>
<pre><code>SELECT column1, column2, column3
FROM table1
INTERSECT
SELECT column1, column2, column3
FROM table2;</code></pre><hr>

<h4 id="차집합">차집합</h4>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/62ef11ee-ef8b-4bfa-af3e-4fcf996e75d3/image.png" alt="">
<strong>SQL에서의 차집합</strong>
<strong>EXCEPT</strong> 또는 <strong>MINUS</strong>(Oracle의 경우) 연산자는 두 개 이상의 SELECT 문의 결과에서 첫 번째 SELECT 문의 결과에만 포함되는 행을 반환하는 연산자입니다. 각 SELECT 문은 같은 열 수와 데이터 형식을 가져야합니다.</p>
<p>EXCEPT 또는 MINUS 연산자를 사용하여 두 개의 테이블에서 첫 번째 SELECT 문의 결과에만 포함되는 데이터를 찾는 예제를 살펴보겠습니다.</p>
<pre><code>SELECT column1, column2, column3
FROM table1
EXCEPT
SELECT column1, column2, column3
FROM table2;</code></pre><p>이 쿼리는 table1의 column1, column2, column3에 해당하는 결과 중 table2의 column1, column2, column3에 해당하는 결과를 제외한 결과를 반환합니다.</p>
<p>EXCEPT 연산자는 첫 번째 SELECT 문의 결과에서 두 번째 SELECT 문의 결과에 있는 행을 제거합니다. 따라서 결과 집합은 첫 번째 SELECT 문에서 반환되는 행 중 두 번째 SELECT 문에서 반환되는 행이 없는 행만 포함합니다.</p>
<hr>

<h2 id="테이블-결합">테이블 결합</h2>
<p>테이블 결합(Table Join)은 SQL에서 두 개 이상의 테이블에서 데이터를 가져와 결합하여 새로운 결과 집합을 만드는 작업입니다. 테이블 결합은 데이터베이스에서 데이터를 검색하고 분석하는 데 필수적인 기술 중 하나입니다.</p>
<p>일반적으로 테이블 결합은 JOIN 키워드를 사용하여 수행됩니다. JOIN 키워드는 INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN 등 다양한 유형의 결합을 수행할 수 있습니다.</p>
<hr>

<h3 id="곱집합과-교차결합">곱집합과 교차결합</h3>
<p>곱집합(Cartesian Product)은 두 개 이상의 집합에서 가능한 모든 조합을 구하는 것입니다. SQL에서는 교차결합(CROSS JOIN)을 사용하여 두 개 이상의 테이블의 모든 조합을 만들 수 있습니다.</p>
<pre><code>SELECT *
FROM products
CROSS JOIN colors;</code></pre><p>위의 쿼리는 products 테이블과 colors 테이블의 모든 행 조합을 반환합니다. 결과 집합은 products 테이블의 행 수와 colors 테이블의 행 수를 곱한 크기를 가지며, 각 조합은 products와 colors의 모든 열을 포함합니다.</p>
<p>교차결합(CROSS JOIN)은 두 개 이상의 테이블에서도 사용할 수 있으며, 가능한 모든 행 조합을 반환합니다. 하지만 CROSS JOIN은 성능상의 이유로 가능한 사용을 피해야 합니다. 따라서 가능한 경우, 조인 키워드(예: INNER JOIN, LEFT JOIN)를 사용하여 테이블을 결합하는 것이 좋습니다.</p>
<p><em><strong>Syntax</strong></em> 교차결합(Cross Join)
SELECT * FROM 테이블명1, 테이블명2
<strong>[sample72_x]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/e555f5c0-e358-4bdd-ae94-cfae046ae088/image.png" alt="">
<strong>[sample72_y]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c3a0bd72-d0f9-45bf-a75a-3fc8ef0a1365/image.png" alt=""></p>
<p><strong>[예제_FROM구에 테이블 두개를 지정해 곱집합 구하기]</strong></p>
<pre><code>select * from sample72_x, sample72_y;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/f7fc672e-ea9e-4052-835a-56ff9d4444f8/image.png" alt=""></p>
<blockquote>
<p>FROM 구에 복수의 테이블을 지정하면 교차결합을 한다.</p>
</blockquote>
<hr>

<h4 id="--union-연결과-결합-연결의-차이">- UNION 연결과 결합 연결의 차이</h4>
<p><strong>UNION 연결</strong>: UNION 연산자는 두 개 이상의 SELECT 문의 결과를 연결하여 하나의 결과 집합으로 만드는 것입니다. 단, 각 SELECT 문의 결과 집합은 동일한 열 수를 가져야 하며, 결과 집합에 중복된 행이 없어야 합니다. 예를 들어, 아래와 같이 두 개의 SELECT 문을 UNION 연산자로 연결하여 하나의 결과 집합으로 만들 수 있습니다.</p>
<pre><code>SELECT column1, column2
FROM table1
UNION
SELECT column1, column2
FROM table2;</code></pre><p><em>위의 쿼리는 table1과 table2에서 column1과 column2를 선택하고, 두 결과 집합을 UNION 연산자로 결합하여 중복된 행을 제거한 후 하나의 결과 집합으로 반환합니다.</em></p>
<p><strong>결합 연결</strong>: 결합 연결은 두 개 이상의 테이블에서 데이터를 결합하여 새로운 결과 집합을 만드는 것입니다. 이 때, 결합 연산에는 JOIN 키워드를 사용합니다. JOIN 키워드는 INNER JOIN, LEFT JOIN, RIGHT JOIN, FULL OUTER JOIN 등 다양한 유형의 결합을 수행할 수 있습니다. 예를 들어, 아래와 같이 INNER JOIN으로 두 개의 테이블을 결합할 수 있습니다.</p>
<pre><code>SELECT *
FROM table1
INNER JOIN table2
ON table1.column = table2.column;
</code></pre><p><em>위의 쿼리는 table1과 table2에서 column 값이 일치하는 행을 INNER JOIN으로 결합하여 하나의 결과 집합으로 반환합니다.</em></p>
<blockquote>
<p>따라서, UNION 연결은 SELECT 문의 결과를 결합하는 것이고, 결합 연결은 테이블에서 데이터를 결합하는 것입니다.</p>
</blockquote>
<hr>

<h3 id="내부결합">내부결합</h3>
<p>내부결합(Inner Join)은 두 개 이상의 테이블에서 데이터를 결합하여 새로운 결과 집합을 생성하는 데 사용되는 조인 유형 중 하나입니다.</p>
<p>내부결합은 JOIN 키워드와 ON 절을 사용하여 수행됩니다. ON 절은 결합할 테이블 간의 조인 조건을 지정합니다. INNER JOIN은 ON 절에서 정의한 조인 조건을 만족하는 두 테이블의 공통 열 값을 기준으로 데이터를 결합합니다.</p>
<p>예를 들어, customers와 orders라는 두 개의 테이블이 있다면, customers와 orders를 공통된 customer_id 열을 기준으로 INNER JOIN 할 수 있습니다.</p>
<pre><code>SELECT *
FROM customers
INNER JOIN orders
ON customers.customer_id = orders.customer_id;</code></pre><p><em>위의 쿼리는 customers와 orders 테이블에서 customer_id 열의 값이 일치하는 모든 행을 INNER JOIN하여 하나의 결과 집합으로 반환합니다.</em></p>
<p>내부결합은 두 테이블에서 공통 열 값을 가진 행만을 결합하기 때문에, 결과 집합은 JOIN하는 두 테이블의 교집합이 됩니다. 따라서, INNER JOIN을 사용하여 두 테이블을 결합하면, JOIN하는 두 테이블에서 공통된 데이터만을 결과로 얻을 수 있습니다.</p>
<p><strong>[내부결합 예제]</strong>
select * from 상품;
select * from 재고수;
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ab38f86e-84ef-4d6f-b313-795f0ea7673f/image.png" alt=""></p>
<pre><code>select *
from 상품, 재고수
where 상품.상품코드 = 재고수.상품코드;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/4988a4aa-5e30-4003-bc3e-97029167792e/image.png" alt="">
위의 SQL 쿼리는 두 개의 테이블인 상품과 재고수를 INNER JOIN하여 상품코드에 대한 정보를 함께 조회하는 것을 의미합니다.</p>
<p>쿼리에서 사용된 WHERE 절에서는 INNER JOIN에 사용되는 조인 조건을 지정합니다. 즉, 상품 테이블과 재고수 테이블을 INNER JOIN하는데, 상품코드 열이 일치하는 경우에만 두 테이블의 행을 결합하고, 이에 해당하지 않는 경우에는 결과 집합에서 제외됩니다.</p>
<p>쿼리의 실행 결과는 상품과 재고수 테이블에서 상품코드 열이 일치하는 모든 행을 결합하여 반환하므로, 두 테이블에서 공통된 데이터만을 결과로 얻게 됩니다. 결과 집합에는 상품과 재고수의 모든 열에 대한 정보가 함께 포함되어 있습니다.</p>
<h3 id="inner-join으로-내부결합하기">INNER JOIN으로 내부결합하기</h3>
<p><em>일반 내부 결합</em></p>
<pre><code>-- 내부결합(from절에 두 테이블을 콤마로 연결)
select 상품명, 재고수
from 상품, 재고수
where 상품.상품코드 = 재고수.상품코드
;</code></pre><p><strong>INNER JOIN :</strong> 두 개의 테이블에서 조건을 만족하는 행을 반환합니다. 즉, 교집합을 구하는 것과 같습니다.</p>
<p><em>INNER JOIN을 이용한 내부결합</em></p>
<pre><code>-- 내부결합(inner join 키워드를 이용, 이때 innser는 생략할 수 있음.)
select 상품명, 재고수
-- from 상품 inner join 재고수
from 상품 join 재고수
on 상품.상품코드 = 재고수.상품코드
;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/72a40760-6c25-4292-abe3-f82c0616c309/image.png" alt=""></p>
<p>두개의 코드 모두 결과는 같다.</p>
<hr>

<p><strong>[예제2]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/18972e1a-5688-4dff-b89e-1e59bbc7e1a9/image.png" alt=""></p>
<p><strong>[예제2.1_중복행 처리]</strong>
아래와 같이 작성하면 오류가 발생한다.</p>
<pre><code>select 상품명, 메이커명, 메이커코드
from 상품2, 메이커
where 상품2.메이커코드 = 메이커.메이커코드
;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/ecfd1257-cf5d-4506-9c8a-0f8b7ced7554/image.png" alt=""></p>
<p><strong>ambiguous</strong> : 모호한
상품2와 메이커 테이블에 메이커코드가 둘다 가지고 있기때문에 어떤 값을 출력할지 애매하다는 것이다.</p>
<p>아래와 같이 별칭을 주어서 구분할 수 있도록 해주자.</p>
<pre><code>select 상품명, 메이커명, S.메이커코드
from 상품2 S, 메이커 M
where S.메이커코드 = M.메이커코드
;
-- &#39;위 코드나 아래 코드나 결과는 같음&#39;
select 상품명, 메이커명, S.메이커코드
from S inner join 메이커 M
on S.메이커코드 = M.메이커코드
;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3d8740f7-1cb7-4d69-9bd4-257d40fb8bec/image.png" alt="">
그럼 정상적으로 실행이 된다.</p>
<p><strong>[예제2.2_메이커코드로 분류]</strong></p>
<pre><code>select 상품명, 메이커명, S.메이커코드
from 상품2 S, 메이커 M
where S.메이커코드 = M.메이커코드
and S.메이커코드 = &#39;M001&#39;
;
-- &#39;위 코드나 아래 코드나 결과는 같음&#39;
select 상품명, 메이커명, S.메이커코드
from S inner join 메이커 M
on S.메이커코드 = M.메이커코드
WHERE S.메이커코드 = &#39;M001&#39;
;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/8b2e900e-09ec-45f9-b0d3-b2b946a21335/image.png" alt="">
메이커코드 &#39;M001&#39;인 것만 분류해 출력한 결과이다.</p>
<hr>

<h3 id="외부결합">외부결합</h3>
<p>외부결합(Outer Join)은 두 개 이상의 테이블에서 데이터를 결합하여 새로운 결과 집합을 생성하는 방법 중 하나입니다. 외부결합은 INNER JOIN과 마찬가지로 JOIN의 한 유형이며, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOIN 등 다양한 종류가 있습니다.</p>
<p>외부결합은 INNER JOIN과 달리 조인 조건에 부합하지 않는 데이터도 결과 집합에 포함시키는 특징이 있습니다. 이는 조인하고자 하는 두 테이블에서 공통된 데이터가 아닌 경우에도 모든 데이터를 결과에 포함시키기 위해 사용됩니다.</p>
<p>LEFT OUTER JOIN: 왼쪽 테이블의 모든 행과, 오른쪽 테이블에서 조인 조건에 부합하는 데이터를 함께 결과 집합으로 반환하며, 오른쪽 테이블에서 조인 조건에 부합하지 않는 데이터는 NULL 값으로 채워진다.
RIGHT OUTER JOIN: 오른쪽 테이블의 모든 행과, 왼쪽 테이블에서 조인 조건에 부합하는 데이터를 함께 결과 집합으로 반환하며, 왼쪽 테이블에서 조인 조건에 부합하지 않는 데이터는 NULL 값으로 채워진다.
FULL OUTER JOIN: 왼쪽, 오른쪽 테이블의 모든 행을 함께 결과 집합으로 반환하며, 일치하지 않는 행은 NULL 값으로 채워진다.</p>
<p>외부결합은 두 개 이상의 테이블에서 데이터를 쿼리할 때, 특히 특정 테이블에서 해당하는 데이터가 없는 경우에도 모든 데이터를 결과에 포함시켜야 할 때 많이 사용됩니다.</p>
<p><strong>[외부결합 예제]</strong>
<img src="https://velog.velcdn.com/images/jjinny_0609/post/bd174d16-b42a-4820-bff6-fb2dd2d863ce/image.png" alt=""></p>
<pre><code>select 상품3.상품명, 재고수.재고수
-- from 상품3 left join 재고수
from 재고수, 상품3
on 상품3.상품코드 = 재고수.상품코드(+) -- left join(Oracle)
;</code></pre><hr>

<p><strong>[네이버 로그인,자유게시판 데이터를 저장하는 테이블 만드는 예제]</strong></p>
<pre><code>create database naver_1;
use naver_1;

create table member
(
    id varchar(30) primary key,
    pswd varchar(30) NOT NULL,
    name varchar(30) NOT NULL,
    birth date NOT NULL,    -- varchar해도 상관은없다 다만 2월에 30일을 입력했을때 insert 될 수있어서 따로 조건설정을 해줘야함.
    -- 생일을 3개로 나누어서 해도 되지않느냐? -&gt; 자바스크립트에서 concat을 이용해서 문자열을 결합시켜서 하나로 만들어도 됨.
    gender varchar(5) NOT NULL,
    email varchar(30), 
    phonenum varchar(20) NOT NULL
);

create table board
(
    no int primary key auto_increment,
    title varchar(30) NOT NULL,        -- 제목
    content varchar(20) NOT NULL,    -- 내용
    categori varchar(30) NOT NULL,
    id varchar(10),
    tag varchar(500),
    regdate datetime default now(),    -- 날짜값을 넣지않으면 기본값인 오늘 날짜가 들어간다는 뜻
    count int,    -- 조회수 insert 안했을때 0이 들어가고 제목을 클릭하면 count에 저장된 값에 대해 1씩 증가(update해주어야한다)
    good int,   -- 좋아요도 마찬가지로 insert 안했을때 0이 들어가고 좋아요 버튼을 클릭하면 good에 저장된 값에 대해 1씩 증가(update해주어야한다)
    -- member 테이블의 id열이 부모열, board 테이블의 id열이 자식열
    foreign key(id) references member(id)
);
-- table만들때 못적었으면 아래와 같이 작성
-- alter table board add constraint foreign key(m_id) references member(m_id);</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/72886cfc-d1c0-4470-9c32-7611e0b397df/image.png" alt="">
이런식으로 값을 입력한 것을 회원가입을 누르면 값이 저장되도록 만들어 주어야한다.</p>
<hr>

<p>desc 로 확인해보면 member에서 id는 기본키
<img src="https://velog.velcdn.com/images/jjinny_0609/post/2b65b217-7494-4397-be54-a17c39c0c921/image.png" alt="">
desc로 board도 확인해보면 id에 외래키로 지정된 것을 확인할 수 있다.</p>
<hr>

<pre><code>insert into board(title,categori, content, id) 
values(&#39;안녕하세요.&#39;, &#39;자유게시판&#39;,&#39;오늘 정모 있습니다.&#39;,&#39;bbb&#39;);</code></pre><p>member에 id가 존재하지 않는 id로 입력해서 기본키인 아이디값이 맞지않아서 오류가 발생한다.
(기본키에 들어간 값과 외래키 설정을 확인)
<img src="https://velog.velcdn.com/images/jjinny_0609/post/90dd33c9-d4ef-4adf-b061-1fc9ed76dab3/image.png" alt=""></p>
<hr>

<pre><code>insert into board(title,categori, content, id) 
values(&#39;안녕하세요.&#39;, &#39;자유게시판&#39;,&#39;오늘 정모 있습니다.&#39;,&#39;zzzz&#39;);</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/a88165eb-c524-4333-b285-59d50a2043ba/image.png" alt=""></p>
<hr>

<h2 id="데이터베이스-설계">데이터베이스 설계</h2>
<p><strong>- DB설계/DB구현</strong>
테이블 명세서 : 데이터베이스에서 사용되는 테이블의 구조와 속성을 정의하는 문서입니다. 이 문서는 데이터베이스 개발자나 데이터베이스 관리자가 테이블을 생성하고 관리하는 데 사용됩니다.</p>
<p>SQL 테이블 명세서는 일반적으로 다음과 같은 정보를 포함합니다.</p>
<ol>
<li>테이블 이름</li>
<li>테이블이 사용할 데이터베이스 이름</li>
<li>각 열(column)의 이름</li>
<li>각 열의 데이터 타입(data type)</li>
<li>각 열의 크기(size)</li>
<li>각 열이 NULL 값을 허용하는지 여부</li>
<li>각 열이 기본값(default)을 가지는지 여부</li>
<li>각 열이 Primary Key, Foreign Key, Unique Key 등의 제약 조건을 가지는지 여부</li>
</ol>
<p>SQL 테이블 명세서는 데이터베이스 스키마 설계 및 변경, 데이터베이스 구성 관리 등에 사용됩니다.</p>
<h3 id="erd-diagram">ERD Diagram</h3>
<p><strong>실선</strong>(identifying) : 부모 테이블의 기본키(pk)가 되는 경우
부모가 있어야 자식이 생기는 경우</p>
<p><strong>점선</strong>(NON-identifying) : 부모 테이블의 기본키(pk)가 자식 테이블(fk)가 되는 경우
자식 테이블(fk)의 일반속성이 되는 경우</p>
<p><strong>기호의 종류(도형 혹은 식별자)</strong>
｜: 1개 / 실선은(dash) ‘1&#39;을 나타낸다.</p>
<p>∈: 여러개 / 까마귀 발(crow’s foot or Many)은 ‘다수&#39; 혹은 &#39;그 이상&#39;을 나타낸다.</p>
<p>○: 0개 / 고리(ring or Optional)은 ‘0&#39;을 나타낸다.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/49945f0d-9376-4f56-8b02-7106b68b1d44/image.png" alt="">
Type1(실선과 실선): 정확히 1 (하나의 A는 하나의 B로 이어져 있다.)
Type2(까마귀발): 여러개 (하나의 A는 여러개의 B로 구성되어 있다.)
Type3(실선과 까마귀발): 1개 이상 (하나의 A는 하나 이상의 B로 구성되어 있다.)
Type4(고리와 실선): 0 혹은 1 (하나의 A는 하나 이하의 B로 구성되어 있다.)
Type5(고리와 까마귀발): 0개 이상 (하나의 A는 0또는 하나 이상의 B로 구성되 있다.)</p>
<hr>
**[ERD 예제]**

<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/221422c0-2beb-4993-aff4-cee8fa4f2402/image.png" alt=""></p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/47c51e93-66b5-4ce3-af15-3c3be7103176/image.png" alt="">는 1을 뜻하기 때문에 &#39;하나의 학생&#39;</p>
<p>수강내역 테이블의 
<img src="https://velog.velcdn.com/images/jjinny_0609/post/eedc10ab-6533-4a68-9144-da1ad89873ce/image.png" alt=""> 는 0<del>N을 뜻하기 때문에 &#39;0</del>N 개의 수강내역&#39;을 뜻한다.
수강내역의 입장에서는 &#39;0~N 개의 수강내역은 하나의 학생에게 포함되어 진다&#39;라고 해석이 가능하다.</p>
<p>위 내용을 바탕으로 유추해 본다면 ERD의</p>
<ul>
<li>부모 테이블은 학생 테이블이다.</li>
<li>자식 테이블은 수강내역 테이블이다.</li>
<li>부모 테이블의 PK를 자식 테이블에서 PK로 사용하고 있다.</li>
<li>학생 한 명은 0~N 개의 수강내역을 가진다.</li>
<li>수강내역은 하나의 학생을 가진다.</li>
<li>수강내역 테이블은 학생 테이블의 PK인 [ 학생ID ]를 FK로 가진다.</li>
</ul>
<p>[Mysql에서 ERD 다이어그램 생성하기]
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c422c39c-ccce-4670-9417-aba29bf97acf/image.png" alt="">
next 몇번 누르고 본인이 작업할 데이터베이스 영역을 체크해주고 넘기다보면 아래와 같은 화면이 나타난다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4230d1fa-2d9f-4673-aea5-357dbe53a373/image.png" alt="">
<img src="https://velog.velcdn.com/images/jjinny_0609/post/1ff19217-7bdc-4f69-84dc-c093414897c6/image.png" alt="">
관계설정을 위해 아이콘을 눌러 해당 테이블에 클릭해서 이어주면 관계 생성이 된다.
(多쪽 먼저 클릭하고 1쪽 클릭.)</p>
<ul>
<li>IE표기법과 Barker표기법
<img src="https://velog.velcdn.com/images/jjinny_0609/post/4409b37f-e13b-4775-86a5-7e1f749f8200/image.png" alt=""></li>
</ul>
<hr>

<h3 id="정규화">정규화</h3>
<p>정규화 : 데이터베이스 설계 시 중복 데이터를 제거하고 데이터를 더욱 효율적으로 저장하기 위한 기법입니다. 데이터베이스 정규화는 데이터 중복을 줄이면서 데이터 일관성을 유지하기 위해 테이블을 분해하는 과정입니다. 정규화는 보통 1차 정규화부터 5차 정규화까지 총 5단계로 이루어집니다.</p>
<p>1차 정규화: 테이블의 컬럼이 원자적인 값을 가지도록 테이블을 분해합니다. 이 과정에서 테이블은 중복된 데이터를 가지지 않게 됩니다.</p>
<p>2차 정규화: 테이블에 기본키를 정의하고, 모든 컬럼이 기본키에 종속되도록 테이블을 분해합니다. 이 과정에서는 부분 함수 종속성을 제거합니다.</p>
<p>3차 정규화: 테이블에서 후보키가 아닌 모든 컬럼이 기본키에 종속되도록 테이블을 분해합니다. 이 과정에서는 이행적 함수 종속성을 제거합니다.</p>
<p>4차 정규화: 테이블에서 다중값 종속성을 제거하기 위해 테이블을 분해합니다.</p>
<p>5차 정규화: 조인을 이용하여 테이블을 분해하여 데이터의 일관성을 유지합니다.</p>
<p>정규화를 통해 데이터베이스는 중복 데이터를 제거하고 일관성 있는 데이터를 유지할 수 있습니다. 그러나, 과도한 정규화는 데이터베이스 성능을 저하시킬 수 있으므로, 테이블을 적절한 수준으로 분해하는 것이 중요합니다.</p>
<hr>

<h4 id="제1-정규형-1nf"><strong>제1 정규형 (1NF)</strong></h4>
<p>제1 정규형은 다음과 같은 규칙들을 만족해야 한다.</p>
<ol>
<li>각 컬럼이 하나의 속성만을 가져야 한다.</li>
<li>하나의 컬럼은 같은 종류나 타입(type)의 값을 가져야 한다.</li>
<li>각 컬럼이 유일한(unique) 이름을 가져야 한다.</li>
<li>칼럼의 순서가 상관없어야 한다.</li>
</ol>
<p>조금 복잡해보이지만, 간단하게 예시를 들면 이해가 빠르다. 아래 테이블을 살펴보자.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/8997585a-868b-4fb8-a87a-f42d7a951fbf/image.png" alt=""></p>
<p>[그림 1] 1정규화가 필요한 테이블</p>
<p>각 컬럼이 하나의 값(속성)만을 가져야 한다. -&gt; 불만족! 하나의 칼럼(과목)에 두 개의 값을 가짐
하나의 컬럼은 같은 종류나 타입(type)의 값을 가져야 한다. -&gt; 만족
각 컬럼이 유일한(unique) 이름을 가져야 한다. -&gt; 만족
칼럼의 순서가 상관없어야 한다. -&gt; 만족
1번 규칙을 불만족하므로 이를 고치기 위해서는 아래와 같이 분해하면 된다.</p>
<p>[그림 2] 1NF
<img src="https://velog.velcdn.com/images/jjinny_0609/post/7e018304-e123-4361-b90b-5902ad0aed6c/image.png" alt=""></p>
<p>위와 같이 각 칼럼이 원자 값을 갖도록 테이블을 분해하면 1 정규형을 만족하게 바꿀 수 있다. </p>
<h4 id="제2-정규형-2nf">제2 정규형 (2NF)</h4>
<p>제2 정규형은 다음과 같은 규칙을 만족해야 한다.</p>
<ol>
<li>1정규형을 만족해야 한다.</li>
<li>모든 컬럼이 부분적 종속(Partial Dependency)이 없어야 한다. == 모든 칼럼이 완전 함수 종속을 만족해야 한다.</li>
</ol>
<p>부분적 종속이란 기본키 중에 특정 컬럼에만 종속되는 것이다. </p>
<p>완전 함수 종속이란 기본키의 부분집합이 결정자가 되어선 안된다는 것이다. ( 비슷한 말이다 )</p>
<p>[그림 3] 2정규화가 필요한 테이블
<img src="https://velog.velcdn.com/images/jjinny_0609/post/1f7a7a17-696f-451d-b183-a21054deb895/image.png" alt=""></p>
<p>위와 같은 테이블과 FD 다이어그램을 보자.</p>
<p>성적의 특정 값을 알기 위해서는 학생 번호+과목이 있어야 한다. (ex : 102번의 자바 성적 70 )</p>
<p>하지만 특정 과목의 지도교수는 과목명만 알면 지도교수가 누군지 알 수 있다. (ex : 자바의 지도교수 박자바)</p>
<p>위 테이블에서 기본키는 (학생 번호, 과목)으로 복합키이다. </p>
<p>그런데 이때 지도교수 칼럼은 (학생 번호, 과목)에 종속되지 않고 (과목) 에만 종속되는 부분적 종속이다. </p>
<p>따라서 제2 정규화를 만족하지 않으므로 아래와 같이 분해해야 한다.</p>
<p>[그림 4] 2NF
<img src="https://velog.velcdn.com/images/jjinny_0609/post/3107ed8c-74b9-4df2-9719-ee7a1a5ea612/image.png" alt=""></p>
<p>위와 같이 분해하면 제2 정규형을 만족한다. </p>
<h4 id="제3-정규형-3nf">제3 정규형 (3NF)</h4>
<p>제3 정규형은 다음과 같은 규칙을 만족해야 한다.</p>
<ol>
<li>2 정규형을 만족해야 한다.</li>
<li>기본키를 제외한 속성들 간의 이행 종속성 (Transitive Dependency)이 없어야 한다.
이행 종속성이란 A-&gt;B, B-&gt;C 일 때 A-&gt;C 가 성립하면 이행 종속이라고 한다. </li>
</ol>
<p>[그림 5] 3정규화가 필요한 테이블
<img src="https://velog.velcdn.com/images/jjinny_0609/post/714aa00f-8eb1-4b7e-8caf-b451f442638a/image.png" alt="">
위와 같은 테이블을 보자. ID를 알면 등급을 알 수 있다. 등급을 알면 할인율을 알 수 있다. 따라서 ID를 알면 할인율을 알 수 있다. 따라서 이행 종속성이 존재하므로 제 3 정규형을 만족하지 않는다.</p>
<p>3정규형을 만족하기 위해서는 아래와 같이 분해해야 한다.</p>
<p>[그림 6] 3NF
<img src="https://velog.velcdn.com/images/jjinny_0609/post/0e98deb7-89ec-4aa7-bf18-f0a7d592509d/image.png" alt=""></p>
<p>위와 같이 분해하면 제 3정규형을 만족한다.</p>
<h4 id="bcnf-boyce-codd-normal-form">BCNF (Boyce-Codd Normal Form)</h4>
<p>BCNF는 제 3정규형을 좀 더 강화한 버전으로 다음과 같은 규칙을 만족해야 한다.</p>
<ol>
<li>3정규형을 만족해야 한다.</li>
<li>모든 결정자가 후보키 집합에 속해야 한다.</li>
</ol>
<p>모든 결정자가 후보키 집합에 속해야 한다는 뜻은, 후보키 집합에 없는 칼럼이 결정자가 되어서는 안 된다는 뜻이다.</p>
<p>[그림 7] BCNF가 필요한 테이블
<img src="https://velog.velcdn.com/images/jjinny_0609/post/f10838ae-628f-4130-86c3-fc8d6cb8c71f/image.png" alt=""></p>
<p>위와 같은 테이블을 보자. (학생 번호, 과목)이 기본키로 지도교수를 알 수 있다. 하지만 같은 과목을 다른 교수가 가르칠 수도 있어서 과목-&gt; 지도교수 종속은 성립하지 않는다. 하지만 지도교수가 어떤 과목을 가르치는지는 알 수 있으므로 지도교수-&gt; 과목 종속이 성립한다.</p>
<p>이처럼 후보키 집합이 아닌 칼럼이 결정자가 되어버린 상황을 BCNF를 만족하지 않는다고 한다. </p>
<p>(참고로 위 테이블은 제3 정규형까지는 만족하는 테이블이다 )</p>
<p>BCNF를 만족하기 위해서는 아래와 같이 분해하면 된다.</p>
<p>[그림 8] BCNF
<img src="https://velog.velcdn.com/images/jjinny_0609/post/aee6000c-5356-4faf-b49e-b45963201c53/image.png" alt=""></p>
<p>참고로 위에서 학생 번호와 지도교수는 다치 종속성이 발생하게 되는데, 이는 제4 정규형에서 다뤄진다.</p>
<p>제4 정규형 이상~
<img src="https://velog.velcdn.com/images/jjinny_0609/post/fbf94619-0919-40fa-8fd2-841b3f90309b/image.png" alt=""></p>
<p>Normalization
정규형</p>
<p>보통 정규화는 BCNF 까지만 하는 경우가 많다. 그 이상 정규화를 하면 정규화의 단점이 나타날 수도 있다.</p>
<h4 id="제4-정규형4nf">제4 정규형(4NF)</h4>
<p>제4 정규형은 다음과 같은 규칙을 만족해야 한다.</p>
<ol>
<li>BCNF를 만족해야 한다.</li>
<li>다치 종속(Multi-valued Dependency)이 없어야 한다.</li>
</ol>
<p>여기서 다치 종속이란 다음과 같은 조건들을 만족할 때를 뜻한다.</p>
<ol>
<li><p>A-&gt;B 일 때 하나의 A값에 여러 개의 B값이 존재하면 다치 종속성을 가진다고 하고 A↠B라고 표시한다</p>
</li>
<li><p>최소 3개의 칼럼이 존재한다.</p>
</li>
<li><p>R(A, B, C)가 있을 때 A와 B 사이에 다치 종속성이 있을 때 B와 C가 독립적이다.</p>
</li>
</ol>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/3f6c5869-d2dc-4b01-94b1-9fd4f5a20bb5/image.png" alt=""></p>
<p>위와 같은 테이블을 보자. 101번 학생은 자바와 C++ 과목을 수강하고, 노래와 게임을 취미로 가진다. </p>
<p>이렇게 되면 학생 번호 하나에 과목 여러 개와 취미 여러 개가 종속된다. 이런 경우 학생 번호를 토대로 값을 조회하면 아래와 같이 중복이 발생하게 된다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/ed20aec3-fe48-42bb-8241-52883d4c7071/image.png" alt=""></p>
<p>과목과 취미는 관계가 없는 독립적인 관계이다. 하지만 같은 테이블의 학생 번호라는 칼럼에 다치 종속되어버려 중복이 발생하는 문제가 생겼다.</p>
<p>4NF를 만족하기 위해서는 아래와 같이 분해하면 된다.</p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/535f5694-e752-4f92-bda3-ca4cd9bd7b3d/image.png" alt=""></p>
<p>위 2개의 테이블은 여전히 다치 종속성을 가지지만, 2개 이상의 칼럼이 하나의 칼럼에 다치 종속되지는 않기 때문에 제4 정규형을 만족한다.</p>
<h4 id="제5-정규형5nf">제5 정규형(5NF)</h4>
<p>제5 정규형은 중복을 제거하기 위해 분해할 수 있을 만큼 전부 분해하는 것이다. 이러한 5NF는 Project Join Normal Form(PJNF)라고도 불린다. 이러한 제 5정규형은 다음과 같은 규칙을 만족해야 한다.</p>
<ol>
<li>4NF를 만족해야 한다.</li>
<li>조인 종속(Join dependency)이 없어야 한다.</li>
<li>조인 연산을 했을 때 손실이 없어야 한다.</li>
</ol>
<p>조인 종속은 다치 종속의 좀 더 일반화된 형태이다. 만약 하나의 릴레이션을 여러 개의 릴레이션으로 무손실 분해했다가 다시 결합할 수 있다면 조인 종속이라고 한다. </p>
<p><img src="https://velog.velcdn.com/images/jjinny_0609/post/7f31977d-4c42-48e0-b51f-c29f5ea73519/image.png" alt=""></p>
<p>예를 들어 A라는 릴레이션을 B와 C로 분해했다가 다시 조인했을 때 그대로 A가 된다면, A는 조인 종속성이 있다고 한다.</p>
<p>제5 정규형의 경우 예시를 들기 복잡하기 때문에 생략하겠다. </p>
<p>정규화 내용 출처 : <a href="https://code-lab1.tistory.com/48">https://code-lab1.tistory.com/48</a></p>
<hr>

<h3 id="트랜잭션">트랜잭션</h3>
<p> 트랜잭션 : 두개 이상의 sql을 동시다발로 실행하고자 할때 사용
 [예시]</p>
<pre><code> select * from board where no = 1125;
 update board set count = count + 1 where no = 1125;

 start transcation
 select * from board where no = 1125;
 update board set count = count + 1 where no = 1125;

 select와 update 둘다 성공했으면 commit
 select와 update 둘 중 하나라도 실패했으면 rollback</code></pre><p> 데이터베이스의 상태를 변화시키는 하나의 논리적인 작업 단위입니다. 트랜잭션은 하나 이상의 SQL 쿼리를 묶어서 하나의 작업으로 처리하며, 이 작업은 모두 실행되거나, 모두 실행되지 않아야 합니다. 즉, 모든 작업이 성공하면 전체 트랜잭션이 성공으로 처리되고, 하나라도 실패하면 전체 트랜잭션은 실패 처리됩니다.</p>
<p>트랜잭션은 데이터의 무결성과 일관성을 보장하기 위해 필요합니다. 데이터베이스에서 데이터의 변경이 발생하면, 해당 작업을 트랜잭션으로 묶어서 처리하면, 데이터의 일관성이 유지됩니다. 만약 작업 중 일부가 실패하면, 이전 상태로 롤백하거나, 작업이 완료되지 않은 상태로 유지되므로 데이터의 무결성이 유지됩니다.</p>
<p>트랜잭션은 일반적으로 4가지의 속성을 갖습니다. 이것을 ACID라고 합니다.</p>
<ul>
<li><p><strong>원자성(Atomicity)</strong> : 트랜잭션은 원자적(Atomic)이어야 합니다. 즉, 트랜잭션 내의 모든 작업은 전부 실행되거나 전부 실행되지 않아야 합니다.</p>
</li>
<li><p><strong>일관성(Consistency)</strong> : 트랜잭션을 실행한 결과는 일관성 있어야 합니다. 즉, 데이터베이스의 제약 조건을 위반하지 않아야 합니다.</p>
</li>
<li><p><strong>고립성(Isolation)</strong> : 동시에 여러 트랜잭션이 실행될 때, 각각의 트랜잭션은 독립적으로 실행되는 것처럼 보여야 합니다. 즉, 다른 트랜잭션에 영향을 받지 않고 실행되어야 합니다.</p>
</li>
<li><p><strong>지속성(Durability)</strong> : 트랜잭션을 성공적으로 완료하면, 해당 작업 결과는 영구적으로 저장되어야 합니다. 즉, 시스템 장애가 발생해도 데이터의 일관성을 유지할 수 있어야 합니다.</p>
</li>
</ul>
<p>트랜잭션은 BEGIN TRAN, COMMIT, ROLLBACK과 같은 SQL 문을 사용하여 수행됩니다. BEGIN TRAN 문은 트랜잭션을 시작하고, COMMIT 문은 트랜잭션을 완료하고 변경 내용을 데이터베이스에 반영합니다. ROLLBACK 문은 트랜잭션 내에서 발생한 모든 변경 내용을 취소하고 이전 상태로 되돌립니다.</p>
<p>트랜잭션은 데이터베이스에서 무결성을 유지하고 데이터의 일관성을 보장하는 데 중요합니다. 하나의 트랜잭션 내에서 발생한 모든 작업이 전체적으로 성공하거나 실패하기 때문에 데이터베이스에서 발생할 수 있는 문제를 예방하고 데이터 무결성을 유지할 수 있습니다.</p>
<h3 id="auto-commit">Auto commit</h3>
<p>Auto commit은 데이터베이스에서 쿼리를 실행할 때 자동으로 COMMIT 문이 실행되어, 쿼리 결과가 즉시 데이터베이스에 반영되는 것을 말합니다. 이것은 일반적으로 데이터베이스에서 기본적으로 설정되어 있습니다.</p>
<p>Auto commit이 활성화되면, 각 쿼리문 실행 후 해당 쿼리에 대한 변경 사항이 데이터베이스에 즉시 적용됩니다. 이것은 단일 쿼리 실행의 경우에는 편리하지만, 여러 쿼리가 수행되는 트랜잭션에서는 문제가 발생할 수 있습니다. 예를 들어, 여러 개의 쿼리문이 하나의 트랜잭션으로 묶여 있을 때, 첫 번째 쿼리문에서 오류가 발생하면 해당 트랜잭션 전체가 롤백되어야 할 수 있습니다. 하지만 auto commit이 활성화되어 있으면 첫 번째 쿼리문에서 오류가 발생하여 롤백이 필요한 경우, 이전까지 실행된 모든 쿼리문에 대한 변경 사항이 이미 데이터베이스에 적용되어 있기 때문에 롤백이 불가능합니다.</p>
<p>따라서, auto commit을 사용하는 경우에는 데이터의 일관성과 무결성에 대한 위험이 존재합니다. 따라서, 트랜잭션을 수행할 때에는 auto commit을 비활성화하여, 모든 쿼리문이 트랜잭션 내에서 묶여 실행되고, 트랜잭션의 성공 여부에 따라 적용되거나 롤백되도록 구성해야 합니다. 이를 통해 데이터베이스의 무결성과 일관성을 보장할 수 있습니다.</p>
<p><strong>[네이버 게시물 클릭했을때 조회수 올리는법]</strong></p>
<pre><code>select * from board where no = 3;    -- 3번 게시물 title을 클릭하면
update board set count = count+1 where no = 3;

select * from board;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/e9d94ee5-02e2-433b-b3c5-0ec32e28df78/image.png" alt=""></p>
<p>위 코드에서 일부러 board에 오타를 내보았습니다.</p>
<pre><code>select * from bord where no = 3;    -- 3번 게시물 title을 클릭하면
update board set count = count+1 where no = 3;</code></pre><p>select 결과에 상관없이 auto commit 되어서 count+1 모습입니다.
<img src="https://velog.velcdn.com/images/jjinny_0609/post/25c53523-8dfd-4f06-a600-f557ae88d899/image.png" alt=""></p>
<p>트랜잭션을 사용</p>
<pre><code>start transaction;
select * from board where no = 3;    -- 3번 게시물 title을 클릭하면
update board set count = count+1 where no = 3;
-- 정상적으로 select와 update가 되는 경우
-- commit

start transaction;
select * from bod where no = 3;    -- 3번 게시물 title을 클릭하면
update board set count = count+1 where no = 3;
-- update는 정상적으로 수행되었으나, select가 제대로 작동하지 않았음. : count값을 원래대로 되롤려 줘야함.
rollback;
-- commit
select * from board;</code></pre><p><img src="https://velog.velcdn.com/images/jjinny_0609/post/bbf98e33-9bb4-4774-8c28-5d9bd4f4177b/image.png" alt="">
현재 count 7인 상황
<img src="https://velog.velcdn.com/images/jjinny_0609/post/c8498312-73ae-4dc4-90b9-9bafcd71e3f9/image.png" alt="">
rollback으로 8이 되지않았음.</p>
]]></description>
        </item>
    </channel>
</rss>