<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>다연이네</title>
    <link>https://daspace.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Thu, 7 May 2026 05:20:56 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>　다연　</managingEditor>
    <image>
      <title>다연이네</title>
      <url>https://tistory1.daumcdn.net/tistory/4287716/attach/67febb33128c4652bc7c45825804832c</url>
      <link>https://daspace.tistory.com</link>
    </image>
    <item>
      <title>강북삼성병원 야경</title>
      <link>https://daspace.tistory.com/346</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zQDz8/btrRJQr2K8w/6kYydLB9w81JS4nPK5Urqk/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zQDz8/btrRJQr2K8w/6kYydLB9w81JS4nPK5Urqk/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zQDz8/btrRJQr2K8w/6kYydLB9w81JS4nPK5Urqk/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzQDz8%2FbtrRJQr2K8w%2F6kYydLB9w81JS4nPK5Urqk%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bl3fSn/btrRH5QyhmX/3gtimhMqO5jGkkHr16Ez30/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bl3fSn/btrRH5QyhmX/3gtimhMqO5jGkkHr16Ez30/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bl3fSn/btrRH5QyhmX/3gtimhMqO5jGkkHr16Ez30/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbl3fSn%2FbtrRH5QyhmX%2F3gtimhMqO5jGkkHr16Ez30%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;3024&quot; height=&quot;4032&quot; data-origin-width=&quot;3024&quot; data-origin-height=&quot;4032&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/T2GIq/btrRH5Xh5Qm/YVmjS3uKsSFin2psviiG70/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/T2GIq/btrRH5Xh5Qm/YVmjS3uKsSFin2psviiG70/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/T2GIq/btrRH5Xh5Qm/YVmjS3uKsSFin2psviiG70/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FT2GIq%2FbtrRH5Xh5Qm%2FYVmjS3uKsSFin2psviiG70%2Fimg.jpg&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;4032&quot; height=&quot;3024&quot; data-origin-width=&quot;4032&quot; data-origin-height=&quot;3024&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;#야경맛집 #강북삼성병원&lt;/p&gt;</description>
      <category>기타</category>
      <category>강북삼성병원</category>
      <category>야경맛집</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/346</guid>
      <comments>https://daspace.tistory.com/346#entry346comment</comments>
      <pubDate>Mon, 21 Nov 2022 15:45:32 +0900</pubDate>
    </item>
    <item>
      <title>Linux 기본 셋팅 (PuTTY)</title>
      <link>https://daspace.tistory.com/345</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스로 서비스를 올리기 위해 기존 Window에 셋팅했던 프로젝트를 리눅스로 옮기는 과정을 정리한다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;&lt;span&gt;&lt;span&gt;1. &lt;/span&gt;&lt;span&gt;개발 서버 정보 &lt;/span&gt;&lt;span&gt;: &lt;s&gt;xxx.xxx.x.xx&lt;/s&gt; (SSH)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;2. &lt;/span&gt;&lt;span&gt;계정정보 &lt;/span&gt;&lt;span&gt;: &lt;s&gt;id / password&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;3. &lt;/span&gt;&lt;span&gt;설치경로 &lt;/span&gt;&lt;span&gt;: /home/gwtest/bdy&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;4. &lt;/span&gt;&lt;span&gt;사용포트 &lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;9002&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;5. contextpath : xclick_&lt;/span&gt;&lt;span&gt;bdy&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;6. DB &lt;/span&gt;&lt;span&gt;정보 &lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;HOST &lt;s&gt;xxx.xxx.x.xx&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;PORT 1521&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;SID orcl : &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;계정 &lt;s&gt;id / password&lt;/s&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;7. &lt;/span&gt;&lt;span&gt;소스 :&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;s&gt;&lt;span&gt;svn://xxxxxx&lt;/span&gt;&lt;/s&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;8.JDK : &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;OpenJDK1.8&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span&gt;&lt;span&gt;9.WAS : &lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;apache-tomcat-9.0.46&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 서버 및 데이터베이스 정보는 비공개&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;* 소스 -&amp;gt; svn, &lt;span style=&quot;color: #ef5369;&quot;&gt;&lt;i&gt;&lt;b&gt;'셋팅'만 정리&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;윈도우 환경에서 서비스가 올라간다는 가정 하에 시작한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;1. PuTTY 다운로드, 접속&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(리눅스 서버 접속을 위한 프로그램)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bhAbPU/btq92SmbZ7Q/yDqsJY2MM6v1B5uycTqR51/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bhAbPU/btq92SmbZ7Q/yDqsJY2MM6v1B5uycTqR51/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bhAbPU/btq92SmbZ7Q/yDqsJY2MM6v1B5uycTqR51/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbhAbPU%2Fbtq92SmbZ7Q%2FyDqsJY2MM6v1B5uycTqR51%2Fimg.png&quot; data-origin-width=&quot;447&quot; data-origin-height=&quot;433&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Host Name: 개발서버 정보&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Port: 22(ssh)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;* 우측의 Save 버튼을 통해 세션 저장 가능&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;2. 폴더 생성 - mkdir&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;접속 후 아이디와 비밀번호를 입력한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;로그인 성공 후 명령어 &lt;b&gt;pwd&lt;/b&gt;를 통해 현재 위치를 확인하고, 설치경로에 맞는 폴더를 생성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;설치 경로가 &amp;nbsp;/home/gwtest/bdy이고, 현재는 gwtest까지밖에 없기 때문에 해당 위치에 &lt;b&gt;mkdir bdy&lt;/b&gt; 명령어를 통해 폴더를 생성해주었다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;pwd&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;현재 경로(위치)를 보여준다.&lt;br /&gt;mkdir bdy&amp;nbsp; &amp;nbsp; &amp;nbsp; bdy라는 폴더를 생성한다.&lt;br /&gt;cd bdy&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; bdy라는 폴더로 이동한다.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;139&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/BppCK/btq97PvyRAe/wMFDoFrvKGGyYVyWKrCPg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/BppCK/btq97PvyRAe/wMFDoFrvKGGyYVyWKrCPg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/BppCK/btq97PvyRAe/wMFDoFrvKGGyYVyWKrCPg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBppCK%2Fbtq97PvyRAe%2FwMFDoFrvKGGyYVyWKrCPg1%2Fimg.png&quot; data-origin-width=&quot;657&quot; data-origin-height=&quot;139&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;3. filezilla 다운로드 (윈도우용)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;u&gt;&lt;span style=&quot;color: #0000ff;&quot;&gt;&lt;/span&gt;&lt;/u&gt;&lt;u&gt;&lt;a href=&quot;https://filezilla-project.org/&quot;&gt;https://filezilla-project.org/&lt;/a&gt;&lt;/u&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일질라란 컴퓨터의 파일들을 FTP 서버에 옮기도록 돕는 프로그램이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;쉽게 말해 윈도우의 파일을 리눅스로, 리눅스의 파일을 윈도우로 복사할 수 있게 해주는 프로그램이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;리눅스 편집기(vi)를 통해 파일 내용을 수정하는 것이 불편하고 익숙하지 않다면, 파일질라를 통해 파일을 윈도우로 받아와 수정한 뒤 재업로드하는 것이 훨씬 간편하다고 느낄 것이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xvOBP/btq97PI7nJB/GvMDCvdTlUXp9XWijmQUb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xvOBP/btq97PI7nJB/GvMDCvdTlUXp9XWijmQUb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xvOBP/btq97PI7nJB/GvMDCvdTlUXp9XWijmQUb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxvOBP%2Fbtq97PI7nJB%2FGvMDCvdTlUXp9XWijmQUb1%2Fimg.png&quot; data-origin-width=&quot;1307&quot; data-origin-height=&quot;843&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;개발서버 및 계정정보를 통해 리눅스에 접속했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;가운데를 기준으로 좌측은 윈도우, 우측은 리눅스이다. 보이는 바와 같이 방금 mkdir로생성했던 bdy 폴더가 gwtest 밑에 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞으로 파일질라를 통해 모든 파일을 리눅스로 업로드할 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;4. WAS 다운로드&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에 맞는 WAS을 다운로드한다. 이번 프로젝트는 톰캣9버전을 사용했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;208&quot; data-origin-height=&quot;32&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kSCFf/btrackOUTdj/YhIn3TeJ8HqFRMd9vELnxk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kSCFf/btrackOUTdj/YhIn3TeJ8HqFRMd9vELnxk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kSCFf/btrackOUTdj/YhIn3TeJ8HqFRMd9vELnxk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkSCFf%2FbtrackOUTdj%2FYhIn3TeJ8HqFRMd9vELnxk%2Fimg.png&quot; data-origin-width=&quot;208&quot; data-origin-height=&quot;32&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;해당 zip파일을 파일질라를 통해 리눅스로 업로드한 후, 명령어를 통해 압축을 푼다. 압축을 풀 때는 mkdir로 폴더를 생성하여 그 안에 압축을 풀었다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;unzip 파일명.zip&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;압축풀기&lt;br /&gt;zip 압축후파일명.zip 원래파일명&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;압축하기&lt;b&gt;&lt;br /&gt;&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;36&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ct9iuE/btq97QabO6o/1KqGkE9fGVNMtzWw2k0uyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ct9iuE/btq97QabO6o/1KqGkE9fGVNMtzWw2k0uyK/img.png&quot; data-alt=&quot;zip과 압축 풀린 폴더&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ct9iuE/btq97QabO6o/1KqGkE9fGVNMtzWw2k0uyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fct9iuE%2Fbtq97QabO6o%2F1KqGkE9fGVNMtzWw2k0uyK%2Fimg.png&quot; data-origin-width=&quot;655&quot; data-origin-height=&quot;36&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;zip과 압축 풀린 폴더&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;5. JDK 다운로드(리눅스용)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로젝트에 맞는 JDK-리눅스용을 다운로드한다. (리눅스 bit를 확인 한 후 그에 맞는 JDK 다운)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;175&quot; data-origin-height=&quot;27&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yLgZh/btq93nfLyVY/dwcf2grooykcf2B7f0209K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yLgZh/btq93nfLyVY/dwcf2grooykcf2B7f0209K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yLgZh/btq93nfLyVY/dwcf2grooykcf2B7f0209K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyLgZh%2Fbtq93nfLyVY%2Fdwcf2grooykcf2B7f0209K%2Fimg.png&quot; data-origin-width=&quot;175&quot; data-origin-height=&quot;27&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 확장자가 tar이다. 압축된 상태 그대로 리눅스로 업로드한 후 명령어를 통해 압축을 풀었다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;tar로 압축&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; tar -cvf 파일명.tar 폴더명&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; (폴더를 파일명.tar로 압축)&lt;br /&gt;tar 압축풀기&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;tar -xvf 파일명.tar&amp;nbsp;&lt;br /&gt;tar.gz로 압축&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; tar -zcvf 파일명.tar 폴더명&lt;br /&gt;tar.gz로 압축 풀기&amp;nbsp; &amp;nbsp;tar -zxvf 파일명.tar.gz&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;37&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QRRPC/btraawoz0XB/inXqhUGvz0OILxLuZUK6w1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QRRPC/btraawoz0XB/inXqhUGvz0OILxLuZUK6w1/img.png&quot; data-alt=&quot;tar와 압축 풀린 폴더&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QRRPC/btraawoz0XB/inXqhUGvz0OILxLuZUK6w1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQRRPC%2Fbtraawoz0XB%2FinXqhUGvz0OILxLuZUK6w1%2Fimg.png&quot; data-origin-width=&quot;650&quot; data-origin-height=&quot;37&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;tar와 압축 풀린 폴더&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JDK에 권한을 부여한다.&amp;nbsp;&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%; height: 20px;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 20px;&quot;&gt;
&lt;td style=&quot;width: 100%; height: 20px;&quot;&gt;&lt;span&gt;&lt;span&gt;chmod 755 jdk1.80_291(&lt;/span&gt;&lt;span&gt;폴더명&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;/span&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;6. 프로젝트 업로드&lt;/b&gt;&lt;/span&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mkdir project로, 프로젝트를 위한 폴더를 생성한다. 해당 폴더에 이클립스에서 작업했던 프로젝트들이 담길 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이클립스에서 작업했던 프로젝트들 내에 경로가 윈도우 기준으로 맞춰진 모든 부분을 수정해준다.(ex. web.xml 등)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;/home/gwtest/bdy/project/xclickr3_bdy_web~ 로 리눅스 경로 맞춰 수정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 후 빌드를 한 다음 team&amp;gt;disconnect로 svn 연결을 끊어주고, 프로젝트들을 복사해 tar로 압축한 후 리눅스에 올려 압축을 풀어준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(이 때 java는 빌드되어 jar 형태로 말려있기 때문에 리눅스로 올리지 않는다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;37&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DrPZp/btq94rI66E8/mW6pBXk1K25XZdpMTZsGmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DrPZp/btq94rI66E8/mW6pBXk1K25XZdpMTZsGmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DrPZp/btq94rI66E8/mW6pBXk1K25XZdpMTZsGmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDrPZp%2Fbtq94rI66E8%2FmW6pBXk1K25XZdpMTZsGmK%2Fimg.png&quot; data-origin-width=&quot;566&quot; data-origin-height=&quot;37&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;7. server.xml 수정, catalina.sh 수정&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서버 포트를 다른 사람들과 겹치지 않게 수정해줘야한다. 로컬에서 셋팅했을 경우(이클립스) 상관 없으나, 리눅스는 다중 사용자를 지원하기 때문에 포트번호가 겹치지 않아야 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;나의 경우 SHUTDOWN 포트를 수정했고, 모든 context 경로들(윈도우 기준에 맞춰진)을 리눅스에 맞춰 수정했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;수정된 파일을 파일질라를 통해 업로드한다. 위치는 톰캣 &amp;gt; conf&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lToOc/btrac8mYQyY/esK7jedJHeKbrffjqSLJG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lToOc/btrac8mYQyY/esK7jedJHeKbrffjqSLJG1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lToOc/btrac8mYQyY/esK7jedJHeKbrffjqSLJG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlToOc%2Fbtrac8mYQyY%2FesK7jedJHeKbrffjqSLJG1%2Fimg.png&quot; data-origin-width=&quot;660&quot; data-origin-height=&quot;431&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이클립스에서 작업했을 때, 서버에 Arguments를 추가해줬던 경우(해당사항 없으면 넘어가도 된다) catalina.sh를 수정해줘야한다. Argements를 추가했는지 안했는지 기억이 안난다면, 아래 사진과 같이 확인 가능하다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;753&quot; width=&quot;691&quot; height=&quot;509&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/OZNt6/btrackBr4T4/vS8yxvOgqk3c1zITxDE2p1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/OZNt6/btrackBr4T4/vS8yxvOgqk3c1zITxDE2p1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/OZNt6/btrackBr4T4/vS8yxvOgqk3c1zITxDE2p1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FOZNt6%2FbtrackBr4T4%2FvS8yxvOgqk3c1zITxDE2p1%2Fimg.png&quot; data-origin-width=&quot;1021&quot; data-origin-height=&quot;753&quot; width=&quot;691&quot; height=&quot;509&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(위 사진은 Argement가 추가되어있지 않은 경우이다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;만약 추가한 경우, 리눅스에서 catalina.sh파일을 다운받아와 수정해준다. (나의 경우 JAVA_OPTS 부분을 추가해줬다)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;catalina.sh의 위치는 톰캣 &amp;gt; bin 이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;82&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EXoqv/btq99ms0E5J/AvVA3vDaRod9rcK7Yfcimk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EXoqv/btq99ms0E5J/AvVA3vDaRod9rcK7Yfcimk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EXoqv/btq99ms0E5J/AvVA3vDaRod9rcK7Yfcimk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEXoqv%2Fbtq99ms0E5J%2FAvVA3vDaRod9rcK7Yfcimk%2Fimg.png&quot; data-origin-width=&quot;943&quot; data-origin-height=&quot;82&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;명령어를 통해 카타리나에 대한 실행권한을 부여한다. (카타리나 뿐만 아니라 확장자가 sh인 모든 파일)&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 100%;&quot;&gt;chmod 700 *.sh&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;또한, 카타리나가 특정 jdk를 바라보도록 아래 2줄을 추가해줘야한다. (리눅스 내 경로로 맞추기)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;46&quot; data-ke-mobilestyle=&quot;widthOrigin&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/r3PxS/btq91VjgNLa/HPzrZiv7fqx3PkwkXK3k5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/r3PxS/btq91VjgNLa/HPzrZiv7fqx3PkwkXK3k5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/r3PxS/btq91VjgNLa/HPzrZiv7fqx3PkwkXK3k5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fr3PxS%2Fbtq91VjgNLa%2FHPzrZiv7fqx3PkwkXK3k5K%2Fimg.png&quot; data-origin-width=&quot;370&quot; data-origin-height=&quot;46&quot; data-ke-mobilestyle=&quot;widthOrigin&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카타리나 수정이 끝나면 다시 리눅스로 업로드한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;8. 서버 실행 &amp;amp; 종료&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;실행&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ex) cd /gwtest/bdy/apache-tomcat-7.0.22/bin/&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;./startup.sh&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;종료&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;Ex) cd /gwtest/bdy/apache-tomcat-7.0.22/bin/&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;./shutdown.sh&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;Tips&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;- PuTTY를 한 개 더 띄워&amp;nbsp; 실시간으로로그를 확인할 수 있다.&amp;nbsp;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&amp;nbsp; &amp;nbsp;cd명령어를 통해 톰캣 내 logs 폴더까지 들어간 후, &lt;b&gt;tail -f catalina.out&amp;nbsp;&lt;/b&gt;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;- &lt;b&gt;ps -ef | grep tomcat&lt;/b&gt; 명령어를 통해 현재 실행중인 톰캣목록을 볼 수 있다.&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;- 권한&amp;nbsp;&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&amp;nbsp; &lt;b&gt;&amp;nbsp;chmod 644&lt;/b&gt;&amp;nbsp; 소유자:읽기,쓰기&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;그룹/다른사용자:읽기&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&amp;nbsp; &amp;nbsp;&lt;b&gt;chmod 755&amp;nbsp;&lt;/b&gt; 소유자:읽기,쓰기,실행&amp;nbsp; &amp;nbsp;그룹/다른사용자:읽기, 실행&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;&amp;nbsp; &amp;nbsp;디렉토리인 경우, 디렉토리 파일 안에 있는 하위까지 변경: chmod &lt;b&gt;-R&lt;/b&gt; 755 파일명&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Setting/OS</category>
      <category>Linux</category>
      <category>Linux세팅</category>
      <category>Linux셋팅</category>
      <category>리눅스</category>
      <category>리눅스세팅</category>
      <category>리눅스셋팅</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/345</guid>
      <comments>https://daspace.tistory.com/345#entry345comment</comments>
      <pubDate>Wed, 21 Jul 2021 15:07:09 +0900</pubDate>
    </item>
    <item>
      <title>Git</title>
      <link>https://daspace.tistory.com/314</link>
      <description>&lt;p&gt;&lt;b&gt;버전관리시스템(VCS - Version Control System)&amp;nbsp;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;각 파일을 이전 상태로 되돌릴 수 있고, 프로젝트를 통째로 이전 상태로 되돌릴 수 있고, 시간에 따라 수정 내용을 비교해 볼 수 있고, 누가 문제를 일으켰는지 추적할 수 도 있고, 누가 언제 만들어낸 이슈인지도 알 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;버전 관리 시스템 종류&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ㄱ. 로컬 버전 관리 시스템 (요즘 잘 안씀)&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 데이터베이스를 사용해서 파일의 변경 정보를 관리&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; RCS(Revision Control System) - 회사에서 많이 사용&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 날짜별로, 시간별로 DB관리, 일련의 Patch Set을 적용해서 모든 파일을 특정 시점으로 되돌릴 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ㄴ. 중앙 집중식 버전 관리 시스템(CVCS)&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &lt;span style=&quot;color: #333333;&quot;&gt;CVS, [Subversion] == SVN, Perforce 같은 시스템은 &lt;/span&gt;파일을 관리하는 서버가 별도로 있고 &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 클라이언트가 중앙 서버에서 파일을 받아 사용&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 치명적인 결함 - 가장 대표적 : 중앙 서버에 문제가 발생하면 그동안 작업 불가&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; 중앙 데이터베이스가 있는 하드디스크에 문제가 생기면 프로젝트의 모든 히스토리를 잃음&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ㄷ. 분산 버전 관리 시스템&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;[Git], Mecurial, Bazaar, Darcs 등&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;중앙 집중식의 치명적 결함을 극복 - 저장소를 히스토리와 더불어 전부 복제&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;서버에 문제가 생기면 이 복제물로 다시 작업을 시작할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;용어&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;1) VCS&lt;/p&gt;
&lt;p&gt;2) Checkout (중앙 서버에서 파일을 받아 사용)&lt;/p&gt;
&lt;p&gt;3) Patch Set (파일에서 변경되는 부분)&lt;/p&gt;
&lt;p&gt;4) Clone (복제, 모든 데이터를 가진 진정한 백업)&lt;/p&gt;
&lt;p&gt;5) Git 브랜치 (branch 가지)&lt;/p&gt;
&lt;p&gt;6) Commit (Staging Area -&amp;gt; 로컬 저장소에 저장)&lt;/p&gt;
&lt;p&gt;7) 체크섬 (40/16) SHA-1 해시 기법&lt;/p&gt;
&lt;p&gt;8) 세 가지 상태 (깃은 파일을 아래 3가지 상태로 관리)&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; ㄱ. Committed 데이터가 로컬 DB에 안전하게 저장된 상태 ( 로컬 저장소에 저장 완료! 원격(서버)저장소X )&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; ㄴ. Modified&amp;nbsp; &amp;nbsp; &lt;span&gt;수정한 파일을 아직 로컬 데이터베이스에 커밋하지 않은 것&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; ㄷ. Staged&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;현재 수정한 파일을 곧 커밋할 것이라고 표시한 상태&lt;/p&gt;
&lt;p&gt;9)&lt;span&gt;&amp;nbsp;&lt;span&gt;Git 디렉토리는 Git이 프로젝트의 메타데이터와 객체 데이터베이스를 저장하는 곳을 말한다. &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp;이 Git 디렉토리가 Git의 핵심이다. 다른 컴퓨터에 있는 저장소를&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;Clone&lt;span&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;할 때 Git 디렉토리가 만들어진다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;10) 워킹 트리는 &lt;span&gt;프로젝트의 특정 버전을 Checkout 한 것이다. Git 디렉토리는 지금 작업하는 디스크에 있고 &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;그 디렉토리 안에 압축된 데이터베이스에서 파일을 가져와서 워킹 트리를 만든다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;11) Index == Staging Area&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;12)&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;깃허브: 포스팅 업체, 서버, 깃과 다름&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/314</guid>
      <comments>https://daspace.tistory.com/314#entry314comment</comments>
      <pubDate>Wed, 3 Mar 2021 12:24:05 +0900</pubDate>
    </item>
    <item>
      <title>[days16] 파일 업로드 처리</title>
      <link>https://daspace.tistory.com/313</link>
      <description>&lt;p&gt;&lt;b&gt;ex05&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;첨부파일을 서버에 전송하는 방식&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1) &amp;lt;form&amp;gt; 태그 이용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2) Ajax 이용&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;초기설정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;pom.xml&lt;/p&gt;
&lt;pre id=&quot;code_1614141984721&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
   xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
   xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd&quot;&amp;gt;
   &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
   &amp;lt;groupId&amp;gt;org.zerock&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;controller&amp;lt;/artifactId&amp;gt;
   &amp;lt;name&amp;gt;ex05&amp;lt;/name&amp;gt;
   &amp;lt;packaging&amp;gt;war&amp;lt;/packaging&amp;gt;
   &amp;lt;version&amp;gt;1.0.0-BUILD-SNAPSHOT&amp;lt;/version&amp;gt;
   &amp;lt;properties&amp;gt;
      &amp;lt;java-version&amp;gt;1.8&amp;lt;/java-version&amp;gt;
      &amp;lt;org.springframework-version&amp;gt;5.0.7.RELEASE&amp;lt;/org.springframework-version&amp;gt;
      &amp;lt;org.aspectj-version&amp;gt;1.9.0&amp;lt;/org.aspectj-version&amp;gt;
      &amp;lt;org.slf4j-version&amp;gt;1.7.25&amp;lt;/org.slf4j-version&amp;gt;
   &amp;lt;/properties&amp;gt;
   &amp;lt;dependencies&amp;gt;
      &amp;lt;!-- Spring --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
         &amp;lt;exclusions&amp;gt;
            &amp;lt;!-- Exclude Commons Logging in favor of SLF4j --&amp;gt;
            &amp;lt;exclusion&amp;gt;
               &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;
               &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;
            &amp;lt;/exclusion&amp;gt;
         &amp;lt;/exclusions&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-webmvc&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- AspectJ --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.aspectj&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;aspectjrt&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.aspectj-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- Logging --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.slf4j-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jcl-over-slf4j&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.slf4j-version}&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;slf4j-log4j12&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.slf4j-version}&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;!-- p.54 &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt; &amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt; 
         &amp;lt;version&amp;gt;1.2.15&amp;lt;/version&amp;gt; &amp;lt;exclusions&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;javax.mail&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;mail&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;javax.jms&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;jms&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;com.sun.jdmk&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;jmxtools&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;com.sun.jmx&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;jmxri&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;/exclusions&amp;gt; &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt; 
         &amp;lt;/dependency&amp;gt; --&amp;gt;
      &amp;lt;!-- @Inject --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.inject&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;javax.inject&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- Servlet --&amp;gt;
      &amp;lt;!-- &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt; &amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt; 
         &amp;lt;version&amp;gt;2.5&amp;lt;/version&amp;gt; &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt; &amp;lt;/dependency&amp;gt; --&amp;gt;
      &amp;lt;!-- p.111 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;javax.servlet-api&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;3.1.0&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.servlet.jsp&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jsp-api&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.1&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jstl&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.2&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- Test p.54 --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;4.12&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p.54 --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-test&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.18.18&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;&amp;lt;!-- log4j.xml 설정 필요(자동) --&amp;gt;
         &amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.2.17&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p.83 https://github.com/brettwooldridge/HiKariCP --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.zaxxer&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;HikariCP&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;4.0.2&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 90 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.mybatis&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;mybatis&amp;lt;/artifactId&amp;gt;
         &amp;lt;!-- &amp;lt;version&amp;gt;3.4.6&amp;lt;/version&amp;gt; --&amp;gt;
         &amp;lt;version&amp;gt;3.5.6&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.mybatis&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;mybatis-spring&amp;lt;/artifactId&amp;gt;
         &amp;lt;!-- &amp;lt;version&amp;gt;1.3.2&amp;lt;/version&amp;gt; --&amp;gt;
         &amp;lt;version&amp;gt;2.0.6&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-tx&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-jdbc&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 101 --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.bgee.log4jdbc-log4j2&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;log4jdbc-log4j2-jdbc4&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.16&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 147 jackson-databind --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.fasterxml.jackson.core&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jackson-databind&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.12.1&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 149 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;commons-fileupload&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;commons-fileupload&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.4&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 357 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.fasterxml.jackson.dataformat&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jackson-dataformat-xml&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.12.1&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 357 Java 인스턴스를 JSON 타입의 문자열로 변환 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.google.code.gson&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;gson&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.8.6&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.aspectj&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;aspectjweaver&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.aspectj-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;net.coobird&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;thumbnailator&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;0.4.8&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.quartz-scheduler&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;quartz&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.3.0&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.quartz-scheduler&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;quartz-jobs&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.3.0&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-web&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-config&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-core&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-taglibs&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
   &amp;lt;/dependencies&amp;gt;
   &amp;lt;build&amp;gt;
      &amp;lt;plugins&amp;gt;
         &amp;lt;plugin&amp;gt;
            &amp;lt;artifactId&amp;gt;maven-eclipse-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.9&amp;lt;/version&amp;gt;
            &amp;lt;configuration&amp;gt;
               &amp;lt;additionalProjectnatures&amp;gt;
                  &amp;lt;projectnature&amp;gt;org.springframework.ide.eclipse.core.springnature&amp;lt;/projectnature&amp;gt;
               &amp;lt;/additionalProjectnatures&amp;gt;
               &amp;lt;additionalBuildcommands&amp;gt;
                  &amp;lt;buildcommand&amp;gt;org.springframework.ide.eclipse.core.springbuilder&amp;lt;/buildcommand&amp;gt;
               &amp;lt;/additionalBuildcommands&amp;gt;
               &amp;lt;downloadSources&amp;gt;true&amp;lt;/downloadSources&amp;gt;
               &amp;lt;downloadJavadocs&amp;gt;true&amp;lt;/downloadJavadocs&amp;gt;
            &amp;lt;/configuration&amp;gt;
         &amp;lt;/plugin&amp;gt;
         &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;3.5.1&amp;lt;/version&amp;gt;
            &amp;lt;configuration&amp;gt;
               &amp;lt;source&amp;gt;1.8&amp;lt;/source&amp;gt;
               &amp;lt;target&amp;gt;1.8&amp;lt;/target&amp;gt;
               &amp;lt;compilerArgument&amp;gt;-Xlint:all&amp;lt;/compilerArgument&amp;gt;
               &amp;lt;showWarnings&amp;gt;true&amp;lt;/showWarnings&amp;gt;
               &amp;lt;showDeprecation&amp;gt;true&amp;lt;/showDeprecation&amp;gt;
            &amp;lt;/configuration&amp;gt;
         &amp;lt;/plugin&amp;gt;
         &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;exec-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;1.2.1&amp;lt;/version&amp;gt;
            &amp;lt;configuration&amp;gt;
               &amp;lt;mainClass&amp;gt;org.test.int1.Main&amp;lt;/mainClass&amp;gt;
            &amp;lt;/configuration&amp;gt;
         &amp;lt;/plugin&amp;gt;
      &amp;lt;/plugins&amp;gt;
   &amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;web.xml&lt;/p&gt;
&lt;pre id=&quot;code_1614142036187&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;web-app version=&quot;3.1&quot;
	xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
	xmlns=&quot;http://java.sun.com/xml/ns/javaee&quot;
	xsi:schemaLocation=&quot;http://java.sun.com/xml/ns/javaee https://java.sun.com/xml/ns/javaee/web-app_3_1.xsd&quot;&amp;gt;

	&amp;lt;!-- The definition of the Root Spring Container shared by all Servlets and Filters --&amp;gt;
	&amp;lt;context-param&amp;gt;
		&amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
		&amp;lt;param-value&amp;gt;/WEB-INF/spring/root-context.xml&amp;lt;/param-value&amp;gt;
	&amp;lt;/context-param&amp;gt;
	
	&amp;lt;!-- Creates the Spring Container shared by all Servlets and Filters --&amp;gt;
	&amp;lt;listener&amp;gt;
		&amp;lt;listener-class&amp;gt;org.springframework.web.context.ContextLoaderListener&amp;lt;/listener-class&amp;gt;
	&amp;lt;/listener&amp;gt;

	&amp;lt;!-- Processes application requests --&amp;gt;
	&amp;lt;servlet&amp;gt;
		&amp;lt;servlet-name&amp;gt;appServlet&amp;lt;/servlet-name&amp;gt;
		&amp;lt;servlet-class&amp;gt;org.springframework.web.servlet.DispatcherServlet&amp;lt;/servlet-class&amp;gt;
		&amp;lt;init-param&amp;gt;
			&amp;lt;param-name&amp;gt;contextConfigLocation&amp;lt;/param-name&amp;gt;
			&amp;lt;param-value&amp;gt;/WEB-INF/spring/appServlet/servlet-context.xml&amp;lt;/param-value&amp;gt;
		&amp;lt;/init-param&amp;gt;
		&amp;lt;!-- p 159 404--&amp;gt;
      &amp;lt;init-param&amp;gt;
        &amp;lt;param-name&amp;gt;throwExceptionIfNoHandlerFound&amp;lt;/param-name&amp;gt;
        &amp;lt;param-value&amp;gt;true&amp;lt;/param-value&amp;gt;
      &amp;lt;/init-param&amp;gt;
      
		&amp;lt;load-on-startup&amp;gt;1&amp;lt;/load-on-startup&amp;gt;
		
		&amp;lt;multipart-config&amp;gt;
         &amp;lt;location&amp;gt;C:\\upload\\temp&amp;lt;/location&amp;gt;
         &amp;lt;max-file-size&amp;gt;20971520&amp;lt;/max-file-size&amp;gt; &amp;lt;!--1MB * 20 --&amp;gt;
         &amp;lt;max-request-size&amp;gt;41943040&amp;lt;/max-request-size&amp;gt;&amp;lt;!-- 40MB --&amp;gt;
         &amp;lt;file-size-threshold&amp;gt;20971520&amp;lt;/file-size-threshold&amp;gt; &amp;lt;!-- 20MB --&amp;gt;
      &amp;lt;/multipart-config&amp;gt;
	&amp;lt;/servlet&amp;gt;
		
	&amp;lt;servlet-mapping&amp;gt;
		&amp;lt;servlet-name&amp;gt;appServlet&amp;lt;/servlet-name&amp;gt;
		&amp;lt;url-pattern&amp;gt;/&amp;lt;/url-pattern&amp;gt;
	&amp;lt;/servlet-mapping&amp;gt;
	
	&amp;lt;filter&amp;gt;
      &amp;lt;filter-name&amp;gt;encodingFilter&amp;lt;/filter-name&amp;gt;
      &amp;lt;filter-class&amp;gt;org.springframework.web.filter.CharacterEncodingFilter&amp;lt;/filter-class&amp;gt;
      &amp;lt;init-param&amp;gt;
         &amp;lt;param-name&amp;gt;encoding&amp;lt;/param-name&amp;gt;
         &amp;lt;param-value&amp;gt;UTF-8&amp;lt;/param-value&amp;gt;
      &amp;lt;/init-param&amp;gt;
   &amp;lt;/filter&amp;gt;
   &amp;lt;filter-mapping&amp;gt;
      &amp;lt;filter-name&amp;gt;encodingFilter&amp;lt;/filter-name&amp;gt;
      &amp;lt;url-pattern&amp;gt;/*&amp;lt;/url-pattern&amp;gt;
   &amp;lt;/filter-mapping&amp;gt;

&amp;lt;/web-app&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;- 상단 네임스페이스 버전 3.1로 수정하고, http 링크 수정하고, &amp;lt;multipart-config&amp;gt; 태그 추가&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;servlet-context.xml에 아래 코딩 추가&lt;/p&gt;
&lt;pre id=&quot;code_1614142119460&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;context:component-scan base-package=&quot;org.zerock.controller&quot; /&amp;gt;
	
	&amp;lt;!-- 파일첨부하려면 반드시, 이름도 반드시 --&amp;gt;
	&amp;lt;beans:bean id=&quot;multipartResolver&quot;
      class=&quot;org.springframework.web.multipart.support.StandardServletMultipartResolver&quot;&amp;gt;
   &amp;lt;/beans:bean&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-Java 설정을 이용하는 경우 p492&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1) &amp;lt;form&amp;gt; 방식의 파일 업로드&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨트롤러&lt;/p&gt;
&lt;pre id=&quot;code_1614142214815&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@GetMapping(&quot;/uploadForm&quot;)
	public void uploadForm() {

		log.info(&quot;upload form&quot;);
	}

	@PostMapping(&quot;/uploadFormAction&quot;)
	public void uploadFormPost(MultipartFile[] uploadFile, Model model) {

		String uploadFolder = &quot;C:\\upload&quot;;

		for (MultipartFile multipartFile : uploadFile) {

			log.info(&quot;-------------------------------------&quot;);
			log.info(&quot;Upload File Name: &quot; + multipartFile.getOriginalFilename());
			log.info(&quot;Upload File Size: &quot; + multipartFile.getSize());

			File saveFile = new File(uploadFolder, multipartFile.getOriginalFilename());

			try {
				multipartFile.transferTo(saveFile);
			} catch (Exception e) {
				log.error(e.getMessage());
			} // end catch
		} // end for

	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;uploadForm.jsp&lt;/p&gt;
&lt;pre id=&quot;code_1614142288328&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
    pageEncoding=&quot;UTF-8&quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;


&amp;lt;form action=&quot;uploadFormAction&quot; method=&quot;post&quot; enctype=&quot;multipart/form-data&quot;&amp;gt;

&amp;lt;input type='file' name='uploadFile' multiple&amp;gt;

&amp;lt;button&amp;gt;Submit&amp;lt;/button&amp;gt;

&amp;lt;/form&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2) Ajax를 이용하는 파일 업로드&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨트롤러&lt;/p&gt;
&lt;pre id=&quot;code_1614142356052&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	@GetMapping(&quot;/uploadAjax&quot;)
	public void uploadAjax() {

		log.info(&quot;upload ajax&quot;);
	}

	@PostMapping(&quot;/uploadAjaxAction&quot;)
	public void uploadAjaxPost(MultipartFile[] uploadFile) {

		log.info(&quot;update ajax post.........&quot;);

		String uploadFolder = &quot;C:\\upload&quot;;

		for (MultipartFile multipartFile : uploadFile) {

			log.info(&quot;-------------------------------------&quot;);
			log.info(&quot;Upload File Name: &quot; + multipartFile.getOriginalFilename());
			log.info(&quot;Upload File Size: &quot; + multipartFile.getSize());

			String uploadFileName = multipartFile.getOriginalFilename();

			// IE has file path
			uploadFileName = uploadFileName.substring(uploadFileName.lastIndexOf(&quot;\\&quot;) +
					1);
			log.info(&quot;only file name: &quot; + uploadFileName);

			File saveFile = new File(uploadFolder, uploadFileName);

			try {

				multipartFile.transferTo(saveFile);
			} catch (Exception e) {
				log.error(e.getMessage());
			} // end catch

		} // end for

	}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;uploadAjax.jsp&lt;/p&gt;
&lt;pre id=&quot;code_1614142378091&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;%@ page language=&quot;java&quot; contentType=&quot;text/html; charset=UTF-8&quot;
	pageEncoding=&quot;UTF-8&quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta http-equiv=&quot;Content-Type&quot; content=&quot;text/html; charset=UTF-8&quot;&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
	&amp;lt;h1&amp;gt;Upload with Ajax&amp;lt;/h1&amp;gt;



	&amp;lt;style&amp;gt;
.uploadResult {
	width: 100%;
	background-color: gray;
}

.uploadResult ul {
	display: flex;
	flex-flow: row;
	justify-content: center;
	align-items: center;
}

.uploadResult ul li {
	list-style: none;
	padding: 10px;
}

.uploadResult ul li img {
	width: 100px;
}
&amp;lt;/style&amp;gt;

&amp;lt;style&amp;gt;
.bigPictureWrapper {
  position: absolute;
  display: none;
  justify-content: center;
  align-items: center;
  top:0%;
  width:100%;
  height:100%;
  background-color: gray; 
  z-index: 100;
}

.bigPicture {
  position: relative;
  display:flex;
  justify-content: center;
  align-items: center;
}
&amp;lt;/style&amp;gt;

&amp;lt;div class='bigPictureWrapper'&amp;gt;
  &amp;lt;div class='bigPicture'&amp;gt;
  &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;


	&amp;lt;div class='uploadDiv'&amp;gt;
		&amp;lt;input type='file' name='uploadFile' multiple&amp;gt;
	&amp;lt;/div&amp;gt;

	&amp;lt;div class='uploadResult'&amp;gt;
		&amp;lt;ul&amp;gt;

		&amp;lt;/ul&amp;gt;
	&amp;lt;/div&amp;gt;


	&amp;lt;button id='uploadBtn'&amp;gt;Upload&amp;lt;/button&amp;gt;

&amp;lt;!-- 그냥 jquery 사용하는 스크립트다 --&amp;gt;
	&amp;lt;script src=&quot;https://code.jquery.com/jquery-3.3.1.min.js&quot;
		integrity=&quot;sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=&quot;
		crossorigin=&quot;anonymous&quot;&amp;gt;&amp;lt;/script&amp;gt;

	&amp;lt;script&amp;gt;

 $(document).ready(function(){
		
		 $(&quot;#uploadBtn&quot;).on(&quot;click&quot;, function(e){

		 var formData = new FormData();
		
		 var inputFile = $(&quot;input[name='uploadFile']&quot;);
		
		 var files = inputFile[0].files;
		
		 console.log(files);
		
		 //add filedate to formdata
		 for(var i = 0; i &amp;lt; files.length; i++){
		 	formData.append(&quot;uploadFile&quot;, files[i]);
		 }

		
		 $.ajax({
		 url: '/uploadAjaxAction',
		 processData: false,
		 contentType: false, // 얘네 두개는 무조건 false줘야하고 의미 몰라도 됨 (필수사항이라고 알기)
		 data: formData,
		 type: 'POST',
		 success: function(result){
		 	alert(&quot;Uploaded&quot;);
		 }
		 }); //$.ajax
		
	 });  
}); 

		

	&amp;lt;/script&amp;gt;


&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;</description>
      <category>Spring</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/313</guid>
      <comments>https://daspace.tistory.com/313#entry313comment</comments>
      <pubDate>Wed, 24 Feb 2021 13:37:02 +0900</pubDate>
    </item>
    <item>
      <title>[days16] 댓글과 댓글 수에 대한 처리</title>
      <link>https://daspace.tistory.com/312</link>
      <description>&lt;p&gt;1. 쿼리 실행&lt;/p&gt;
&lt;pre id=&quot;code_1614141062672&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;alter table tbl_board add (replycnt number default 0);

select * from tbl_board;

update tbl_board
set replycnt = 
	(
	select count(rno) 
    from tbl_reply 
    where tbl_reply.bno = tbl_board.bno
    );

commit;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;댓글수에 대한 컬럼을 추가하고, 기존에 댓글이 있는 게시글의 경우 그 댓글 수로 update하는 작업&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. BoardVO&amp;nbsp;추가&lt;/p&gt;
&lt;pre id=&quot;code_1614141152075&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private int replyCnt; //추가&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;컬럼을 추가했으니 필드도 추가해주자&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;3. BoardMapper.java&lt;/p&gt;
&lt;pre id=&quot;code_1614141188564&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//@Param 알고 있어야
public void updateReplyCnt(@Param(&quot;bno&quot;) Long bno, @Param(&quot;amount&quot;) int amount);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;댓글 수를 update하는 메소드&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4. BoardMapper.xml&lt;/p&gt;
&lt;pre id=&quot;code_1614141229295&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	&amp;lt;update id=&quot;updateReplyCnt&quot;&amp;gt;
    	update tbl_board 
    	set replycnt = replycnt + #{amount} 
    	where bno = #{bno}
  	&amp;lt;/update&amp;gt;  &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;5. replyServiceImpl&lt;/p&gt;
&lt;p&gt;-&amp;nbsp; &amp;nbsp;private BoardMapper boardMapper; 추가 &lt;br /&gt;-&amp;nbsp;&amp;nbsp;@Transactional&amp;nbsp;댓글&amp;nbsp;추가,&amp;nbsp;삭제&amp;nbsp;&amp;nbsp;메소드&amp;nbsp;변경&amp;nbsp;(댓글수&amp;nbsp;증가하는&amp;nbsp;작업)&lt;/p&gt;
&lt;pre id=&quot;code_1614141287703&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zerock.domain.Criteria;
import org.zerock.domain.ReplyPageDTO;
import org.zerock.domain.ReplyVO;
import org.zerock.mapper.BoardMapper;
import org.zerock.mapper.ReplyMapper;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

// p.390
@Service
@Log4j
@AllArgsConstructor
public class ReplyServiceImpl implements ReplyService {
  
  private ReplyMapper mapper;  //@AllArgsConstructor 생성자에 의해 자동 주입(DI) 
  
  private BoardMapper boardMapper;
  
  //댓글은 전부 ajax
	@Transactional
	@Override
	public int register(ReplyVO vo) {

		log.info(&quot;register......&quot; + vo);

		boardMapper.updateReplyCnt(vo.getBno(), 1);

		return mapper.insert(vo);

	}	
  @Override
  public ReplyVO get(Long rno) {
    log.info(&quot;get......&quot; + rno);
    return mapper.read(rno);
  }

  @Override
  public int modify(ReplyVO vo) {
    log.info(&quot;modify......&quot; + vo);
    return mapper.update(vo);
  }

	@Transactional
	@Override
	public int remove(Long rno) {

		log.info(&quot;remove....&quot; + rno);

		ReplyVO vo = mapper.read(rno);

		boardMapper.updateReplyCnt(vo.getBno(), -1);
		return mapper.delete(rno);

	}

  @Override
  public List&amp;lt;ReplyVO&amp;gt; getList(Criteria cri, Long bno) {
    log.info(&quot;get Reply List of a Board &quot; + bno);
    return mapper.getListWithPaging(cri, bno);
  }
  
 
  @Override
  public ReplyPageDTO getListPage(Criteria cri, Long bno) {
    return new ReplyPageDTO(
        mapper.getCountByBno(bno), 
        mapper.getListWithPaging(cri, bno));
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;private BoardMapper boardMapper 필드를 추가하고&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;댓글 추가, 삭제 메소드에 @Transaction을 삽입해 트랜잭션이 이루어지도록 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;6. list.jsp에서 댓글 수를 출력해 타이틀 옆에 띄우는 코딩&lt;/p&gt;
&lt;pre id=&quot;code_1614141375572&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;b&amp;gt;[  &amp;lt;c:out value=&quot;${board.replyCnt}&quot; /&amp;gt;  ]&amp;lt;/b&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/312</guid>
      <comments>https://daspace.tistory.com/312#entry312comment</comments>
      <pubDate>Wed, 24 Feb 2021 13:36:18 +0900</pubDate>
    </item>
    <item>
      <title>[days16] AOP와 트랜잭션</title>
      <link>https://daspace.tistory.com/311</link>
      <description>&lt;p&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;AOP&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;AOP는 '관심사의 분리'를 추구한다. 예를 들어 나눗셈을 구현한다고 하면 '핵심 로직'은 두 개의 숫자를 나누는 것이지만, '주변 로직'은 0을 나누는 것ㅇ이 아닌지 등을 체크하는 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;AOP는 과거에 개발자가 작성했던 '관심사 + 비즈니스 로직'을 분리해서 별도의 코드로 작성하도록 하고, 실행할 때 이를 결합하는 방식으로 접근한다. 실제 실행은 결합된 상태의 코드가 실행되므로 개발자들은 핵심 비즈니스 로직에만 근거하여 코드를 작성하고, 나머지는 어떤 관심사들과 결합할 것인지를 설정하는 것 만으로 모든 개발을 마칠 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예제&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. pom.xml&lt;/b&gt;에 스프링 버전과 AOP 버전을 수정, 라이브러리 추가&lt;/p&gt;
&lt;p&gt;&amp;nbsp; - 스프링AOP는 AspectJ라는 라이브러리의 도움을 많이 받음&lt;/p&gt;
&lt;pre id=&quot;code_1614138790776&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;project xmlns=&quot;http://maven.apache.org/POM/4.0.0&quot;
   xmlns:xsi=&quot;http://www.w3.org/2001/XMLSchema-instance&quot;
   xsi:schemaLocation=&quot;http://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd&quot;&amp;gt;
   &amp;lt;modelVersion&amp;gt;4.0.0&amp;lt;/modelVersion&amp;gt;
   &amp;lt;groupId&amp;gt;org.zerock&amp;lt;/groupId&amp;gt;
   &amp;lt;artifactId&amp;gt;controller&amp;lt;/artifactId&amp;gt;
   &amp;lt;name&amp;gt;ex04&amp;lt;/name&amp;gt;
   &amp;lt;packaging&amp;gt;war&amp;lt;/packaging&amp;gt;
   &amp;lt;version&amp;gt;1.0.0-BUILD-SNAPSHOT&amp;lt;/version&amp;gt;
   &amp;lt;properties&amp;gt;
      &amp;lt;java-version&amp;gt;1.8&amp;lt;/java-version&amp;gt;
      &amp;lt;org.springframework-version&amp;gt;5.0.7.RELEASE&amp;lt;/org.springframework-version&amp;gt;
      &amp;lt;org.aspectj-version&amp;gt;1.9.0&amp;lt;/org.aspectj-version&amp;gt;
      &amp;lt;org.slf4j-version&amp;gt;1.7.25&amp;lt;/org.slf4j-version&amp;gt;
   &amp;lt;/properties&amp;gt;
   &amp;lt;dependencies&amp;gt;
      &amp;lt;!-- Spring --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-context&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
         &amp;lt;exclusions&amp;gt;
            &amp;lt;!-- Exclude Commons Logging in favor of SLF4j --&amp;gt;
            &amp;lt;exclusion&amp;gt;
               &amp;lt;groupId&amp;gt;commons-logging&amp;lt;/groupId&amp;gt;
               &amp;lt;artifactId&amp;gt;commons-logging&amp;lt;/artifactId&amp;gt;
            &amp;lt;/exclusion&amp;gt;
         &amp;lt;/exclusions&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-webmvc&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- AspectJ --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.aspectj&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;aspectjrt&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.aspectj-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- Logging --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;slf4j-api&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.slf4j-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jcl-over-slf4j&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.slf4j-version}&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.slf4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;slf4j-log4j12&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.slf4j-version}&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;!-- p.54 &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt; &amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt; 
         &amp;lt;version&amp;gt;1.2.15&amp;lt;/version&amp;gt; &amp;lt;exclusions&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;javax.mail&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;mail&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;javax.jms&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;jms&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;com.sun.jdmk&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;jmxtools&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;exclusion&amp;gt; &amp;lt;groupId&amp;gt;com.sun.jmx&amp;lt;/groupId&amp;gt; 
         &amp;lt;artifactId&amp;gt;jmxri&amp;lt;/artifactId&amp;gt; &amp;lt;/exclusion&amp;gt; &amp;lt;/exclusions&amp;gt; &amp;lt;scope&amp;gt;runtime&amp;lt;/scope&amp;gt; 
         &amp;lt;/dependency&amp;gt; --&amp;gt;
      &amp;lt;!-- @Inject --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.inject&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;javax.inject&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- Servlet --&amp;gt;
      &amp;lt;!-- &amp;lt;dependency&amp;gt; &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt; &amp;lt;artifactId&amp;gt;servlet-api&amp;lt;/artifactId&amp;gt; 
         &amp;lt;version&amp;gt;2.5&amp;lt;/version&amp;gt; &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt; &amp;lt;/dependency&amp;gt; --&amp;gt;
      &amp;lt;!-- p.111 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;javax.servlet-api&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;3.1.0&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.servlet.jsp&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jsp-api&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.1&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;javax.servlet&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jstl&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.2&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- Test p.54 --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;junit&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;junit&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;4.12&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;test&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p.54 --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-test&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.projectlombok&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;lombok&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.18.18&amp;lt;/version&amp;gt;
         &amp;lt;scope&amp;gt;provided&amp;lt;/scope&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;&amp;lt;!-- log4j.xml 설정 필요(자동) --&amp;gt;
         &amp;lt;groupId&amp;gt;log4j&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;log4j&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.2.17&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p.83 https://github.com/brettwooldridge/HiKariCP --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.zaxxer&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;HikariCP&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;4.0.2&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 90 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/org.mybatis/mybatis --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.mybatis&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;mybatis&amp;lt;/artifactId&amp;gt;
         &amp;lt;!-- &amp;lt;version&amp;gt;3.4.6&amp;lt;/version&amp;gt; --&amp;gt;
         &amp;lt;version&amp;gt;3.5.6&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.mybatis&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;mybatis-spring&amp;lt;/artifactId&amp;gt;
         &amp;lt;!-- &amp;lt;version&amp;gt;1.3.2&amp;lt;/version&amp;gt; --&amp;gt;
         &amp;lt;version&amp;gt;2.0.6&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-tx&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-jdbc&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 101 --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.bgee.log4jdbc-log4j2&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;log4jdbc-log4j2-jdbc4&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.16&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 147 jackson-databind --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.fasterxml.jackson.core&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jackson-databind&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.12.1&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 149 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;commons-fileupload&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;commons-fileupload&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;1.4&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 357 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.dataformat/jackson-dataformat-xml --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.fasterxml.jackson.dataformat&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jackson-dataformat-xml&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.12.1&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- p 357 Java 인스턴스를 JSON 타입의 문자열로 변환 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/com.google.code.gson/gson --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.google.code.gson&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;gson&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.8.6&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

&amp;lt;!-- AOP 중요 --&amp;gt;
      &amp;lt;!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.aspectj&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;aspectjweaver&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.aspectj-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/net.coobird/thumbnailator --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;net.coobird&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;thumbnailator&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;0.4.8&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.quartz-scheduler&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;quartz&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.3.0&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/org.quartz-scheduler/quartz-jobs --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.quartz-scheduler&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;quartz-jobs&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.3.0&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-web&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-config&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-core&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;

      &amp;lt;!-- https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;org.springframework.security&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;spring-security-taglibs&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;${org.springframework-version}&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
   &amp;lt;/dependencies&amp;gt;
   &amp;lt;build&amp;gt;
      &amp;lt;plugins&amp;gt;
         &amp;lt;plugin&amp;gt;
            &amp;lt;artifactId&amp;gt;maven-eclipse-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;2.9&amp;lt;/version&amp;gt;
            &amp;lt;configuration&amp;gt;
               &amp;lt;additionalProjectnatures&amp;gt;
                  &amp;lt;projectnature&amp;gt;org.springframework.ide.eclipse.core.springnature&amp;lt;/projectnature&amp;gt;
               &amp;lt;/additionalProjectnatures&amp;gt;
               &amp;lt;additionalBuildcommands&amp;gt;
                  &amp;lt;buildcommand&amp;gt;org.springframework.ide.eclipse.core.springbuilder&amp;lt;/buildcommand&amp;gt;
               &amp;lt;/additionalBuildcommands&amp;gt;
               &amp;lt;downloadSources&amp;gt;true&amp;lt;/downloadSources&amp;gt;
               &amp;lt;downloadJavadocs&amp;gt;true&amp;lt;/downloadJavadocs&amp;gt;
            &amp;lt;/configuration&amp;gt;
         &amp;lt;/plugin&amp;gt;
         &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.apache.maven.plugins&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;maven-compiler-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;3.5.1&amp;lt;/version&amp;gt;
            &amp;lt;configuration&amp;gt;
               &amp;lt;source&amp;gt;1.8&amp;lt;/source&amp;gt;
               &amp;lt;target&amp;gt;1.8&amp;lt;/target&amp;gt;
               &amp;lt;compilerArgument&amp;gt;-Xlint:all&amp;lt;/compilerArgument&amp;gt;
               &amp;lt;showWarnings&amp;gt;true&amp;lt;/showWarnings&amp;gt;
               &amp;lt;showDeprecation&amp;gt;true&amp;lt;/showDeprecation&amp;gt;
            &amp;lt;/configuration&amp;gt;
         &amp;lt;/plugin&amp;gt;
         &amp;lt;plugin&amp;gt;
            &amp;lt;groupId&amp;gt;org.codehaus.mojo&amp;lt;/groupId&amp;gt;
            &amp;lt;artifactId&amp;gt;exec-maven-plugin&amp;lt;/artifactId&amp;gt;
            &amp;lt;version&amp;gt;1.2.1&amp;lt;/version&amp;gt;
            &amp;lt;configuration&amp;gt;
               &amp;lt;mainClass&amp;gt;org.test.int1.Main&amp;lt;/mainClass&amp;gt;
            &amp;lt;/configuration&amp;gt;
         &amp;lt;/plugin&amp;gt;
      &amp;lt;/plugins&amp;gt;
   &amp;lt;/build&amp;gt;
&amp;lt;/project&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. 서비스 계층 설계&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;SampleService 인터페이스&lt;/p&gt;
&lt;pre id=&quot;code_1614138848012&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

public interface SampleService {

  public Integer doAdd(String str1, String str2)throws Exception;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;SampleServiceImpl&lt;/p&gt;
&lt;pre id=&quot;code_1614138881697&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

import org.springframework.stereotype.Service;

@Service
public class SampleServiceImpl implements SampleService {

	@Override
	public Integer doAdd(String str1, String str2) throws Exception {

		return Integer.parseInt(str1) + Integer.parseInt(str2);

	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. Advice 작성&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;위의 &lt;span style=&quot;color: #333333;&quot;&gt;SampleServiceImpl 코드를 보면 기존에 항상 하던 log.info()가 빠져있다. 지금까지 해왔던, 로그를 기록해 오던 일은 '반복적이면서 핵심 로직도 아니고, 필요하기는 한 기능'이기 때문에 '관심사'라고 볼 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;로그를 기록해주는 LogAdvice를 설계해보자&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;org.zerock.aop에 LogAdvice.java 생성&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614139067384&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.aop;

import java.util.Arrays;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import lombok.extern.log4j.Log4j;

@Aspect //보조 기능을 하는 구현 클래스
@Log4j  //로그 기록 
@Component // 컴포넌트 스캔
public class LogAdvice {

  @Before( &quot;execution(* org.zerock.service.SampleService*.*(..))&quot;) //AspectJ 문법
  public void logBefore() {

    log.info(&quot;========================&quot;);
  }
  
  @Before(&quot;execution(* org.zerock.service.SampleService*.doAdd(String, String)) &amp;amp;&amp;amp; args(str1, str2)&quot;)
  public void logBeforeWithParam(String str1, String str2) {

    log.info(&quot;str1: &quot; + str1);
    log.info(&quot;str2: &quot; + str2);
  }  
  //before두개면 다 실행

  @AfterThrowing(pointcut = &quot;execution(* org.zerock.service.SampleService*.*(..))&quot;, throwing=&quot;exception&quot;)
  public void logException(Exception exception) {
    
    log.info(&quot;Exception....!!!!&quot;);
    log.info(&quot;exception: &quot;+ exception);
  
  }
  
  
  @Around(&quot;execution(* org.zerock.service.SampleService*.*(..))&quot;)
  public Object logTime( ProceedingJoinPoint pjp) {
    
    long start = System.currentTimeMillis();
    
    log.info(&quot;Target: &quot; + pjp.getTarget());
    log.info(&quot;Param: &quot; + Arrays.toString(pjp.getArgs()));
    
    
    //invoke method 
    Object result = null;
    
    try {
      result = pjp.proceed();
    } catch (Throwable e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    
    long end = System.currentTimeMillis();
    
    log.info(&quot;TIME: &quot;  + (end - start));
    
    return result;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. AOP 설정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;스프링 프로젝트에 AOP를 설정하는 것은 스프링 2버전 이후에는 간단히 자동으로 Proxy 객체를 만들어주는 설정을 추가해주면 된다.&lt;/p&gt;
&lt;p&gt;프로젝트의 root-context.xml에서 Namespaces에 aop와 context를 추가하고 아래 코딩을 추가하자&lt;/p&gt;
&lt;pre id=&quot;code_1614139260723&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   &amp;lt;!-- p.455 --&amp;gt;
   &amp;lt;context:annotation-config&amp;gt;&amp;lt;/context:annotation-config&amp;gt;   
   &amp;lt;context:component-scan base-package=&quot;org.zerock.service&quot; /&amp;gt;
   &amp;lt;context:component-scan base-package=&quot;org.zerock.aop&quot; /&amp;gt;   
   &amp;lt;aop:aspectj-autoproxy&amp;gt;&amp;lt;/aop:aspectj-autoproxy&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;컴포넌트 스캔을 통해 패키지들을 스캔하고, 이 과정에서 SampleServiceImpl 클래스와 LogAdvice가 스프링의 빈으로 등록된다. &amp;lt;aop:aspectj-autoproxy&amp;gt;를 이용해 LogAdvice에 설정한 @들이 동작하게 된다.&lt;/p&gt;
&lt;p&gt;-Java 설정을 이용하는 경우 p456&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. AOP 테스트&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;정상적인 상황이라면 SampleServiceImpl, LogAdvice는 같이 묶여서 자동으로 Proxy 객체가 생성된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;테스트 폴더에 SampleServiceTests 추가&lt;/p&gt;
&lt;pre id=&quot;code_1614139477474&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@Log4j
@ContextConfiguration({ &quot;file:src/main/webapp/WEB-INF/spring/root-context.xml&quot; })
//Java설정의 경우 
//@ContextConfiguration(classes= {RootConfig.class})
public class SampleServiceTests {

  //@Setter(onMethod = @__({ @Autowired }))
  @Setter(onMethod_ = @Autowired)
  private SampleService service;
  
  
  @Test
  public void testClass() {
    //보조기능 출력
    log.info(service);
    log.info(service.getClass().getName());     
    
  }
  
  @Test
  public void testAdd() throws Exception {
    
    log.info(service.doAdd(&quot;123&quot;, &quot;456&quot;));
    
  }
  
  @Test
  public void testAddError() throws Exception {
    
    log.info(service.doAdd(&quot;123&quot;, &quot;ABC&quot;));
    
  }  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eu7wlN/btqYhzehJh2/HqAg4d877Dwh6S2HnRrEk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eu7wlN/btqYhzehJh2/HqAg4d877Dwh6S2HnRrEk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eu7wlN/btqYhzehJh2/HqAg4d877Dwh6S2HnRrEk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Feu7wlN%2FbtqYhzehJh2%2FHqAg4d877Dwh6S2HnRrEk0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;스프링에서 트랜잭션 관리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;스프링 트랜잭션 설정은 AOP와 같이 XML을 이용해서 설정하거나 어노테이션을 이용해서 설정이 가능하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. pom.xml&lt;/b&gt;에 라이브러리 추가 - spring-jdbc, spring-tx, mybatis, mybatis-spring, hikari 등&lt;/p&gt;
&lt;p&gt;(위 pom.xml과 동일)&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. root-context.xml&lt;/b&gt;에는 Namespaces 탭에서 tx 항목 체크 아래 태그 등록&lt;/p&gt;
&lt;pre id=&quot;code_1614140556839&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;tx:annotation-driven /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;: 어노테이션 기반으로 트랜잭션을 설정할 수 있도록 함&lt;/p&gt;
&lt;p&gt;-Java 설정을 이용한 트랜잭션 설정 p470&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 예제 테이블 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614140648762&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;create table tbl_sample1(col1 varchar2(500));
create table tbl_sample2(col2 varchar2(50));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sample1MApper - tbl_sample1 테이블에 데이터 삽입하는 메소드&lt;/p&gt;
&lt;pre id=&quot;code_1614140697715&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.mapper;

import org.apache.ibatis.annotations.Insert;

public interface Sample1Mapper {

	@Insert(&quot;insert into tbl_sample1 (col1) values (#{data}) &quot;)
	public int insertCol1(String data);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Sample2Mapper&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;- tbl_sample2 테이블에 데이터 삽입하는 메소드&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614140707854&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.mapper;

import org.apache.ibatis.annotations.Insert;

public interface Sample2Mapper {

	@Insert(&quot;insert into tbl_sample2 (col2) values (#{data}) &quot;)
	public int insertCol2(String data);

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. 비즈니스 계층과 트랜잭션 설정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;트랜잭션은 비즈니스 계층에서 이루어지므로, org.zerock.service 계층에서 Sample1Mapper, Sample2Mapper를 사용하는 SampleTxService, SampleTxServiceImpl 클래스 설계&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;SampleTxService&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614140826869&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

public interface SampleTxService {

	public void addData(String value);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;SampleTxServiceImpl&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614140848066&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.zerock.mapper.Sample1Mapper;
import org.zerock.mapper.Sample2Mapper;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@Service
@Log4j
public class SampleTxServiceImpl implements SampleTxService {

  @Setter(onMethod_ = { @Autowired })
  private Sample1Mapper mapper1;
  
  @Setter(onMethod_ = { @Autowired })
  private Sample2Mapper mapper2;
  
  @Transactional
  @Override
  public void addData(String value) { //마크: 내부적으로 AOP 처리된다는 의미
    
    log.info(&quot;mapper1....................&quot;);
    mapper1.insertCol1(value);
    
    log.info(&quot;mapper2.....................&quot;);
    mapper2.insertCol2(value);
    
    log.info(&quot;end..........................&quot;);
    //insert 작업을 2번 하는 동안 @트랜잭션 걸었음
    // 하나라도 잘못되면 전부 롤백되는지 확인 (O)
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. Test&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614140899326&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@Log4j
@ContextConfiguration({ &quot;file:src/main/webapp/WEB-INF/spring/root-context.xml&quot; })
//Java설정의 경우 
//@ContextConfiguration(classes= {RootConfig.class})

public class SampleTxServiceTests {

  @Setter(onMethod_ = { @Autowired })
  private SampleTxService service;
  
  
  

  @Test
  public void testLong() {
/*    
    String str =&quot;Starry\r\n&quot; + 
        &quot;Starry night\r\n&quot; + 
        &quot;Paint your palette blue and grey\r\n&quot; + 
        &quot;Look out on a summer's day&quot;;
 */
	  
	    String str =&quot;Starry&quot;;
    log.info(&quot;길이: &quot;+str.getBytes().length); 
    
    service.addData(str);    
    //위 글이 50바이트보다 크면 샘플2에 안들어가져서 트랜잭션에 의해 둘 다 롤백
    //작으면 커밋 (두 테이블 모두 잘 들어감)
  }
  
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;@Transaction 어노테이션에 의해 트랜잭션 처리가 잘 된다.&lt;/p&gt;</description>
      <category>Spring</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/311</guid>
      <comments>https://daspace.tistory.com/311#entry311comment</comments>
      <pubDate>Wed, 24 Feb 2021 13:10:08 +0900</pubDate>
    </item>
    <item>
      <title>[days15] Ajax 댓글 처리</title>
      <link>https://daspace.tistory.com/310</link>
      <description>&lt;p&gt;&lt;b&gt;ex03_02&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1.&amp;nbsp;properties&amp;nbsp;파일&amp;nbsp;존재&amp;nbsp;여부&amp;nbsp;확인 &lt;br /&gt;2.&amp;nbsp;ojdbc.jar&amp;nbsp;확인 &lt;br /&gt;3.&amp;nbsp;developer &lt;br /&gt;&lt;br /&gt;create&amp;nbsp;table&amp;nbsp;tbl_reply&amp;nbsp;( &lt;br /&gt;&amp;nbsp;&amp;nbsp;rno&amp;nbsp;number(10,0),&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;bno&amp;nbsp;number(10,0)&amp;nbsp;not&amp;nbsp;null, &lt;br /&gt;&amp;nbsp;&amp;nbsp;reply&amp;nbsp;varchar2(1000)&amp;nbsp;not&amp;nbsp;null, &lt;br /&gt;&amp;nbsp;&amp;nbsp;replyer&amp;nbsp;varchar2(50)&amp;nbsp;not&amp;nbsp;null,&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;replyDate&amp;nbsp;date&amp;nbsp;default&amp;nbsp;sysdate,&amp;nbsp; &lt;br /&gt;&amp;nbsp;&amp;nbsp;updateDate&amp;nbsp;date&amp;nbsp;default&amp;nbsp;sysdate &lt;br /&gt;); &lt;br /&gt;&lt;br /&gt;create&amp;nbsp;sequence&amp;nbsp;seq_reply; &lt;br /&gt;&lt;br /&gt;alter&amp;nbsp;table&amp;nbsp;tbl_reply&amp;nbsp;add&amp;nbsp;constraint&amp;nbsp;pk_reply&amp;nbsp;primary&amp;nbsp;key&amp;nbsp;(rno); &lt;br /&gt;&lt;br /&gt;alter&amp;nbsp;table&amp;nbsp;tbl_reply&amp;nbsp;&amp;nbsp;add&amp;nbsp;constraint&amp;nbsp;fk_reply_board&amp;nbsp;&amp;nbsp; &lt;br /&gt;foreign&amp;nbsp;key&amp;nbsp;(bno)&amp;nbsp;&amp;nbsp;references&amp;nbsp;&amp;nbsp;tbl_board&amp;nbsp;(bno);&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4.&amp;nbsp;ReplyVO&amp;nbsp;생성&lt;/p&gt;
&lt;pre id=&quot;code_1614079417113&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.domain;

import java.util.Date;

import lombok.Data;

@Data
public class ReplyVO {

  private Long rno;
  private Long bno;

  private String reply;
  private String replyer;
  private Date replyDate;
  private Date updateDate;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5. ReplyMapper.java 생성&lt;/p&gt;
&lt;pre id=&quot;code_1614079447441&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.mapper;

import java.util.List;

import org.apache.ibatis.annotations.Param;
import org.zerock.domain.Criteria;
import org.zerock.domain.ReplyVO;

public interface ReplyMapper {

	public int insert(ReplyVO vo);

	public ReplyVO read(Long bno);

	public int delete(Long bno);

	public int update(ReplyVO reply);

	//P378 @Param 설명 	MyBatis의 @Param 기억   @Param(&quot;bno&quot;) -&amp;gt;#{bno}
	public List&amp;lt;ReplyVO&amp;gt; getListWithPaging(@Param(&quot;cri&quot;) Criteria cri, @Param(&quot;bno&quot;) Long bno);
	//게시글에 대한 총 댓글 수를 반환하는 메소드
	public int getCountByBno(Long bno);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;6. ReplyMapper.xml 생성&lt;/p&gt;
&lt;pre id=&quot;code_1614079494212&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
&amp;lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&amp;gt;
&amp;lt;mapper namespace=&quot;org.zerock.mapper.ReplyMapper&quot;&amp;gt;

	&amp;lt;insert id=&quot;insert&quot;&amp;gt;
		insert into tbl_reply (rno, bno, reply, replyer)
		values (seq_reply.nextval, #{bno}, #{reply}, #{replyer})
	&amp;lt;/insert&amp;gt;

	&amp;lt;select id=&quot;read&quot; resultType=&quot;org.zerock.domain.ReplyVO&quot;&amp;gt;
		select *
		from tbl_reply
		where rno = #{rno}
	&amp;lt;/select&amp;gt;
	
	&amp;lt;delete id=&quot;delete&quot;&amp;gt;
      delete from tbl_reply 
      where rno = #{rno}
   &amp;lt;/delete&amp;gt;

   &amp;lt;update id=&quot;update&quot;&amp;gt;
      update tbl_reply 
      set reply = #{reply},updatedate = sysdate
      where rno = #{rno}
   &amp;lt;/update&amp;gt;
   
   &amp;lt;select id=&quot;getListWithPaging&quot;
      resultType=&quot;org.zerock.domain.ReplyVO&quot;&amp;gt;

     &amp;lt;![CDATA[
       select  rno, bno, reply, replyer, replydate, updatedate
       from 
         (
          select /*+INDEX(tbl_reply idx_reply) */ 
            rownum rn,  rno, bno, reply, replyer, replyDate, updatedate
          from tbl_reply
          where bno =  #{bno}          
             and rno &amp;gt; 0
             and rownum &amp;lt;= #{cri.pageNum} * #{cri.amount}
         ) where rn &amp;gt; (#{cri.pageNum} -1) * #{cri.amount}
   ]]&amp;gt;

   &amp;lt;/select&amp;gt;


   &amp;lt;select id=&quot;getCountByBno&quot; resultType=&quot;int&quot;&amp;gt;
      &amp;lt;![CDATA[
      select  count(rno) 
      from  tbl_reply 
      where  bno = #{bno}
      ]]&amp;gt;
   &amp;lt;/select&amp;gt;
&amp;lt;/mapper&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;7. 단위테스트&lt;/p&gt;
&lt;pre id=&quot;code_1614079529360&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.mapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(&quot;file:src/main/webapp/WEB-INF/spring/root-context.xml&quot;) 
@Log4j
public class ReplyMapperTests {
   
   @Setter(onMethod_ = @Autowired)
   private ReplyMapper mapper;

   @Test
   public void testMapper() {

      log.info(this.mapper);

   }
   
   
      
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;8. @Param 어노테이션에 대한 이해 &lt;br /&gt;MyBatis는&amp;nbsp;두&amp;nbsp;개&amp;nbsp;이상의&amp;nbsp;데이터를&amp;nbsp;파라미터로&amp;nbsp;전달하기&amp;nbsp;위해서는 &lt;br /&gt;1)&amp;nbsp;별도의&amp;nbsp;객체로&amp;nbsp;구성하거나&amp;nbsp;2)Map을&amp;nbsp;이용하거나&amp;nbsp;3)&amp;nbsp;Param을&amp;nbsp;이용해&amp;nbsp;이름을&amp;nbsp;사용&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;9. ReplyService 인터페이스 생성&lt;/p&gt;
&lt;pre id=&quot;code_1614079591600&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.service;

import java.util.List;

import org.zerock.domain.Criteria;
import org.zerock.domain.ReplyPageDTO;
//import org.zerock.domain.ReplyPageDTO;
import org.zerock.domain.ReplyVO;

// p.389
public interface ReplyService {

   public int register(ReplyVO vo);

   public ReplyVO get(Long rno);

   public int modify(ReplyVO vo);

   public int remove(Long rno);

   public List&amp;lt;ReplyVO&amp;gt; getList(Criteria cri, Long bno); //댓글 목록만 돌릴게 아니라
   
   // List&amp;lt;ReplyVO&amp;gt; + replyCnt = ReplyPageDTO
   public ReplyPageDTO getListPage(Criteria cri, Long bno); //댓글 수도 같이 돌리기

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;10. ReplyPageDTO 생성&lt;/p&gt;
&lt;pre id=&quot;code_1614079607327&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.domain;

import java.util.List;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.Getter;

@Data
@AllArgsConstructor
@Getter
public class ReplyPageDTO {

  private int replyCnt; //해당 게시글의 총 댓글 수 저장할 필드
  private List&amp;lt;ReplyVO&amp;gt; list;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;11. 컨트롤러의 설계 &lt;br /&gt;등록&amp;nbsp; &lt;br /&gt;조회 &lt;br /&gt;삭제 &lt;br /&gt;수정 &lt;br /&gt;페이지 &lt;br /&gt;컨트롤러&amp;nbsp;생성&lt;/p&gt;
&lt;pre id=&quot;code_1614079635833&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.controller;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.domain.Criteria;
import org.zerock.domain.ReplyPageDTO;
import org.zerock.domain.ReplyVO;
import org.zerock.service.ReplyService;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

// p.392
@RestController //@Controller가 아니고 @RestController (jsp요청아니라 xml이나 json이나 일반 텍스트를 요청하겠다는 의미)
@RequestMapping(&quot;/replies/&quot;)
@Log4j
@AllArgsConstructor
public class ReplyController {
   private ReplyService service;

   //	 /replies/new + POST -&amp;gt; 댓글 등록 
   @PostMapping(value = &quot;/new&quot;
         , consumes = &quot;application/json&quot; //  json형태로 입력해서
         , produces = { MediaType.TEXT_PLAIN_VALUE }) //돌려주는 값은 일반 텍스트 문자열 (응답)
   public ResponseEntity&amp;lt;String&amp;gt; create(@RequestBody ReplyVO vo) {

      log.info(&quot;ReplyVO: &quot; + vo);

      int insertCount = service.register(vo); //댓글 db에 저장

      log.info(&quot;Reply INSERT COUNT: &quot; + insertCount);

      return insertCount == 1   //영향받은 레코드값
    		  	  ?  new ResponseEntity&amp;lt;&amp;gt;(&quot;success&quot;, HttpStatus.OK) //얘로 응답
                  :  new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.INTERNAL_SERVER_ERROR);
   }

   
   //	 /replies/41 + GET -&amp;gt; 댓글 조회
   @GetMapping(value = &quot;/{rno}&quot;,  //여기 번호가 @PathVariable에 들어감
         produces = { MediaType.APPLICATION_XML_VALUE,  
               MediaType.APPLICATION_JSON_UTF8_VALUE }) //쓰고싶은대로
   public ResponseEntity&amp;lt;ReplyVO&amp;gt; get(@PathVariable(&quot;rno&quot;) Long rno) {

      log.info(&quot;get: &quot; + rno);

      return new ResponseEntity&amp;lt;&amp;gt;(service.get(rno), HttpStatus.OK);
   }

   
   //	 /replies/41 + PUT또는PATCH -&amp;gt; 댓글 수정
   @RequestMapping(method = { RequestMethod.PUT, RequestMethod.PATCH }
   , value = &quot;/{rno}&quot;
         , consumes = &quot;application/json&quot; //수정하고자하는 새로입력받은 데이터는 json
         , produces = {   MediaType.TEXT_PLAIN_VALUE    }) 
   public ResponseEntity&amp;lt;String&amp;gt; modify(
         @RequestBody ReplyVO vo, 
         @PathVariable(&quot;rno&quot;) Long rno) {

      vo.setRno(rno);

      log.info(&quot;rno: &quot; + rno);
      log.info(&quot;modify: &quot; + vo);

      return service.modify(vo) == 1 
            ? new ResponseEntity&amp;lt;&amp;gt;(&quot;success&quot;, HttpStatus.OK)
                  : new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.INTERNAL_SERVER_ERROR);

   }

   //@DeleteMapping + /replies/41 		댓글 삭제 
   @DeleteMapping(value = &quot;/{rno}&quot;, produces = { MediaType.TEXT_PLAIN_VALUE })
   public ResponseEntity&amp;lt;String&amp;gt; remove(@PathVariable(&quot;rno&quot;) Long rno) {

      log.info(&quot;remove: &quot; + rno);

      return service.remove(rno) == 1 
            ? new ResponseEntity&amp;lt;&amp;gt;(&quot;success&quot;, HttpStatus.OK)
                  : new ResponseEntity&amp;lt;&amp;gt;(HttpStatus.INTERNAL_SERVER_ERROR);

   }

   /*
   @GetMapping(value = &quot;/pages/{bno}/{page}&quot;, 
            produces = {
                     MediaType.APPLICATION_XML_VALUE,
                     MediaType.APPLICATION_JSON_UTF8_VALUE 
                     })
   public ResponseEntity&amp;lt;List&amp;lt;ReplyVO&amp;gt;&amp;gt; getList(
         @PathVariable(&quot;page&quot;) int page,
         @PathVariable(&quot;bno&quot;) Long bno) {


      log.info(&quot;getList.................&quot;);
      Criteria cri = new Criteria(page,10);
      log.info(cri);

      return new ResponseEntity&amp;lt;&amp;gt;(service.getList(cri, bno), HttpStatus.OK);
   }
   */

   //	 
   @GetMapping(value = &quot;/pages/{bno}/{page}&quot;, 
            produces = { MediaType.APPLICATION_XML_VALUE,
                     MediaType.APPLICATION_JSON_UTF8_VALUE })
   public ResponseEntity&amp;lt;ReplyPageDTO&amp;gt; getList(@PathVariable(&quot;page&quot;) int page, @PathVariable(&quot;bno&quot;) Long bno) {

      Criteria cri = new Criteria(page, 10);

      log.info(&quot;get Reply List bno: &quot; + bno);

      log.info(&quot;cri:&quot; + cri);

      return new ResponseEntity&amp;lt;&amp;gt;(service.getListPage(cri, bno), HttpStatus.OK);
   }
    

}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;12. get.jsp&lt;/p&gt;
&lt;pre id=&quot;code_1614079694115&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; prefix=&quot;fmt&quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  
  &amp;lt;div class=&quot;panel panel-default&quot;&amp;gt;
   &amp;lt;h3&amp;gt;Board Read - p.251&amp;lt;/h3&amp;gt;
   
         &amp;lt;!-- /.panel-heading --&amp;gt;
       &amp;lt;div class=&quot;panel-body&quot;&amp;gt;

          &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Bno&amp;lt;/label&amp;gt; &amp;lt;input class=&quot;form-control&quot; name='bno'
            value='&amp;lt;c:out value=&quot;${board.bno }&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Title&amp;lt;/label&amp;gt; &amp;lt;input class=&quot;form-control&quot; name='title'
            value='&amp;lt;c:out value=&quot;${board.title }&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Text area&amp;lt;/label&amp;gt;
          &amp;lt;textarea class=&quot;form-control&quot; rows=&quot;3&quot; name='content'
            readonly=&quot;readonly&quot;&amp;gt;&amp;lt;c:out value=&quot;${board.content}&quot; /&amp;gt;&amp;lt;/textarea&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Writer&amp;lt;/label&amp;gt; &amp;lt;input class=&quot;form-control&quot; name='writer'
            value='&amp;lt;c:out value=&quot;${board.writer }&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;
        &amp;lt;/div&amp;gt;
&amp;lt;%-- 
        &amp;lt;button data-oper='modify' class=&quot;btn btn-default&quot;&amp;gt;
        &amp;lt;a href=&quot;/board/modify?bno=&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;&quot;&amp;gt;Modify&amp;lt;/a&amp;gt;&amp;lt;/button&amp;gt;
        &amp;lt;button data-oper='list' class=&quot;btn btn-info&quot;&amp;gt;
        &amp;lt;a href=&quot;/board/list&quot;&amp;gt;List&amp;lt;/a&amp;gt;&amp;lt;/button&amp;gt;  
 --%&amp;gt;
 
   &amp;lt;button data-oper='modify' class=&quot;btn btn-default&quot;&amp;gt;Modify&amp;lt;/button&amp;gt;
   &amp;lt;button data-oper='list' class=&quot;btn btn-info&quot;&amp;gt;List&amp;lt;/button&amp;gt;
    

&amp;lt;%-- &amp;lt;form id='operForm' action=&quot;/boad/modify&quot; method=&quot;get&quot;&amp;gt;
  &amp;lt;input type='hidden' id='bno' name='bno' value='&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'&amp;gt;
&amp;lt;/form&amp;gt; --%&amp;gt;


    &amp;lt;!-- p 317 --&amp;gt;
   &amp;lt;form id='operForm' action=&quot;/boad/modify&quot; method=&quot;get&quot;&amp;gt;
     &amp;lt;input type='hidden' id='bno' name='bno' value='&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${cri.pageNum}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${cri.amount}&quot;/&amp;gt;'&amp;gt;
     
     &amp;lt;!-- p 345 --&amp;gt;
     &amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${cri.keyword}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${cri.type}&quot;/&amp;gt;'&amp;gt;
     
   &amp;lt;/form&amp;gt; 

   &amp;lt;/div&amp;gt;
   
   &amp;lt;!-- ------------- --&amp;gt;
    &amp;lt;div class=&quot;col-lg-12&quot;&amp;gt;

    &amp;lt;!-- /.panel --&amp;gt;
    &amp;lt;div class=&quot;panel panel-default&quot;&amp;gt;
&amp;lt;!--       &amp;lt;div class=&quot;panel-heading&quot;&amp;gt;
        &amp;lt;i class=&quot;fa fa-comments fa-fw&quot;&amp;gt;&amp;lt;/i&amp;gt; Reply
      &amp;lt;/div&amp;gt; --&amp;gt;
      
      &amp;lt;div class=&quot;panel-heading&quot;&amp;gt;
        &amp;lt;i class=&quot;fa fa-comments fa-fw&quot;&amp;gt;&amp;lt;/i&amp;gt; Reply
        &amp;lt;button id='addReplyBtn' class='btn btn-primary btn-xs pull-right'&amp;gt;New Reply&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;      
      
      
      &amp;lt;!-- /.panel-heading --&amp;gt;
      &amp;lt;div class=&quot;panel-body&quot;&amp;gt;        
      
        &amp;lt;ul class=&quot;chat&quot;&amp;gt;

        &amp;lt;/ul&amp;gt;
        &amp;lt;!-- ./ end ul --&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;!-- /.panel .chat-panel --&amp;gt;

   &amp;lt;div class=&quot;panel-footer&quot;&amp;gt;&amp;lt;/div&amp;gt;


      &amp;lt;/div&amp;gt;
  &amp;lt;/div&amp;gt;
  &amp;lt;!-- ./ end row --&amp;gt;
&amp;lt;!-- ------------- --&amp;gt;

&amp;lt;!-- p.420 ------------- --&amp;gt;
&amp;lt;!-- Modal --&amp;gt;
      &amp;lt;div class=&quot;modal fade&quot; id=&quot;myModal&quot; tabindex=&quot;-1&quot; role=&quot;dialog&quot;
        aria-labelledby=&quot;myModalLabel&quot; aria-hidden=&quot;true&quot;&amp;gt;
        &amp;lt;div class=&quot;modal-dialog&quot;&amp;gt;
          &amp;lt;div class=&quot;modal-content&quot;&amp;gt;
            &amp;lt;div class=&quot;modal-header&quot;&amp;gt;
              &amp;lt;button type=&quot;button&quot; class=&quot;close&quot; data-dismiss=&quot;modal&quot;
                aria-hidden=&quot;true&quot;&amp;gt;&amp;amp;times;&amp;lt;/button&amp;gt;
              &amp;lt;h4 class=&quot;modal-title&quot; id=&quot;myModalLabel&quot;&amp;gt;REPLY MODAL&amp;lt;/h4&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;div class=&quot;modal-body&quot;&amp;gt;
              &amp;lt;div class=&quot;form-group&quot;&amp;gt;
                &amp;lt;label&amp;gt;Reply&amp;lt;/label&amp;gt; 
                &amp;lt;input class=&quot;form-control&quot; name='reply' value='New Reply!!!!'&amp;gt;
              &amp;lt;/div&amp;gt;      
              &amp;lt;div class=&quot;form-group&quot;&amp;gt;
                &amp;lt;label&amp;gt;Replyer&amp;lt;/label&amp;gt; 
                &amp;lt;input class=&quot;form-control&quot; name='replyer' value='replyer'&amp;gt;
              &amp;lt;/div&amp;gt;
              &amp;lt;div class=&quot;form-group&quot;&amp;gt;
                &amp;lt;label&amp;gt;Reply Date&amp;lt;/label&amp;gt; 
                &amp;lt;input class=&quot;form-control&quot; name='replyDate' value='2018-01-01 13:13'&amp;gt;
              &amp;lt;/div&amp;gt;
      
            &amp;lt;/div&amp;gt;
&amp;lt;div class=&quot;modal-footer&quot;&amp;gt;
        &amp;lt;button id='modalModBtn' type=&quot;button&quot; class=&quot;btn btn-warning&quot;&amp;gt;Modify&amp;lt;/button&amp;gt;
        &amp;lt;button id='modalRemoveBtn' type=&quot;button&quot; class=&quot;btn btn-danger&quot;&amp;gt;Remove&amp;lt;/button&amp;gt;
        &amp;lt;button id='modalRegisterBtn' type=&quot;button&quot; class=&quot;btn btn-primary&quot;&amp;gt;Register&amp;lt;/button&amp;gt;
        &amp;lt;button id='modalCloseBtn' type=&quot;button&quot; class=&quot;btn btn-default&quot;&amp;gt;Close&amp;lt;/button&amp;gt;
      &amp;lt;/div&amp;gt;          &amp;lt;/div&amp;gt;
          &amp;lt;!-- /.modal-content --&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;!-- /.modal-dialog --&amp;gt;
      &amp;lt;/div&amp;gt;
      &amp;lt;!-- /.modal --&amp;gt;
&amp;lt;!-- ------------- --&amp;gt;      
    
&amp;lt;!-- p 265 --&amp;gt; 
&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
  $(document).ready(function (){
     var operForm = $(&quot;#operForm&quot;);
     
     $(&quot;button[data-oper='modify']&quot;).on(&quot;click&quot;, function (e){
        operForm.attr(&quot;action&quot;,&quot;/board/modify&quot;).submit();
     });
     
     // http://localhost/board/list?[pageNum=3&amp;amp;amount=5 ]
     $(&quot;button[data-oper='list']&quot;).on(&quot;click&quot;, function (e){
        operForm.find(&quot;#bno&quot;).remove();
        operForm.attr(&quot;action&quot;,&quot;/board/list&quot;).submit();
     }); 
  });
&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;/resources/js/reply.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
   // 1.
   // console.log( replyService );
   
   // 2.
   /* 
   console.log(&quot;----------&quot;);
   console.log(&quot;JS TEST&quot;);
   var bnoValue = '&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;';
   replyService.add({ reply:&quot;JS TEST&quot;, replyer:&quot;tester&quot;, bno:bnoValue }
                    ,function (result){
                       alert(&quot;RESULT: &quot; + result);
                    });
    */
    
    // 3. p 407
    /* 
    console.log(&quot;----------&quot;);
    console.log(&quot;JS TEST&quot;);
    var bnoValue = '&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;';
    replyService.getList({ bno:bnoValue, page:1 }
                     ,function (list){
                        for (var i = 0, len=list.length||0 ; i &amp;lt; len; i++) {                           
                           console.log(list[i]);
                   }
                     });
     */
&amp;lt;/script&amp;gt;

&amp;lt;script&amp;gt;
// p.415
$(document).ready(function () {
  //조회하는 게시글 번호
  var bnoValue = '&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;';
  
  var replyUL = $(&quot;.chat&quot;); //댓글을 표시하기 위한 ul태그
  //alert( bnoValue );
  //alert( replyUL );
    showList(1);
    
function showList(page){
   
     console.log(&quot;show list &quot; + page);
    
    replyService.getList({bno:bnoValue,page: page|| 1 }, function(replyCnt, list) {
      
    console.log(&quot;replyCnt: &quot;+ replyCnt );
    console.log(&quot;list: &quot; + list);
    console.log(list);
    
    if(page == -1){
      pageNum = Math.ceil(replyCnt/10.0);
      showList(pageNum);
      return;
    }
      
     var str=&quot;&quot;;
     
     if(list == null || list.length == 0){
       return;
     }
     
     for (var i = 0, len = list.length || 0; i &amp;lt; len; i++) {
       str +=&quot;&amp;lt;li class='left clearfix' data-rno='&quot;+list[i].rno+&quot;'&amp;gt;&quot;;
       str +=&quot;  &amp;lt;div&amp;gt;&amp;lt;div class='header'&amp;gt;&amp;lt;strong class='primary-font'&amp;gt;[&quot;
          +list[i].rno+&quot;] &quot;+list[i].replyer+&quot;&amp;lt;/strong&amp;gt;&quot;; 
       str +=&quot;    &amp;lt;small class='pull-right text-muted'&amp;gt;&quot;
           +replyService.displayTime(list[i].replyDate)+&quot;&amp;lt;/small&amp;gt;&amp;lt;/div&amp;gt;&quot;;
       str +=&quot;    &amp;lt;p&amp;gt;&quot;+list[i].reply+&quot;&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&quot;;
     }
     
     replyUL.html(str);
     
     showReplyPage(replyCnt);

 
   });//end function
     
 }//end showList
    
    var pageNum = 1;
    var replyPageFooter = $(&quot;.panel-footer&quot;);
    
    function showReplyPage(replyCnt){
      
      var endNum = Math.ceil(pageNum / 10.0) * 10;  
      var startNum = endNum - 9; 
      
      var prev = startNum != 1;
      var next = false;
      
      if(endNum * 10 &amp;gt;= replyCnt){
        endNum = Math.ceil(replyCnt/10.0);
      }
      
      if(endNum * 10 &amp;lt; replyCnt){
        next = true;
      }
      
      var str = &quot;&amp;lt;ul class='pagination pull-right'&amp;gt;&quot;;
      
      if(prev){
        str+= &quot;&amp;lt;li class='page-item'&amp;gt;&amp;lt;a class='page-link' href='&quot;+(startNum -1)+&quot;'&amp;gt;Previous&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&quot;;
      }
      
      for(var i = startNum ; i &amp;lt;= endNum; i++){
        
        var active = pageNum == i? &quot;active&quot;:&quot;&quot;;
        
        str+= &quot;&amp;lt;li class='page-item &quot;+active+&quot; '&amp;gt;&amp;lt;a class='page-link' href='&quot;+i+&quot;'&amp;gt;&quot;+i+&quot;&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&quot;;
      }
      
      if(next){
        str+= &quot;&amp;lt;li class='page-item'&amp;gt;&amp;lt;a class='page-link' href='&quot;+(endNum + 1)+&quot;'&amp;gt;Next&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;&quot;;
      }
      
      str += &quot;&amp;lt;/ul&amp;gt;&amp;lt;/div&amp;gt;&quot;;
      
      console.log(str);
      
      replyPageFooter.html(str);
    }
     
    replyPageFooter.on(&quot;click&quot;,&quot;li a&quot;, function(e){
       e.preventDefault();
       console.log(&quot;page click&quot;);
       
       var targetPageNum = $(this).attr(&quot;href&quot;);
       
       console.log(&quot;targetPageNum: &quot; + targetPageNum);
       
       pageNum = targetPageNum;
       
       showList(pageNum);
     });     

    
/*     function showList(page){
      
      replyService.getList({bno:bnoValue,page: page|| 1 }, function(list) {
        
        var str=&quot;&quot;;
       if(list == null || list.length == 0){
        
        replyUL.html(&quot;&quot;);
        
        return;
      }
       for (var i = 0, len = list.length || 0; i &amp;lt; len; i++) {
           str +=&quot;&amp;lt;li class='left clearfix' data-rno='&quot;+list[i].rno+&quot;'&amp;gt;&quot;;
           str +=&quot;  &amp;lt;div&amp;gt;&amp;lt;div class='header'&amp;gt;&amp;lt;strong class='primary-font'&amp;gt;&quot;+list[i].replyer+&quot;&amp;lt;/strong&amp;gt;&quot;; 
           str +=&quot;    &amp;lt;small class='pull-right text-muted'&amp;gt;&quot;+replyService.displayTime(list[i].replyDate)+&quot;&amp;lt;/small&amp;gt;&amp;lt;/div&amp;gt;&quot;;
           str +=&quot;    &amp;lt;p&amp;gt;&quot;+list[i].reply+&quot;&amp;lt;/p&amp;gt;&amp;lt;/div&amp;gt;&amp;lt;/li&amp;gt;&quot;;
         }


    replyUL.html(str);

      });//end function
      
   }//end showList */
   
    var modal = $(&quot;.modal&quot;);
    var modalInputReply = modal.find(&quot;input[name='reply']&quot;);
    var modalInputReplyer = modal.find(&quot;input[name='replyer']&quot;);
    var modalInputReplyDate = modal.find(&quot;input[name='replyDate']&quot;);
    
    var modalModBtn = $(&quot;#modalModBtn&quot;);
    var modalRemoveBtn = $(&quot;#modalRemoveBtn&quot;);
    var modalRegisterBtn = $(&quot;#modalRegisterBtn&quot;);
    
    $(&quot;#modalCloseBtn&quot;).on(&quot;click&quot;, function(e){
       
       modal.modal('hide');
    });
    
    $(&quot;#addReplyBtn&quot;).on(&quot;click&quot;, function(e){
      
      modal.find(&quot;input&quot;).val(&quot;&quot;);
      modalInputReplyDate.closest(&quot;div&quot;).hide();
      modal.find(&quot;button[id !='modalCloseBtn']&quot;).hide();
      
      modalRegisterBtn.show();
      
      $(&quot;.modal&quot;).modal(&quot;show&quot;);
      
    });
    

    modalRegisterBtn.on(&quot;click&quot;,function(e){
      
      var reply = { //json이 아니라 js Object, 
            reply: modalInputReply.val(),
            replyer:modalInputReplyer.val(),
            bno:bnoValue
          }; //js Object -&amp;gt; json 변환하고자 한다면 ? JSON.stringify(reply)
      replyService.add(reply, function(result){
        
        alert(result); //success 
        
        //modal.find(&quot;input&quot;).val(&quot;&quot;); 모달창 초기화
        //modal.modal(&quot;hide&quot;);			숨기기
        
        //showList(1);
        showList(-1); //함수 가보면 -1이면 댓글 목록 다시 출력하는 코딩
        
      });
      
    });


  //댓글 조회 클릭 이벤트 처리 
    $(&quot;.chat&quot;).on(&quot;click&quot;, &quot;li&quot;, function(e){
      
      var rno = $(this).data(&quot;rno&quot;);
      
      replyService.get(rno, function(reply){
      
        modalInputReply.val(reply.reply);
        modalInputReplyer.val(reply.replyer);
        modalInputReplyDate.val(replyService.displayTime( reply.replyDate))
        .attr(&quot;readonly&quot;,&quot;readonly&quot;);
        modal.data(&quot;rno&quot;, reply.rno);
        
        modal.find(&quot;button[id !='modalCloseBtn']&quot;).hide();
        modalModBtn.show();
        modalRemoveBtn.show();
        
        $(&quot;.modal&quot;).modal(&quot;show&quot;);
            
      });
    });
  
    
/*     modalModBtn.on(&quot;click&quot;, function(e){
      
      var reply = {rno:modal.data(&quot;rno&quot;), reply: modalInputReply.val()};
      
      replyService.update(reply, function(result){
            
        alert(result);
        modal.modal(&quot;hide&quot;);
        showList(1);
        
      });
      
    });

    modalRemoveBtn.on(&quot;click&quot;, function (e){
         
       var rno = modal.data(&quot;rno&quot;);
       
       replyService.remove(rno, function(result){
             
           alert(result);
           modal.modal(&quot;hide&quot;);
           showList(1);
           
       });
       
     }); */

    modalModBtn.on(&quot;click&quot;, function(e){
         
        var reply = {rno:modal.data(&quot;rno&quot;), reply: modalInputReply.val()};
        
        replyService.update(reply, function(result){
              
          alert(result);
          modal.modal(&quot;hide&quot;);
          showList(pageNum);
          
        });
        
      });


      modalRemoveBtn.on(&quot;click&quot;, function (e){
        
        var rno = modal.data(&quot;rno&quot;);
        
        replyService.remove(rno, function(result){
              
            alert(result);
            modal.modal(&quot;hide&quot;);
            showList(pageNum);
            
        });
        
      });

 
});

&amp;lt;/script&amp;gt;



&amp;lt;script&amp;gt;

/* console.log(&quot;===============&quot;);
console.log(&quot;JS TEST&quot;);

var bnoValue = '&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'; */

//for replyService add test
/* replyService.add(
    
    {reply:&quot;JS Test&quot;, replyer:&quot;tester&quot;, bno:bnoValue}
    ,
    function(result){ 
      alert(&quot;RESULT: &quot; + result);
    }
); */


//reply List Test
/* replyService.getList({bno:bnoValue, page:1}, function(list){
    
     for(var i = 0,  len = list.length||0; i &amp;lt; len; i++ ){
       console.log(list[i]);
     }
});
 */

 
/*  //17번 댓글 삭제 테스트 
 replyService.remove(17, function(count) {

   console.log(count);

   if (count === &quot;success&quot;) {
     alert(&quot;REMOVED&quot;);
   }
 }, function(err) {
   alert('ERROR...');
 });
 */
 

//12번 댓글 수정 
/* replyService.update({
  rno : 12,
  bno : bnoValue,
  reply : &quot;Modified Reply....&quot;
}, function(result) {

  alert(&quot;수정 완료...&quot;);

});  
 */

&amp;lt;/script&amp;gt;  

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;13. reply.js&lt;/p&gt;
&lt;pre id=&quot;code_1614079744042&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;console.log(&quot;Reply Module........&quot;);

/*
// p.401
var replyService = (function() {
                  return { name : &quot;AAAA&quot; };                  
               })();
*/

/*
// p.402
var replyService = (function() {
                  function add(reply, callback){
                      console.log(&quot;reply.....&quot;);
                  }
                  return { add : add };                  
               })();
*/

 
var replyService = (function() {

   function add(reply, callback, error) {
      console.log(&quot;add reply...............&quot;);

      $.ajax({
         type : 'post',
         url : '/replies/new',
         data : JSON.stringify(reply), //stringify : 위 reply(문자열)를 json타입으로 변환할 때 사용
         contentType : &quot;application/json; charset=utf-8&quot;,
         success : function(result, status, xhr) {
            if (callback) {
               callback(result);
            }
         },
         error : function(xhr, status, er) {
            if (error) {
               error(er);
            }
         }
      })
   }

//   function getList(param, callback, error) {
//
//      var bno = param.bno;
//      var page = param.page || 1;
//

 //        /replies/pages/41/2
//      $.getJSON(&quot;/replies/pages/&quot; + bno + &quot;/&quot; + page + &quot;.json&quot;,
//            function(data) {
//               if (callback) {
//                  callback(data);
//               }
//            }).fail(function(xhr, status, err) {
//         if (error) {
//            error();
//         }
//      });
//   }
   
   

   function getList(param, callback, error) {

       var bno = param.bno;
       var page = param.page || 1;
       
       $.getJSON(&quot;/replies/pages/&quot; + bno + &quot;/&quot; + page + &quot;.json&quot;,
           function(data) {
          
             if (callback) {
               //callback(data); // 댓글 목록만 가져오는 경우 
               callback(data.replyCnt, data.list); //댓글 숫자와 목록을 가져오는 경우 
             }
           }).fail(function(xhr, status, err) {
         if (error) {
           error();
         }
       });
     }

   
   function remove(rno, callback, error) {
      $.ajax({
         type : 'delete',
         url : '/replies/' + rno,
         success : function(deleteResult, status, xhr) {
            if (callback) {
               callback(deleteResult);
            }
         },
         error : function(xhr, status, er) {
            if (error) {
               error(er);
            }
         }
      });
   }

   function update(reply, callback, error) {

      console.log(&quot;RNO: &quot; + reply.rno);

      $.ajax({
         type : 'put',
         url : '/replies/' + reply.rno,
         data : JSON.stringify(reply),
         contentType : &quot;application/json; charset=utf-8&quot;,
         success : function(result, status, xhr) {
            if (callback) {
               callback(result);
            }
         },
         error : function(xhr, status, er) {
            if (error) {
               error(er);
            }
         }
      });
   }

   function get(rno, callback, error) {

      $.get(&quot;/replies/&quot; + rno + &quot;.json&quot;, function(result) {

         if (callback) {
            callback(result);
         }

      }).fail(function(xhr, status, err) {
         if (error) {
            error();
         }
      });
   }

   function displayTime(timeValue) {

      var today = new Date();

      var gap = today.getTime() - timeValue;

      var dateObj = new Date(timeValue);
      var str = &quot;&quot;;

      if (gap &amp;lt; (1000 * 60 * 60 * 24)) {

         var hh = dateObj.getHours();
         var mi = dateObj.getMinutes();
         var ss = dateObj.getSeconds();

         return [ (hh &amp;gt; 9 ? '' : '0') + hh, ':', (mi &amp;gt; 9 ? '' : '0') + mi,
               ':', (ss &amp;gt; 9 ? '' : '0') + ss ].join('');

      } else {
         var yy = dateObj.getFullYear();
         var mm = dateObj.getMonth() + 1; // getMonth() is zero-based
         var dd = dateObj.getDate();

         return [ yy, '/', (mm &amp;gt; 9 ? '' : '0') + mm, '/',
               (dd &amp;gt; 9 ? '' : '0') + dd ].join('');
      }
   }
   ;

   return {
      add : add,
      get : get,
      getList : getList,
      remove : remove,
      update : update,
      displayTime : displayTime
   };

})();
 &lt;/code&gt;&lt;/pre&gt;</description>
      <category>Spring</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/310</guid>
      <comments>https://daspace.tistory.com/310#entry310comment</comments>
      <pubDate>Tue, 23 Feb 2021 20:29:11 +0900</pubDate>
    </item>
    <item>
      <title>[days15] REST 방식으로 전환</title>
      <link>https://daspace.tistory.com/309</link>
      <description>&lt;p&gt;앱에서 서버에 기대하는 것은 완성된 HTML이 아니라 그저 자신에게 필요한 순수한 데이터만을 요구하게 되어 있다. 이처럼 서버의 역할은 점점 더 순수하게 데이터에 대한 처리를 목적으로 하는 형태로 진화하고 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- URL :&lt;/b&gt; 이 곳에 가면 당신이 원하는 것을 찾을 수 있습니다. (URI의 하위개념)&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- URI :&lt;/b&gt; &lt;span style=&quot;color: #333333;&quot;&gt;당신이 원하는 주소는 여기입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;REST&lt;/b&gt;는 하나의 URI는 하나의 고유한 리소스를 대표하도록 설계된다는 개념에 전송방식을 결합해서 원하는 작업을 지정한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;URI + GET/POST/PUT/DELETE...&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;REST관련 어노테이션들&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;@RestController&amp;nbsp; &amp;nbsp;Controller가 REST 방식을 처리하기 위한 것임을 명시&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;@ResponseBody&amp;nbsp; &amp;nbsp; 일반적인 JSP와 같은 뷰로 전달되는게 아니라 데이터 자체를 전달하기 위한 용도&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;@PathVariable&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;URL 경로에 있는 값을 파라미터로 추출하려고 할 때 사용&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;@CrossOrigin&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Ajax의 크로스 도메인 문제를 해결&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;@RequestBody&amp;nbsp; &amp;nbsp; &amp;nbsp; JSON 데이터를 원하는 타입으로 바인딩 처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;@RestController&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;메소드의 리턴 타입으로 사용자가 정의한 클래스 타입을 지정할 수 있고, 이를 JSON이나 XML로 자동으로 처리 가능&lt;/p&gt;
&lt;p&gt;사용하기 위한 준비&lt;/p&gt;
&lt;p&gt;1. pom.xml에 필요 라이브러리 추가&lt;/p&gt;
&lt;pre id=&quot;code_1614077291566&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;     &amp;lt;!-- p 147 jackson-databind --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.fasterxml.jackson.core&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jackson-databind&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.12.1&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;!-- 추가--&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.fasterxml.jackson.dataformat&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;jackson-dataformat-xml&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.9.6&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
      &amp;lt;!-- 추가 --&amp;gt;
      &amp;lt;dependency&amp;gt;
         &amp;lt;groupId&amp;gt;com.google.code.gson&amp;lt;/groupId&amp;gt;
         &amp;lt;artifactId&amp;gt;gson&amp;lt;/artifactId&amp;gt;
         &amp;lt;version&amp;gt;2.8.2&amp;lt;/version&amp;gt;
      &amp;lt;/dependency&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 라이브러리는 JSON 데이터를 처리하기 위해, 또 니중에 브라우저에 객체를 JSON이라는 포맷의 문자열로 변환시켜 전송하기 위해 필요하다. 또한, 테스트 시 직접 Java 인스턴스를 JSON 타입의 문자열로 변환해야 하는 일들도 있으므로 gson 라이브러리도 추가한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SampleController 생성&lt;/p&gt;
&lt;p&gt;- 기존의 @Controller는 문자열을 반환하는 경우 JSP 파일의 이름으로 처리하지만, @RestController의 경우 순수한 데이터가 된다.&lt;/p&gt;
&lt;p&gt;- @GetMapping에 사용된 produces 속성은 해당 메소드가 생산하는 MIME 타입을 의미한다. 문자열로 직접 지정할 수 도 있고, 메소드 내의 MediaType이라는 클래스를 이용할 수도 있다.&lt;/p&gt;
&lt;pre id=&quot;code_1614077662943&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.controller;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.zerock.domain.SampleVO;
import org.zerock.domain.Ticket;

import lombok.extern.log4j.Log4j;


@RestController
@RequestMapping(&quot;/sample&quot;)
@Log4j
public class SampleController {
	
	// p.359
	   @GetMapping(value = &quot;/getText&quot;, produces = &quot;text/plain; charset=UTF-8&quot;)   
	   public String getText() {
	      log.info(&quot;MIME TYPE : &quot; + MediaType.TEXT_PLAIN_VALUE);
	      return &quot;안녕하세요&quot;;
	   }  
	   
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/baactN/btqYiCae58b/T034Mk43z8pJlPeb3OFb1k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/baactN/btqYiCae58b/T034Mk43z8pJlPeb3OFb1k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/baactN/btqYiCae58b/T034Mk43z8pJlPeb3OFb1k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbaactN%2FbtqYiCae58b%2FT034Mk43z8pJlPeb3OFb1k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/LwFcF/btqYgFSLvsN/oPQ7EMohEwGi8P7GDsil1K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/LwFcF/btqYgFSLvsN/oPQ7EMohEwGi8P7GDsil1K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/LwFcF/btqYgFSLvsN/oPQ7EMohEwGi8P7GDsil1K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FLwFcF%2FbtqYgFSLvsN%2FoPQ7EMohEwGi8P7GDsil1K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;객체의 반환&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;객체를 반환하는 작업은 JSON이나 XML을 이용한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;SampleVO&lt;/p&gt;
&lt;p&gt;- @NoArgsConstructor 비어있는 생성자 만들기&lt;/p&gt;
&lt;pre id=&quot;code_1614077822947&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class SampleVO {
   
   private Integer mno;
   private String firstName;
   private String LastName;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨트롤러에 메소드 추가&lt;/p&gt;
&lt;pre id=&quot;code_1614077901205&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// p.361
	   @GetMapping(value = &quot;/getSample&quot;, produces = {
	         //MediaType.APPLICATION_JSON_UTF8_VALUE, 
	         MediaType.APPLICATION_JSON_VALUE,
	         MediaType.APPLICATION_XML_VALUE
	   }) 
	   public SampleVO getSample() {
	      return new SampleVO(112, &quot;스타&quot;, &quot;로드&quot;);
	   }
	   //url 뒤에 .json 붙히면 자동으로 json으로 출력
	   //안붙히면 기본은 xml&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/3PxZO/btqYiCVAH36/MysVyxySw1ykmzfXGz7o4k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/3PxZO/btqYiCVAH36/MysVyxySw1ykmzfXGz7o4k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/3PxZO/btqYiCVAH36/MysVyxySw1ykmzfXGz7o4k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F3PxZO%2FbtqYiCVAH36%2FMysVyxySw1ykmzfXGz7o4k%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/GRmyv/btqYnmqUU05/M4eoIBK1kOBwf1Xq3kvlh0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/GRmyv/btqYnmqUU05/M4eoIBK1kOBwf1Xq3kvlh0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/GRmyv/btqYnmqUU05/M4eoIBK1kOBwf1Xq3kvlh0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGRmyv%2FbtqYnmqUU05%2FM4eoIBK1kOBwf1Xq3kvlh0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;@GetMapping이나 @RequestMapping의 procedures 속성은 반드시 지정해야 하는 것은 아니므로 생략해도 된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;컬렉션 타입의 객체 반환&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;배열, 리스트, 맵 타입의 객체 전송&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨트롤러 추가&lt;/p&gt;
&lt;pre id=&quot;code_1614078273756&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// p.364
	   @GetMapping(&quot;/getMap&quot;)
	   public Map&amp;lt;String, SampleVO&amp;gt; getMap(){
	      
	      Map&amp;lt;String, SampleVO&amp;gt; map = new HashMap&amp;lt;String, SampleVO&amp;gt;();
	           //  key              value
	      map.put(&quot;First&quot;, new SampleVO(1, &quot;f&quot;, &quot;l&quot;));            
	      map.put(&quot;Second&quot;, new SampleVO(2, &quot;f&quot;, &quot;l&quot;));
	      
	      return map;
	   }

	   
	// p.363
	   @GetMapping(&quot;/getList&quot;)
	   public List&amp;lt;SampleVO&amp;gt; getList(){
	      return IntStream
	            .range(1, 10)
	            .mapToObj(i -&amp;gt; new SampleVO(i, &quot;first &quot; + i, &quot;last &quot;+i))
	            .collect(Collectors.toList());
	   } //포폴 스프링 REST 방식으로 처리했다 써야함 (꼭 사용하기)
&lt;/code&gt;&lt;/pre&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/whLs0/btqYiC2jOLR/BV4C7pcuee7SrKvuSS8yT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/whLs0/btqYiC2jOLR/BV4C7pcuee7SrKvuSS8yT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/whLs0/btqYiC2jOLR/BV4C7pcuee7SrKvuSS8yT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FwhLs0%2FbtqYiC2jOLR%2FBV4C7pcuee7SrKvuSS8yT1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50%;&quot;&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/sRPbU/btqYoYJN82V/G0AkKkKBGHimQDlPfZKQkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sRPbU/btqYoYJN82V/G0AkKkKBGHimQDlPfZKQkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sRPbU/btqYoYJN82V/G0AkKkKBGHimQDlPfZKQkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsRPbU%2FbtqYoYJN82V%2FG0AkKkKBGHimQDlPfZKQkK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ResponseEntity 타입&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;Rest방식으로 호출하는 경우는 화면 자체가 아니라 데이터 자체를 전송하는 방식으로 처리되기 때문에 데이터를 요청한 쪽에서는 정상 데이터인지 비정상 데이터인지를 구분할 수 있는 확실한 방법을 제공해야 한다.&lt;/p&gt;
&lt;p&gt;ResponseEntity는 데이터와 함께 HTTP 헤더의 상태메시지 등을 같이 전달하는 용도로 사용한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨트롤러&lt;/p&gt;
&lt;pre id=&quot;code_1614078553242&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// p.365
	   @GetMapping(value = &quot;/check&quot;, params = {&quot;height&quot;, &quot;weight&quot;})
	   public ResponseEntity&amp;lt;SampleVO&amp;gt; check(Double height, Double weight){
	      SampleVO vo = new SampleVO(1, &quot;&quot;+height, &quot;&quot;+weight);
	      ResponseEntity&amp;lt;SampleVO&amp;gt; result = null;
	      
	      if (height &amp;lt; 150) {
	         result = ResponseEntity.status(HttpStatus.BAD_GATEWAY).body(vo);
	      } else {
	         result = ResponseEntity.status(HttpStatus.OK).body(vo);
	      }
	      return result;
	   }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ckV6H8/btqYo0ATWtE/HvwjVQqZfbco1yOiXXRU5K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ckV6H8/btqYo0ATWtE/HvwjVQqZfbco1yOiXXRU5K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ckV6H8/btqYo0ATWtE/HvwjVQqZfbco1yOiXXRU5K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FckV6H8%2FbtqYo0ATWtE%2FHvwjVQqZfbco1yOiXXRU5K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;@PathVariable&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;REST 방식에서는 URL 내에 최대한 많은 정보를 담으려고 노력한다. 예전에는 ? 뒤에 추가되는 쿼리 스트링 형태로 파라미터를 전달되던 데이터들이 REST 방식에서는 경로의 일부로 차용되는 경우가 많다.&lt;/p&gt;
&lt;p&gt;스프링 MVC에서는 @PathVariable 어노테이션을 이용해 URL 상에 경로의 일부를 파라미터로 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨트롤러&lt;/p&gt;
&lt;pre id=&quot;code_1614079114863&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// p.366
	   //     /sample/product/bags/1234&quot;
	   @GetMapping(&quot;/product/{cat}/{pid}&quot;)
	   public String[] getPath(@PathVariable(&quot;cat&quot;) String cat
	         , @PathVariable(&quot;pid&quot;) Integer pid) {
	      return new String[] { &quot;category: &quot; + cat, &quot;productid: &quot; + pid };
	   }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;요청 URL&lt;/p&gt;
&lt;pre id=&quot;code_1614079114863&quot; class=&quot;java&quot; style=&quot;margin: 20px auto 0px; display: block; overflow: auto; padding: 15px; color: #383a42; background: #f6f7f8; font-size: 14px; border-radius: 3px; font-family: Menlo, Consolas, Monaco, monospace; border: 1px solid #dddddd; cursor: default; z-index: 1;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a href=&quot;/sample/product/bags/1234&quot;&amp;gt;/sample/product/bags/1234&amp;lt;/a&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bcu2Cv/btqYpWkJF2w/UB3DJRk4u0vM2lkuc9DAYK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bcu2Cv/btqYpWkJF2w/UB3DJRk4u0vM2lkuc9DAYK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bcu2Cv/btqYpWkJF2w/UB3DJRk4u0vM2lkuc9DAYK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbcu2Cv%2FbtqYpWkJF2w%2FUB3DJRk4u0vM2lkuc9DAYK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;@RequestBody&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;전달된 요청의 내용을 이용해 해당 파라미터의 타입으로 변환을 요구한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Ticket 클래스 추가&lt;/p&gt;
&lt;pre id=&quot;code_1614078684914&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.domain;

import lombok.Data;

@Data
public class Ticket {

  private int tno;
  private String owner;
  private String grade;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;컨트롤러&lt;/p&gt;
&lt;pre id=&quot;code_1614078732152&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	// p.368
	   // 클라이언트에서 [json 데이터]를 파라미터로 ajax 요청
	   //    {&quot;tno&quot;:1,&quot;owner&quot;:&quot;kenik&quot;,&quot;grade&quot;:&quot;mvp&quot;}   --&amp;gt;     Ticket 자바객체로 변환
	   //                   @RequestBody
	   @PostMapping(&quot;/ticket&quot;)
	   public Ticket convert(@RequestBody Ticket ticket) {
	      log.info(&quot;&amp;gt; convert..........ticket &quot; + ticket);
	      return ticket;
	   }	&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;jsp (뷰)&lt;/p&gt;
&lt;pre id=&quot;code_1614078824797&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- p.369 --&amp;gt;
&amp;lt;%
  Ticket ticket = new Ticket();
  ticket.setTno(1);
  ticket.setOwner(&quot;kenik&quot;);
  ticket.setGrade(&quot;mvp&quot;);
  
  //자바 객체Ticket 을 json 데이터로 변환하는 코딩
  String jsonTicket = new Gson().toJson(ticket);
%&amp;gt;
jsonTicket : &amp;lt;%= jsonTicket %&amp;gt;&amp;lt;br&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/92nnw/btqYhzrfc1I/LAE8qDRE5ofjMn6ASTPiv0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/92nnw/btqYhzrfc1I/LAE8qDRE5ofjMn6ASTPiv0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/92nnw/btqYhzrfc1I/LAE8qDRE5ofjMn6ASTPiv0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F92nnw%2FbtqYhzrfc1I%2FLAE8qDRE5ofjMn6ASTPiv0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;다양한 전송방식&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;REST 방식의 데이터 교환에서 가장 특이한 점은 기존의 GET/POST 외에 다양한 방식으로 데이터를 전달한다는 점이다.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 26.3328%; height: 154px;&quot; border=&quot;1&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 24px;&quot;&gt;Create&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 24px;&quot;&gt;POST&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 24px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 24px;&quot;&gt;Read&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 24px;&quot;&gt;GET&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 25px;&quot;&gt;Update&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 25px;&quot;&gt;PUT&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 25px;&quot;&gt;
&lt;td style=&quot;width: 50%; height: 25px;&quot;&gt;Delete&lt;/td&gt;
&lt;td style=&quot;width: 50%; height: 25px;&quot;&gt;DELETE&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/309</guid>
      <comments>https://daspace.tistory.com/309#entry309comment</comments>
      <pubDate>Tue, 23 Feb 2021 20:20:23 +0900</pubDate>
    </item>
    <item>
      <title>[days14] 페이징 처리 및 [검색 기능] 구현 (2/2)</title>
      <link>https://daspace.tistory.com/308</link>
      <description>&lt;p&gt;앞의 페이징 처리에 이어서 검색 기능 추가 p325&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;게시물의 검색 기능은 다음과 같이 분류가 가능하다.&lt;/p&gt;
&lt;p&gt;- 제목/내용/작성자와 같이 단일 항목 검색&lt;/p&gt;
&lt;p&gt;- 제목,내용/제목,작성자 등 다중 항목 검색&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;** AND와 OR이 섞여있는 SQL을 작성할 때는 우선순위 연산자인 '()'를 이용해 OR 조건을 처리해야한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;&amp;nbsp;MyBatis의 동적 SQL&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;MyBatis는 동적 태그 기능을 통해서 SQL을 파라미터들의 조건에 맞게 조정할 수 있는 기능을 제공한다.&lt;/p&gt;
&lt;p&gt;MyBatis의 동적 태그는 약간의 구문을 이용해 전달되는 파라미터를 가공해서 경우에 따라 다른 SQL을 만들어 실행할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;- MyBatis의 동적 태그들&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&amp;nbsp; if / choose(when, otherwise) / trim(where, set) /&amp;nbsp;foreach&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;if - 검색 조건이 'T'이면 title이 keyword인 항목 검색&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;if test=&quot;type == 'T'.toString()&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; ( title like '%' || #{keyword} || '%' )&lt;/p&gt;
&lt;p&gt;&amp;lt;/if&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;if ... &amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; :&lt;/p&gt;
&lt;p&gt;&amp;lt;/if&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;&amp;lt;choose&amp;gt; - 여러 상황들 중 하나의 상황에만 동작 (if~else 처럼)&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;choose&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;when test=&quot;type == 'T'.toString()&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; (title like '%' || #{keyword} || '%' )&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;/when&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;when ...&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; :&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;/when&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;otherwise&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; (title like '%' || #{keyword} || '%' OR content like '%' || #{keyword} || '%')&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;/otherwise&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/choose&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;&amp;lt;trim&amp;gt; &amp;lt;where&amp;gt; &amp;lt;set&amp;gt; - 단독으로 사용되지 않고 &amp;lt;if&amp;gt;, &amp;lt;choose&amp;gt;와 같은 태그들을 내포하여 SQL들을 연결,&amp;nbsp;&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;앞 뒤에 필요한 구문들 (AND, OR, WHERE 등)을 추가하거나 생략하는 역할&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;&amp;lt;where&amp;gt;&lt;/b&gt;&lt;/span&gt;의 경우 태그 안쪽에서 SQL이 생성될 때는 WHERE 구문이 붙고, 그렇지 않은 경우 생성되지 않는다.&lt;/p&gt;
&lt;p&gt;select * from tbl_board&lt;/p&gt;
&lt;p&gt;&amp;lt;where&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;if test=&quot;bno != null&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;bno = #{bno}&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;/if&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/where&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- bno 값이 존재하는 경우 : select * from tbl_board &lt;span style=&quot;color: #9d9d9d;&quot;&gt;where bno=33&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- bno 값이 존재하지 않는 경우 : select * from tbl_board&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;&amp;lt;trim&amp;gt;&lt;/b&gt;&lt;/span&gt;은 하위에서 만들어지는 SQL문을 조사하여 앞 쪽에 추가적인 SQL을 넣을 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; prefix, suffix, prefixOverrides, suffixOverrides 속성을 지정 가능하다.&lt;/p&gt;
&lt;p&gt;select * from tbl_board&lt;/p&gt;
&lt;p&gt;&amp;lt;where&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;if test = &quot;bno != null&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; bno = #{bno}&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;/if&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;trim prifix = &quot;and&quot;&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;rownum = 1&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;lt;/trim&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/where&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- bno 값이 존재하는 경우 : select * from tbl_board where &lt;span style=&quot;color: #9d9d9d;&quot;&gt;bno = 33 and&lt;/span&gt; rownum = 1&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- bno 값이 존재하지 않는 경우 : select * from tbl_board where rownum=1&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #f89009;&quot;&gt;&lt;b&gt;&amp;lt;foreach&amp;gt;&lt;/b&gt;&lt;/span&gt;는 List, 배열, 맵 등을 이용해 루프를 처리할 수 있다. 주로 IN 조건에서 많이 사용하지만, 경우에 따라서는 복잡한 WHERE 조건을 만들 때에도 사용할 수 있다.&lt;/p&gt;
&lt;p&gt;foreach를 배열이나 List를 이용하는 경우에는 item 속성만을 이용하면 되고, Map의 형태로 key와 value를 이용해야 할 때에는 index와 item속성을 둘 다 이용한다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;19.&lt;/p&gt;
&lt;p&gt;검색&amp;nbsp;조건&amp;nbsp;처리를&amp;nbsp;위한&amp;nbsp;Criteria의&amp;nbsp;변화 &lt;br /&gt;&amp;nbsp;-&amp;gt; 필드 type(조건)과 keyword(검색어) 추가, 메소드&amp;nbsp;생성&amp;nbsp;2개&lt;/p&gt;
&lt;pre id=&quot;code_1613997369025&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.domain;

import org.springframework.web.util.UriComponentsBuilder;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;


@ToString
@Setter
@Getter
public class Criteria {

  private int pageNum;
  private int amount;
  
  private String type;
  private String keyword;

  public Criteria() {
    this(1, 10);
  }

  public Criteria(int pageNum, int amount) {
    this.pageNum = pageNum;
    this.amount = amount;
  }
  
  public String[] getTypeArr() {
    return type == null? new String[] {}: type.split(&quot;&quot;);
    //TC 이면 T하나 C하나 잘라 배열로 만듦
  }
  
  // p 349
  // 가장 편리한 점 한글 처리에 신경쓰지 않아도 된다.
  // 쿼리스트링(queryString)
  // UriComponentsBuilder 클래스 라이브러리 사용해서 자동으로
  // ?pageNum=2&amp;amp;amount=10&amp;amp;keyword=kenik&amp;amp;type=W  이렇게 뒤에 붙는다. (jsp에서 지저분하게 안해도 됨)   
  public String getListLink() {
     String path = &quot;&quot;;
     UriComponentsBuilder builder  = 
           UriComponentsBuilder.fromPath(path)
           .queryParam(&quot;pageNum&quot;, this.pageNum)
           .queryParam(&quot;amount&quot;, this.amount)
           .queryParam(&quot;type&quot;, this.getType())
           .queryParam(&quot;keyword&quot;, this.keyword) 
           ;      
     return builder.toUriString();
  }

}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;20.&lt;/p&gt;
&lt;p&gt;list.jsp&amp;nbsp;&lt;/p&gt;
&lt;p&gt;검색을 위한 태그&lt;/p&gt;
&lt;pre id=&quot;code_1613997810675&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;   &amp;lt;form id='searchForm' action=&quot;/board/list&quot; method='get'&amp;gt;
      &amp;lt;select name='type'&amp;gt;
         &amp;lt;option value=&quot;&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type == null?'selected':''}&quot;/&amp;gt;&amp;gt;--&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;T&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'T'?'selected':''}&quot;/&amp;gt;&amp;gt;제목&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;C&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'C'?'selected':''}&quot;/&amp;gt;&amp;gt;내용&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;W&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'W'?'selected':''}&quot;/&amp;gt;&amp;gt;작성자&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;TC&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'TC'?'selected':''}&quot;/&amp;gt;&amp;gt;제목
            or 내용&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;TW&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'TW'?'selected':''}&quot;/&amp;gt;&amp;gt;제목
            or 작성자&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;TWC&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'TWC'?'selected':''}&quot;/&amp;gt;&amp;gt;제목
            or 내용 or 작성자&amp;lt;/option&amp;gt;
      &amp;lt;/select&amp;gt; 
      &amp;lt;input  type='text' name='keyword' value='&amp;lt;c:out value=&quot;${pageMaker.cri.keyword}&quot;/&amp;gt;' /&amp;gt; 
      &amp;lt;input  type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${pageMaker.cri.pageNum}&quot;/&amp;gt;' /&amp;gt; 
      &amp;lt;input  type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${pageMaker.cri.amount}&quot;/&amp;gt;' /&amp;gt;
      &amp;lt;button class='btn btn-default'&amp;gt;Search&amp;lt;/button&amp;gt;
   &amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;검색을 위한 스크립트&lt;/p&gt;
&lt;pre id=&quot;code_1613997827466&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
//p342 검색을 위한
var searchForm = $(&quot;#searchForm&quot;);

$(&quot;#searchForm button&quot;).on( &quot;click&quot;, function(e) {

			if (!searchForm.find(&quot;option:selected&quot;).val()) {
				alert(&quot;검색종류를 선택하세요&quot;);
				return false;
			}
			if (!searchForm.find( &quot;input[name='keyword']&quot;).val()) {
				alert(&quot;키워드를 입력하세요&quot;);
				return false;
			}
			
			searchForm.find(&quot;input[name='pageNum']&quot;).val(&quot;1&quot;);
			e.preventDefault();
			
			searchForm.submit();
		});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;21.&lt;/p&gt;
&lt;p&gt;총&amp;nbsp;레코드&amp;nbsp;수&amp;nbsp;가져올때도&amp;nbsp;검색된&amp;nbsp;것의&amp;nbsp;총&amp;nbsp;레코드&amp;nbsp;수를&amp;nbsp;가져와야&amp;nbsp;페이징&amp;nbsp;처리&amp;nbsp;가능 &lt;br /&gt;=&amp;gt;&amp;nbsp;반복적으로&amp;nbsp;써지기&amp;nbsp;때문에&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BoardMapper.xml&lt;/p&gt;
&lt;pre id=&quot;code_1613998005402&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot; ?&amp;gt;
&amp;lt;!DOCTYPE mapper
  PUBLIC &quot;-//mybatis.org//DTD Mapper 3.0//EN&quot;
  &quot;http://mybatis.org/dtd/mybatis-3-mapper.dtd&quot;&amp;gt;
&amp;lt;mapper namespace=&quot;org.zerock.mapper.BoardMapper&quot;&amp;gt;


	&amp;lt;sql id=&quot;criteria&quot;&amp;gt;
		&amp;lt;trim prefix=&quot;(&quot; suffix=&quot;) AND &quot; prefixOverrides=&quot;OR&quot;&amp;gt;
			&amp;lt;foreach item='type' collection=&quot;typeArr&quot;&amp;gt;
				&amp;lt;trim prefix=&quot;OR&quot;&amp;gt;
					&amp;lt;choose&amp;gt;
						&amp;lt;when test=&quot;type == 'T'.toString()&quot;&amp;gt;
							title like '%'||#{keyword}||'%'
						&amp;lt;/when&amp;gt;
						&amp;lt;when test=&quot;type == 'C'.toString()&quot;&amp;gt;
							content like '%'||#{keyword}||'%'
						&amp;lt;/when&amp;gt;
						&amp;lt;when test=&quot;type == 'W'.toString()&quot;&amp;gt;
							writer like '%'||#{keyword}||'%'
						&amp;lt;/when&amp;gt;
					&amp;lt;/choose&amp;gt;
				&amp;lt;/trim&amp;gt;
			&amp;lt;/foreach&amp;gt;
		&amp;lt;/trim&amp;gt;
	&amp;lt;/sql&amp;gt;


	&amp;lt;select id=&quot;getList&quot; resultType=&quot;org.zerock.domain.BoardVO&quot;&amp;gt;
	&amp;lt;![CDATA[
		select * from tbl_board where bno &amp;gt; 0 
		]]&amp;gt;
	&amp;lt;/select&amp;gt;

	&amp;lt;insert id=&quot;insert&quot;&amp;gt;
		insert into tbl_board (bno,title,content,writer)
		values (seq_board.nextval, #{title}, #{content}, #{writer})
	&amp;lt;/insert&amp;gt;

	&amp;lt;insert id=&quot;insertSelectKey&quot;&amp;gt;

		&amp;lt;selectKey keyProperty=&quot;bno&quot; order=&quot;BEFORE&quot;
			resultType=&quot;long&quot;&amp;gt;
			select seq_board.nextval from dual
		&amp;lt;/selectKey&amp;gt;

		insert into tbl_board (bno,title,content, writer)
		values (#{bno},
		#{title}, #{content}, #{writer})
	&amp;lt;/insert&amp;gt;

	&amp;lt;select id=&quot;read&quot; resultType=&quot;org.zerock.domain.BoardVO&quot;&amp;gt;
		select * from tbl_board where bno =
		#{bno}
	&amp;lt;/select&amp;gt;


	&amp;lt;delete id=&quot;delete&quot;&amp;gt;
		delete tbl_board where bno = #{bno}
	&amp;lt;/delete&amp;gt;

	&amp;lt;update id=&quot;update&quot;&amp;gt;
		update tbl_board
		set title= #{title},
		content=#{content},
		writer = #{writer},
		updateDate = sysdate
		where bno =
		#{bno}
	&amp;lt;/update&amp;gt;

	&amp;lt;!-- &amp;lt;select id=&quot;getListWithPaging&quot; resultType=&quot;org.zerock.domain.BoardVO&quot;&amp;gt; 
		&amp;lt;![CDATA[ select bno, title, content, writer, regdate, updatedate from ( 
		select /*+INDEX_DESC(tbl_board pk_board) */ rownum rn, bno, title, content, 
		writer, regdate, updatedate from tbl_board where rownum &amp;lt;= #{pageNum} * #{amount} 
		) where rn &amp;gt; (#{pageNum} -1) * #{amount} ]]&amp;gt; &amp;lt;/select&amp;gt; --&amp;gt;


	&amp;lt;select id=&quot;getListWithPaging&quot;
		resultType=&quot;org.zerock.domain.BoardVO&quot;&amp;gt;
  &amp;lt;![CDATA[
  select 
    bno, title, content, writer, regdate, updatedate
  from 
      (
      select /*+INDEX_DESC(tbl_board pk_board) */
        rownum rn, bno, title, content, writer, regdate, updatedate 
      from 
        tbl_board
      where 
  ]]&amp;gt;
		&amp;lt;include refid=&quot;criteria&quot;&amp;gt;&amp;lt;/include&amp;gt;
      
  &amp;lt;![CDATA[    
      rownum &amp;lt;= #{pageNum} * #{amount}
      )
  where rn &amp;gt; (#{pageNum} -1) * #{amount}   
  ]]&amp;gt;
	&amp;lt;/select&amp;gt;




	&amp;lt;select id=&quot;getTotalCount&quot; resultType=&quot;int&quot;&amp;gt;
		select count(*) from tbl_board where 
		
		&amp;lt;include refid=&quot;criteria&quot;&amp;gt;&amp;lt;/include&amp;gt; 
		
		bno &amp;gt; 0
		
	&amp;lt;/select&amp;gt;

&amp;lt;/mapper&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;22.&lt;/p&gt;
&lt;p&gt;페이징&amp;nbsp;토탈&amp;nbsp;카운트할때도&amp;nbsp;위&amp;nbsp;trim&amp;nbsp;코딩이&amp;nbsp;필요하니&amp;nbsp;이&amp;nbsp;코딩을&amp;nbsp;sql이라는&amp;nbsp;태그로&amp;nbsp;하나&amp;nbsp;빼자&amp;nbsp; &lt;br /&gt;=&amp;gt;&amp;nbsp;중복해서&amp;nbsp;사용되는&amp;nbsp;동적SQL&amp;nbsp;쿼리&amp;nbsp;부분을&amp;nbsp;sql&amp;nbsp;태그&amp;nbsp;사용해서&amp;nbsp;하나&amp;nbsp;뺌 &lt;br /&gt;&amp;lt;sql&amp;nbsp;id=&quot;criteria&quot;&amp;gt;&amp;lt;/sql&amp;gt; &lt;br /&gt;필요한&amp;nbsp;곳에&amp;nbsp;&amp;lt;include&amp;nbsp;refid=&quot;criteria&quot;&amp;gt;&amp;lt;/include&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;23.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;test하기&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;24.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;25.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;검색 버튼의 이벤트 처리 - list.jsp&lt;/p&gt;
&lt;pre id=&quot;code_1613998084042&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    &amp;lt;form id='actionForm' action=&quot;/board/list&quot; method='get'&amp;gt; 
      &amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${pageMaker.cri.pageNum}&quot;/&amp;gt;' /&amp;gt; 
      &amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${pageMaker.cri.amount}&quot;/&amp;gt;' /&amp;gt;
    	&amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${ pageMaker.cri.type }&quot;/&amp;gt;'&amp;gt; 
    	&amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${ pageMaker.cri.keyword }&quot;/&amp;gt;'&amp;gt;
    &amp;lt;/form&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;26.&lt;/p&gt;
&lt;p&gt;조회 페이지에서 검색 추가 -&lt;/p&gt;
&lt;p&gt;get.jsp operForm에&lt;/p&gt;
&lt;pre id=&quot;code_1613998117734&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${cri.keyword}&quot;/&amp;gt;'&amp;gt;
&amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${cri.type}&quot;/&amp;gt;'&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;modify.jsp&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1613998147630&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${cri.type }&quot;/&amp;gt;'&amp;gt;
&amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${cri.keyword }&quot;/&amp;gt;'&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;27.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨트롤러&amp;nbsp;1)&amp;nbsp;modify에&amp;nbsp;추가,&amp;nbsp;2)&amp;nbsp;remove&amp;nbsp;수정&lt;/p&gt;
&lt;pre id=&quot;code_1613998183093&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	 	   @PostMapping(&quot;/modify&quot;)
			public String modify(BoardVO board, @ModelAttribute(&quot;cri&quot;) Criteria cri, RedirectAttributes rttr) {
				log.info(&quot;modify:&quot; + board);
	
				if (service.modify(board)) {
					rttr.addFlashAttribute(&quot;result&quot;, &quot;success&quot;);
				}
	
				rttr.addAttribute(&quot;pageNum&quot;, cri.getPageNum());
				rttr.addAttribute(&quot;amount&quot;, cri.getAmount());
				
				rttr.addAttribute(&quot;type&quot;, cri.getType()); //얘네 두개 추가
				rttr.addAttribute(&quot;keyword&quot;, cri.getKeyword()); //얘네 두개 추가
	
				return &quot;redirect:/board/list&quot;;
			}   
				// p.220
	   /*
	   @PostMapping(&quot;/remove&quot;)
	   public String remove(@RequestParam(&quot;bno&quot;) Long bno, RedirectAttributes rttr)
	   {

	      log.info(&quot;remove...&quot; + bno);
	      if (service.remove(bno)) {
	         rttr.addFlashAttribute(&quot;result&quot;, &quot;success&quot;);
	      }
	      
	      return &quot;redirect:/board/list&quot;;
	   }
	   */
	   @PostMapping(&quot;/remove&quot;)
		public String remove(@RequestParam(&quot;bno&quot;) Long bno, Criteria cri, RedirectAttributes rttr) {

			log.info(&quot;remove...&quot; + bno);
			if (service.remove(bno)) {
				rttr.addFlashAttribute(&quot;result&quot;, &quot;success&quot;);
			}
			rttr.addAttribute(&quot;pageNum&quot;, cri.getPageNum());
			rttr.addAttribute(&quot;amount&quot;, cri.getAmount());
			rttr.addAttribute(&quot;type&quot;, cri.getType());
			rttr.addAttribute(&quot;keyword&quot;, cri.getKeyword());

			return &quot;redirect:/board/list&quot;;
		}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;28.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;modify.jsp 가서 주석 풀기&lt;/p&gt;
&lt;pre id=&quot;code_1613998210685&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;            var keywordTag = $(&quot;input[name='keyword']&quot;).clone();
            var typeTag = $(&quot;input[name='type']&quot;).clone();    
            
            formObj.append(keywordTag);
            formObj.append(typeTag);  &lt;/code&gt;&lt;/pre&gt;</description>
      <category>Spring</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/308</guid>
      <comments>https://daspace.tistory.com/308#entry308comment</comments>
      <pubDate>Mon, 22 Feb 2021 21:22:49 +0900</pubDate>
    </item>
    <item>
      <title>[days14] [페이징 처리] 및 검색 기능 구현  (1/2)</title>
      <link>https://daspace.tistory.com/307</link>
      <description>&lt;p&gt;&lt;b&gt;ex02_02&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;background-color: #dddddd;&quot;&gt;&lt;b&gt;1. 페이징&amp;nbsp;처리&lt;/b&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1.&lt;/p&gt;
&lt;p&gt;페이징 처리에 필요한 파라미터&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1) 현재 페이지 번호 2)한 페이지당 몇개의 데이터를 보여줄 것인지&lt;/p&gt;
&lt;p&gt;=&amp;gt; 위 데이터들을 하나의 객체로 묶어서 클래스를 만들자 (확장성을 위해)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;org.zerock.domain.Criteria 클래스 추가&lt;/p&gt;
&lt;pre id=&quot;code_1613986188929&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.domain;

import org.springframework.web.util.UriComponentsBuilder;

import lombok.Getter;
import lombok.Setter;
import lombok.ToString;


@ToString
@Setter
@Getter
public class Criteria {

  private int pageNum;
  private int amount;
  
 // private String type;
 // private String keyword;

  public Criteria() {
    this(1, 10);
  }

  public Criteria(int pageNum, int amount) {
    this.pageNum = pageNum;
    this.amount = amount;
  }
  /*
  public String[] getTypeArr() {
    return type == null? new String[] {}: type.split(&quot;&quot;);
    //TC 이면 T하나 C하나 잘라 배열로 만듦
  }
  */
  /*
  // p 349
  // 가장 편리한 점 한글 처리에 신경쓰지 않아도 된다.
  // 쿼리스트링(queryString)
  // UriComponentsBuilder 클래스 라이브러리 사용해서 자동으로
  // ?pageNum=2&amp;amp;amount=10&amp;amp;keyword=kenik&amp;amp;type=W  이렇게 뒤에 붙는다. (jsp에서 지저분하게 안해도 됨)   
  public String getListLink() {
     String path = &quot;&quot;;
     UriComponentsBuilder builder  = 
           UriComponentsBuilder.fromPath(path)
           .queryParam(&quot;pageNum&quot;, this.pageNum)
           .queryParam(&quot;amount&quot;, this.amount)
           .queryParam(&quot;type&quot;, this.getType())
           .queryParam(&quot;keyword&quot;, this.keyword) 
           ;      
     return builder.toUriString();
  }
*/
  
  
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;주석부분들은 이따 검색하기 위한 부분들이니 일단 신경쓰지 말고&amp;nbsp;&lt;/p&gt;
&lt;p&gt;pageNum(페이지 수)와 amount(현재 페이지에 뿌릴 게시글 수) 필드와 생성자들을 만들었다.&lt;/p&gt;
&lt;p&gt;위 클래스는 MyBatis에서도 사용됨을 기억하자(중요)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;interface&amp;nbsp;BoardMapper에&amp;nbsp;Criteria&amp;nbsp;타입을&amp;nbsp;파라미터로&amp;nbsp;사용하는&amp;nbsp;메소드&amp;nbsp;작성&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;611&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bmvgsz/btqX81VspML/k03FmKC0lRkQ39ORst9mZk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bmvgsz/btqX81VspML/k03FmKC0lRkQ39ORst9mZk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bmvgsz/btqX81VspML/k03FmKC0lRkQ39ORst9mZk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbmvgsz%2FbtqX81VspML%2Fk03FmKC0lRkQ39ORst9mZk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;611&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;3.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BoardMapper.xml에 코딩 추가 (페이징을 위한 쿼리)&lt;/p&gt;
&lt;pre id=&quot;code_1613986490571&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;select id=&quot;getListWithPaging&quot; resultType=&quot;org.zerock.domain.BoardVO&quot;&amp;gt; 
		&amp;lt;![CDATA[ 
          select 
            bno, title, content, writer, regdate, updatedate 
          from ( 
		    select /*+INDEX_DESC(tbl_board pk_board) */ 
              rownum rn, bno, title, content, writer, regdate, updatedate 
            from 
              tbl_board 
            where 
              rownum &amp;lt;= #{pageNum} * #{amount} 
		  ) 
          where 
            rn &amp;gt; (#{pageNum} -1) * #{amount} 
        ]]&amp;gt; 
&amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;단위 테스트 작업&lt;/p&gt;
&lt;pre id=&quot;code_1613986564711&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//페이징 테스트
@Test
public void testPaging() {

	Criteria cri = new Criteria();
		
	//10개씩 3페이지 
	cri.setPageNum(2);
	cri.setAmount(3);

	List&amp;lt;BoardVO&amp;gt; list = mapper.getListWithPaging(cri);
	list.forEach(board -&amp;gt; log.info(board));
    
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;5.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BoardService 인터페이스 수정&lt;/p&gt;
&lt;p&gt;public List&amp;lt;BoardVO&amp;gt; getList();&amp;nbsp; ---&amp;gt;&amp;nbsp; public List&amp;lt;BoardVO&amp;gt; getList(Criteria cri);&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;473&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bpovej/btqYbHJblhx/i5C9vS5ed5mdRXKq2fBVB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bpovej/btqYbHJblhx/i5C9vS5ed5mdRXKq2fBVB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bpovej/btqYbHJblhx/i5C9vS5ed5mdRXKq2fBVB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbpovej%2FbtqYbHJblhx%2Fi5C9vS5ed5mdRXKq2fBVB1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;473&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;6.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BoardController 수정&lt;/p&gt;
&lt;pre id=&quot;code_1613986885375&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/*
	@GetMapping(&quot;/list&quot;)
	public void list(Model model) {

		log.info(&quot;list&quot;);
		model.addAttribute(&quot;list&quot;, service.getList()); 

	}
*/
	
	@GetMapping(&quot;/list&quot;)
	 public void list(Criteria cri, Model model) {
	
	 log.info(&quot;list: &quot; + cri);
	 model.addAttribute(&quot;list&quot;, service.getList(cri));
	
	}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;7. 페이징 화면 처리&lt;/p&gt;
&lt;p&gt;home.jsp&lt;/p&gt;
&lt;pre id=&quot;code_1613986932219&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;a href=&quot;/board/list?pageNum=2&amp;amp;amount=3&quot;&amp;gt;/board/list?pageNum=2&amp;amp;amount=3&amp;lt;/a&amp;gt; 	
&amp;lt;br&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;490&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WhQ7N/btqX81Vtd58/Hwa3IHzyUetqxMgd6WWem0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WhQ7N/btqX81Vtd58/Hwa3IHzyUetqxMgd6WWem0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WhQ7N/btqX81Vtd58/Hwa3IHzyUetqxMgd6WWem0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWhQ7N%2FbtqX81Vtd58%2FHwa3IHzyUetqxMgd6WWem0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;490&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9QJbb/btqYbHPUdY3/rkM1gOw7nzARTPkuj6Lk21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9QJbb/btqYbHPUdY3/rkM1gOw7nzARTPkuj6Lk21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9QJbb/btqYbHPUdY3/rkM1gOw7nzARTPkuj6Lk21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9QJbb%2FbtqYbHPUdY3%2FrkM1gOw7nzARTPkuj6Lk21%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;브라우저 주소창에 숫자를 입력해 확인할 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;8.&lt;/p&gt;
&lt;p&gt;페이징 블록 만들기&lt;/p&gt;
&lt;p&gt;- jsp 페이지 번호 출력 &lt;br /&gt;-&amp;nbsp;각&amp;nbsp;페이지&amp;nbsp;번호에&amp;nbsp;클릭&amp;nbsp;이벤트&amp;nbsp;처리 &lt;br /&gt;-&amp;nbsp;전체&amp;nbsp;데이터&amp;nbsp;개수를&amp;nbsp;반영해&amp;nbsp;페이지&amp;nbsp;번호&amp;nbsp;조절 &lt;br /&gt;-&amp;nbsp;하나의&amp;nbsp;게시글&amp;nbsp;클릭&amp;nbsp;후&amp;nbsp;다시&amp;nbsp;이전&amp;nbsp;페이지로&amp;nbsp;돌아가기 &lt;br /&gt;&lt;br /&gt;페이징&amp;nbsp;처리할&amp;nbsp;때&amp;nbsp;필요한&amp;nbsp;정보들 &lt;br /&gt;-&amp;nbsp;현재&amp;nbsp;페이지&amp;nbsp;번호 &lt;br /&gt;-&amp;nbsp;이전,&amp;nbsp;다음&amp;nbsp;버튼의&amp;nbsp;표시&amp;nbsp;여부 &lt;br /&gt;-&amp;nbsp;화면에서&amp;nbsp;보여지는&amp;nbsp;페이지의&amp;nbsp;시작&amp;nbsp;번호와&amp;nbsp;끝&amp;nbsp;번호&amp;nbsp; &lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;9.&lt;/p&gt;
&lt;p&gt;페이지 블록을 위해 PageDTO를 생성하자&lt;/p&gt;
&lt;pre id=&quot;code_1613987172309&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package org.zerock.domain;

import lombok.Getter;
import lombok.ToString;
//p306
// 페이지 블럭 	&amp;lt; 1 [2] 3 4 ... 10 &amp;gt; 	을 만들기 위한 클래스 
@Getter
@ToString
public class PageDTO {

  private int startPage;
  private int endPage;
  private boolean prev, next;

  private int total;
  private Criteria cri;

  public PageDTO(Criteria cri, int total) {

    this.cri = cri;
    this.total = total;

    this.endPage = (int) (Math.ceil(cri.getPageNum() / 10.0)) * 10;

    this.startPage = this.endPage - 1;

    int realEnd = (int) (Math.ceil((total * 1.0) / cri.getAmount()));

    if (realEnd &amp;lt;= this.endPage) {
      this.endPage = realEnd;
    }

    this.prev = this.startPage &amp;gt; 1;

    this.next = this.endPage &amp;lt; realEnd;
  }
  
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;10.&lt;/p&gt;
&lt;p&gt;BoardMapper 인터페이스에 아래 메소드 추가&lt;/p&gt;
&lt;pre id=&quot;code_1613987260921&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public int getTotalCount(Criteria cri); // 총 게시글 수를 가져옴&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;11.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;board.xml 추가&lt;/p&gt;
&lt;pre id=&quot;code_1613987327917&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- p 339 --&amp;gt;
&amp;lt;select id=&quot;getTotalCount&quot; resultType=&quot;int&quot;&amp;gt;
	 select count(*) 
	from tbl_board 
	&amp;lt;!--  검색을 위한 것이니 일단 주석
	 where
	&amp;lt;include refid=&quot;criteria&quot;&amp;gt;&amp;lt;/include&amp;gt;
	bno &amp;gt; 0 
	--&amp;gt;
&amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;12.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BoardService 추가&lt;/p&gt;
&lt;p&gt;&amp;nbsp;public&amp;nbsp;int&amp;nbsp;getTotal(Criteria&amp;nbsp;cri);&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;570&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PDzHu/btqYhzwzr10/fKxrXCjyXb2nQhAVzYSGN0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PDzHu/btqYhzwzr10/fKxrXCjyXb2nQhAVzYSGN0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PDzHu/btqYhzwzr10/fKxrXCjyXb2nQhAVzYSGN0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPDzHu%2FbtqYhzwzr10%2FfKxrXCjyXb2nQhAVzYSGN0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;570&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BoardServiceImpe 추가&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @Override &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;public&amp;nbsp;int&amp;nbsp;getTotal(Criteria&amp;nbsp;cri)&amp;nbsp;{ &lt;br /&gt;&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;log.info(&quot;get total count&quot;); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;return mapper.getTotalCount(cri); &lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;}&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;548&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgcnrs/btqX33M3bEs/dDuEi0mHpmSmmy718dtwGK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgcnrs/btqX33M3bEs/dDuEi0mHpmSmmy718dtwGK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgcnrs/btqX33M3bEs/dDuEi0mHpmSmmy718dtwGK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbgcnrs%2FbtqX33M3bEs%2FdDuEi0mHpmSmmy718dtwGK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;548&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;13.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;BoardController 수정 - 아까 list 불러오던 메소드 재수정&lt;/p&gt;
&lt;pre id=&quot;code_1613987488607&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;	/*
	@GetMapping(&quot;/list&quot;)
	public void list(Model model) {

		log.info(&quot;list&quot;);
		model.addAttribute(&quot;list&quot;, service.getList()); 
	}
	*/
	/*
	@GetMapping(&quot;/list&quot;)
	 public void list(Criteria cri, Model model) {
	
	 log.info(&quot;list: &quot; + cri);
	 model.addAttribute(&quot;list&quot;, service.getList(cri));
	
	}
	*/
	// p 307
	   @GetMapping(&quot;/list&quot;)
	   public void list(Criteria cri, Model model) {

	      log.info(&quot;list: &quot; + cri);
	      
	      model.addAttribute(&quot;list&quot;, service.getList(cri));
	      //model.addAttribute(&quot;pageMaker&quot;, new PageDTO(cri, 11)); //  총게시글수 11으로 고정

	      int total = service.getTotal(cri);
	      log.info(&quot;total: &quot; + total);
	      model.addAttribute(&quot;pageMaker&quot;, new PageDTO(cri, total));
	   }
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;14.&lt;/p&gt;
&lt;p&gt;jsp파일에서 페이지 번호 부분 코딩&lt;/p&gt;
&lt;p&gt;-&amp;nbsp;페이지&amp;nbsp;번호&amp;nbsp;이벤트&amp;nbsp;처리&amp;nbsp;-&amp;nbsp;jsp에서&amp;nbsp;페이지&amp;nbsp;이동&amp;nbsp;태그에서&amp;nbsp;처리하면&amp;nbsp;관리(유지보수)어려우니 &lt;br /&gt;&amp;nbsp; form hidden태그 만들고 js로&amp;nbsp; &lt;br /&gt;&amp;nbsp; (요지: 코딩을 직접 페이지 태그에 줄줄이 넣지 않고 js로 만들어 넘기겠다 )&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;list.jsp&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1613987584399&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; prefix=&quot;fmt&quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

   &amp;lt;br&amp;gt;
   &amp;lt;a href=&quot;/board/register&quot;&amp;gt;register&amp;lt;/a&amp;gt;
   &amp;lt;br&amp;gt;
   &amp;lt;br&amp;gt;
   
   &amp;lt;table class=&quot;table table-striped table-bordered table-hover&quot;&amp;gt;
      &amp;lt;thead&amp;gt;
         &amp;lt;tr&amp;gt;
            &amp;lt;th&amp;gt;#번호&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;제목&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;작성자&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;작성일&amp;lt;/th&amp;gt;
            &amp;lt;th&amp;gt;수정일&amp;lt;/th&amp;gt;
         &amp;lt;/tr&amp;gt;
      &amp;lt;/thead&amp;gt;

      &amp;lt;c:forEach items=&quot;${list}&quot; var=&quot;board&quot;&amp;gt;
         &amp;lt;tr&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;c:out value=&quot;${board.bno}&quot; /&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;%-- p 314 1번 페이지가 뿌려질 것
            &amp;lt;td&amp;gt;
               &amp;lt;a href='/board/get?bno=&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'&amp;gt;
                  &amp;lt;c:out value=&quot;${board.title}&quot;/&amp;gt;
               &amp;lt;/a&amp;gt;
            &amp;lt;/td&amp;gt;
            --%&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;!-- 위 코딩 대신 얘로, js로 처리 - 가독성, 유지보수  --&amp;gt;
              &amp;lt;a class='move' href='&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'&amp;gt;
               &amp;lt;c:out value=&quot;${board.title}&quot; /&amp;gt;
              &amp;lt;/a&amp;gt;
            &amp;lt;/td&amp;gt; 

            &amp;lt;td&amp;gt;&amp;lt;c:out value=&quot;${board.writer}&quot; /&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;fmt:formatDate pattern=&quot;yyyy-MM-dd&quot;
                  value=&quot;${board.regdate}&quot; /&amp;gt;&amp;lt;/td&amp;gt;
            &amp;lt;td&amp;gt;&amp;lt;fmt:formatDate pattern=&quot;yyyy-MM-dd&quot;
                  value=&quot;${board.updateDate}&quot; /&amp;gt;&amp;lt;/td&amp;gt;
         &amp;lt;/tr&amp;gt;
      &amp;lt;/c:forEach&amp;gt;
   &amp;lt;/table&amp;gt;
   
   &amp;lt;br&amp;gt;
   
 
   &amp;lt;form id='searchForm' action=&quot;/board/list&quot; method='get'&amp;gt;
      &amp;lt;select name='type'&amp;gt;
         &amp;lt;option value=&quot;&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type == null?'selected':''}&quot;/&amp;gt;&amp;gt;--&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;T&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'T'?'selected':''}&quot;/&amp;gt;&amp;gt;제목&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;C&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'C'?'selected':''}&quot;/&amp;gt;&amp;gt;내용&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;W&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'W'?'selected':''}&quot;/&amp;gt;&amp;gt;작성자&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;TC&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'TC'?'selected':''}&quot;/&amp;gt;&amp;gt;제목
            or 내용&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;TW&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'TW'?'selected':''}&quot;/&amp;gt;&amp;gt;제목
            or 작성자&amp;lt;/option&amp;gt;
         &amp;lt;option value=&quot;TWC&quot;
            &amp;lt;c:out value=&quot;${pageMaker.cri.type eq 'TWC'?'selected':''}&quot;/&amp;gt;&amp;gt;제목
            or 내용 or 작성자&amp;lt;/option&amp;gt;
      &amp;lt;/select&amp;gt; 
      &amp;lt;input  type='text' name='keyword' value='&amp;lt;c:out value=&quot;${pageMaker.cri.keyword}&quot;/&amp;gt;' /&amp;gt; 
      &amp;lt;input  type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${pageMaker.cri.pageNum}&quot;/&amp;gt;' /&amp;gt; 
      &amp;lt;input  type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${pageMaker.cri.amount}&quot;/&amp;gt;' /&amp;gt;
      &amp;lt;button class='btn btn-default'&amp;gt;Search&amp;lt;/button&amp;gt;
   &amp;lt;/form&amp;gt;
    
    
    &amp;lt;!-- p 311 --&amp;gt;
    &amp;lt;form id='actionForm' action=&quot;/board/list&quot; method='get'&amp;gt; 
      &amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${pageMaker.cri.pageNum}&quot;/&amp;gt;' /&amp;gt; 
      &amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${pageMaker.cri.amount}&quot;/&amp;gt;' /&amp;gt;
    	&amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${ pageMaker.cri.type }&quot;/&amp;gt;'&amp;gt; 
    	&amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${ pageMaker.cri.keyword }&quot;/&amp;gt;'&amp;gt;
    &amp;lt;/form&amp;gt;
    
   &amp;lt;!-- p 308 --&amp;gt;
   &amp;lt;div class='pull-right'&amp;gt;
               &amp;lt;ul class=&quot;pagination&quot;&amp;gt;

                  &amp;lt;%--             &amp;lt;c:if test=&quot;${pageMaker.prev}&quot;&amp;gt;
              &amp;lt;li class=&quot;paginate_button previous&quot;&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;Previous&amp;lt;/a&amp;gt;
              &amp;lt;/li&amp;gt;
            &amp;lt;/c:if&amp;gt;

            &amp;lt;c:forEach var=&quot;num&quot; begin=&quot;${pageMaker.startPage}&quot;
              end=&quot;${pageMaker.endPage}&quot;&amp;gt;
              &amp;lt;li class=&quot;paginate_button&quot;&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;${num}&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;/c:forEach&amp;gt;

            &amp;lt;c:if test=&quot;${pageMaker.next}&quot;&amp;gt;
              &amp;lt;li class=&quot;paginate_button next&quot;&amp;gt;&amp;lt;a href=&quot;#&quot;&amp;gt;Next&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
            &amp;lt;/c:if&amp;gt; --%&amp;gt;

                  &amp;lt;c:if test=&quot;${pageMaker.prev}&quot;&amp;gt;
                     &amp;lt;li class=&quot;paginate_button previous&quot;&amp;gt;&amp;lt;a
                        href=&quot;${pageMaker.startPage -1}&quot;&amp;gt;Previous&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
                  &amp;lt;/c:if&amp;gt;

                  &amp;lt;c:forEach var=&quot;num&quot; begin=&quot;${pageMaker.startPage}&quot;
                     end=&quot;${pageMaker.endPage}&quot;&amp;gt;
                     &amp;lt;li class=&quot;paginate_button  ${pageMaker.cri.pageNum == num ? &quot;active&quot;:&quot;&quot;} &quot;&amp;gt;
                        &amp;lt;a href=&quot;${num}&quot;&amp;gt;${num}&amp;lt;/a&amp;gt;
                     &amp;lt;/li&amp;gt;
                  &amp;lt;/c:forEach&amp;gt;

                  &amp;lt;c:if test=&quot;${pageMaker.next}&quot;&amp;gt;
                     &amp;lt;li class=&quot;paginate_button next&quot;&amp;gt;&amp;lt;a
                        href=&quot;${pageMaker.endPage +1 }&quot;&amp;gt;Next&amp;lt;/a&amp;gt;&amp;lt;/li&amp;gt;
                  &amp;lt;/c:if&amp;gt;

               &amp;lt;/ul&amp;gt;
            &amp;lt;/div&amp;gt;
            &amp;lt;!--  end Pagination --&amp;gt;
         &amp;lt;/div&amp;gt;
         
 
&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
   $(document).ready(function(){
      var result = '&amp;lt;c:out value=&quot;${result}&quot;/&amp;gt;';
      
      checkModal(result);
      
      // p.257
      history.replaceState({}, null, null);
      
      function checkModal(result){
         if(result === '' || history.state) return;
         if( parseInt(result)&amp;gt;0 ) alert(&quot;게시글 &quot; + parseInt(result) +&quot; 번이 등록되었습니다. &quot;); 
      } 
   });
&amp;lt;/script&amp;gt;

&amp;lt;script&amp;gt;
  // p 312  버튼 클릭 이벤트
  var actionForm = $(&quot;#actionForm&quot;);
  $(&quot;.paginate_button a&quot;).on(&quot;click&quot;, function (e){
     e.preventDefault();
     console.log(&quot;click&quot;);
     actionForm.find(&quot;input[name='pageNum']&quot;).val($(this).attr(&quot;href&quot;)); //$(this).attr(&quot;href&quot;) == 3페이지
     actionForm.submit();
  });
&amp;lt;/script&amp;gt;

&amp;lt;script&amp;gt;
  // p 314 
  $(&quot;.move&quot;).on(&quot;click&quot;, function (e){
     e.preventDefault();
     console.log(&quot;click&quot;); 
     /* actionForm은 현재 페이지 번호와 amout가지고 있는 폼 */
     actionForm.append(&quot;&amp;lt;input type='hidden' name='bno' value='&quot;+$(this).attr(&quot;href&quot;)+&quot;'&amp;gt;&quot;);
     actionForm.attr(&quot;action&quot;, &quot;/board/get&quot;);
     actionForm.submit();
  });

&amp;lt;/script&amp;gt;

&amp;lt;script&amp;gt;
//p342 검색을 위한
var searchForm = $(&quot;#searchForm&quot;);

$(&quot;#searchForm button&quot;).on( &quot;click&quot;, function(e) {

			if (!searchForm.find(&quot;option:selected&quot;).val()) {
				alert(&quot;검색종류를 선택하세요&quot;);
				return false;
			}
			if (!searchForm.find( &quot;input[name='keyword']&quot;).val()) {
				alert(&quot;키워드를 입력하세요&quot;);
				return false;
			}
			
			searchForm.find(&quot;input[name='pageNum']&quot;).val(&quot;1&quot;);
			e.preventDefault();
			
			searchForm.submit();
		});
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코딩에서 주요 부분은&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;1. 페이지 버튼 태그&lt;/p&gt;
&lt;pre id=&quot;code_1613987761559&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- p 308 --&amp;gt;
&amp;lt;div class='pull-right'&amp;gt;
  &amp;lt;ul class=&quot;pagination&quot;&amp;gt;
    &amp;lt;c:if test=&quot;${pageMaker.prev}&quot;&amp;gt;
      &amp;lt;li class=&quot;paginate_button previous&quot;&amp;gt;
       &amp;lt;a href=&quot;${pageMaker.startPage -1}&quot;&amp;gt;Previous&amp;lt;/a&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;/c:if&amp;gt;

    &amp;lt;c:forEach var=&quot;num&quot; begin=&quot;${pageMaker.startPage}&quot; end=&quot;${pageMaker.endPage}&quot;&amp;gt;
      &amp;lt;li class=&quot;paginate_button  ${pageMaker.cri.pageNum == num ? &quot;active&quot;:&quot;&quot;} &quot;&amp;gt;
        &amp;lt;a href=&quot;${num}&quot;&amp;gt;${num}&amp;lt;/a&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;/c:forEach&amp;gt;

    &amp;lt;c:if test=&quot;${pageMaker.next}&quot;&amp;gt;
      &amp;lt;li class=&quot;paginate_button next&quot;&amp;gt;
        &amp;lt;a  href=&quot;${pageMaker.endPage +1 }&quot;&amp;gt;Next&amp;lt;/a&amp;gt;
      &amp;lt;/li&amp;gt;
    &amp;lt;/c:if&amp;gt;

  &amp;lt;/ul&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;!--  end Pagination --&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;번호의 출력 부분은 &amp;lt;c:out&amp;gt;을 이용해 출력하는 것이 좋지만 예제에서는 가독성의 문제로 일반 EL 이용&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. hidden을 모아 넘길 action 폼&lt;/p&gt;
&lt;pre id=&quot;code_1613987940074&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- p 311 --&amp;gt;
&amp;lt;form id='actionForm' action=&quot;/board/list&quot; method='get'&amp;gt; 
   &amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${pageMaker.cri.pageNum}&quot;/&amp;gt;' /&amp;gt; 
   &amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${pageMaker.cri.amount}&quot;/&amp;gt;' /&amp;gt;
   &amp;lt;!-- 검색을 위한
     &amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${ pageMaker.cri.type }&quot;/&amp;gt;'&amp;gt; 
     &amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${ pageMaker.cri.keyword }&quot;/&amp;gt;'&amp;gt;
    --&amp;gt;
 &amp;lt;/form&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;3. 페이지 버튼 클릭 이벤트 jQuery&lt;/p&gt;
&lt;pre id=&quot;code_1613987816242&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  // p 312  버튼 클릭 이벤트
  var actionForm = $(&quot;#actionForm&quot;);
  $(&quot;.paginate_button a&quot;).on(&quot;click&quot;, function (e){
     e.preventDefault();
     console.log(&quot;click&quot;);
     actionForm.find(&quot;input[name='pageNum']&quot;).val($(this).attr(&quot;href&quot;)); //$(this).attr(&quot;href&quot;) == x페이지
     actionForm.submit();
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&amp;nbsp; &amp;nbsp;4. 게시글 세부보기 클릭 jQuery&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613987870797&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  // p 314 
  $(&quot;.move&quot;).on(&quot;click&quot;, function (e){
     e.preventDefault();
     console.log(&quot;click&quot;); 
     /* actionForm은 현재 페이지 번호와 amout가지고 있는 폼 */
     actionForm.append(&quot;&amp;lt;input type='hidden' name='bno' value='&quot;+$(this).attr(&quot;href&quot;)+&quot;'&amp;gt;&quot;);
     actionForm.attr(&quot;action&quot;, &quot;/board/get&quot;);
     actionForm.submit();
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;어쨌든 게시글 세부보기로 가나 다른 페이지로 이동을 하나 action 폼이 submit된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;15.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;조회&amp;nbsp;또는&amp;nbsp;수정&amp;nbsp;페이지에서&amp;nbsp;List로&amp;nbsp;돌아가기&amp;nbsp;(1페이지가&amp;nbsp;아니라&amp;nbsp;보고있던&amp;nbsp;해당&amp;nbsp;페이지로&amp;nbsp;이동해야함) &lt;br /&gt;돌아갈&amp;nbsp;페이지&amp;nbsp;번호와&amp;nbsp;수량을&amp;nbsp;알고&amp;nbsp;있어야&amp;nbsp;돌아갈&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;(넘겨주는&amp;nbsp;작업) &lt;br /&gt;controller 수정&lt;/p&gt;
&lt;pre id=&quot;code_1613988058087&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/*
@GetMapping({ &quot;/get&quot;, &quot;/modify&quot; })
public void get(@RequestParam(&quot;bno&quot;) Long bno, Model model) {

	log.info(&quot;/get or modify &quot;);
	model.addAttribute(&quot;board&quot;, service.get(bno)); 
}
*/
@GetMapping({ &quot;/get&quot;, &quot;/modify&quot; })
public void get(@RequestParam(&quot;bno&quot;) Long bno, @ModelAttribute(&quot;cri&quot;) Criteria cri, Model model) {
					//@ModelAttribute ? 
					//모델에 담아 넘기겠다? 커맨드 객체는 안 담아도 넘어갔잖아 ? 
					//일단은 ...
	log.info(&quot;/get or modify&quot;);
	model.addAttribute(&quot;board&quot;, service.get(bno));
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;16.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;세부보기 jsp 수정&lt;/p&gt;
&lt;p&gt;get.jsp - list버튼&amp;nbsp;누를때&amp;nbsp;페이지번호&amp;nbsp;,&amp;nbsp;amout가지고&amp;nbsp;요청하도록&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1613988192816&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; prefix=&quot;fmt&quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
  
  &amp;lt;div class=&quot;panel panel-default&quot;&amp;gt;
   &amp;lt;h3&amp;gt;Board Read - p.251&amp;lt;/h3&amp;gt;
   
         &amp;lt;!-- /.panel-heading --&amp;gt;
       &amp;lt;div class=&quot;panel-body&quot;&amp;gt;

          &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Bno&amp;lt;/label&amp;gt; &amp;lt;input class=&quot;form-control&quot; name='bno'
            value='&amp;lt;c:out value=&quot;${board.bno }&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Title&amp;lt;/label&amp;gt; &amp;lt;input class=&quot;form-control&quot; name='title'
            value='&amp;lt;c:out value=&quot;${board.title }&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Text area&amp;lt;/label&amp;gt;
          &amp;lt;textarea class=&quot;form-control&quot; rows=&quot;3&quot; name='content'
            readonly=&quot;readonly&quot;&amp;gt;&amp;lt;c:out value=&quot;${board.content}&quot; /&amp;gt;&amp;lt;/textarea&amp;gt;
        &amp;lt;/div&amp;gt;

        &amp;lt;div class=&quot;form-group&quot;&amp;gt;
          &amp;lt;label&amp;gt;Writer&amp;lt;/label&amp;gt; &amp;lt;input class=&quot;form-control&quot; name='writer'
            value='&amp;lt;c:out value=&quot;${board.writer }&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;
        &amp;lt;/div&amp;gt;
&amp;lt;%-- 
        &amp;lt;button data-oper='modify' class=&quot;btn btn-default&quot;&amp;gt;
        &amp;lt;a href=&quot;/board/modify?bno=&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;&quot;&amp;gt;Modify&amp;lt;/a&amp;gt;&amp;lt;/button&amp;gt;
        &amp;lt;button data-oper='list' class=&quot;btn btn-info&quot;&amp;gt;
        &amp;lt;a href=&quot;/board/list&quot;&amp;gt;List&amp;lt;/a&amp;gt;&amp;lt;/button&amp;gt;  
 --%&amp;gt;
 
 &amp;lt;!-- data-oper  --&amp;gt;
 &amp;lt;!-- data-xxx='데이터'    :   어떤 데이터를 태그에 저장하고자 할 때  --&amp;gt;
   &amp;lt;button data-oper='modify' class=&quot;btn btn-default&quot;&amp;gt;Modify&amp;lt;/button&amp;gt;
   &amp;lt;button data-oper='list' class=&quot;btn btn-info&quot;&amp;gt;List&amp;lt;/button&amp;gt;
    

&amp;lt;%-- &amp;lt;form id='operForm' action=&quot;/boad/modify&quot; method=&quot;get&quot;&amp;gt;
  &amp;lt;input type='hidden' id='bno' name='bno' value='&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'&amp;gt;
&amp;lt;/form&amp;gt; --%&amp;gt;


    &amp;lt;!-- p 317 --&amp;gt;
   &amp;lt;form id='operForm' action=&quot;/boad/modify&quot; method=&quot;get&quot;&amp;gt;
     &amp;lt;input type='hidden' id='bno' name='bno' value='&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${cri.pageNum}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${cri.amount}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;!-- 검색된 결과의 조회페이지 --&amp;gt;
     &amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${cri.keyword}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${cri.type}&quot;/&amp;gt;'&amp;gt;
      
   &amp;lt;/form&amp;gt; 

   &amp;lt;/div&amp;gt;

    &amp;lt;/div&amp;gt;
&amp;lt;!-- p 265 --&amp;gt; 
&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
  $(document).ready(function (){
     var operForm = $(&quot;#operForm&quot;);
     
     // 수정
     $(&quot;button[data-oper='modify']&quot;).on(&quot;click&quot;, function (e){
        operForm.attr(&quot;action&quot;,&quot;/board/modify&quot;).submit();
     });
     //jQuery ${modify} ??
     
     //리스트 돌아가기
     //http://localhost/board/get?[pageNum=1&amp;amp;amount=10&amp;amp;bno=23] 
     $(&quot;button[data-oper='list']&quot;).on(&quot;click&quot;, function (e){
        operForm.find(&quot;#bno&quot;).remove();
        operForm.attr(&quot;action&quot;,&quot;/board/list&quot;).submit();
     });
  });
&amp;lt;/script&amp;gt;

&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위 코딩에서 주요 부분은&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;1.&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1613988240702&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;!-- p 317 --&amp;gt;
&amp;lt;form id='operForm' action=&quot;/boad/modify&quot; method=&quot;get&quot;&amp;gt;
     &amp;lt;input type='hidden' id='bno' name='bno' value='&amp;lt;c:out value=&quot;${board.bno}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${cri.pageNum}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${cri.amount}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;!-- 검색된 결과의 조회페이지 --&amp;gt;
     &amp;lt;!--
     &amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${cri.keyword}&quot;/&amp;gt;'&amp;gt;
     &amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${cri.type}&quot;/&amp;gt;'&amp;gt;
     --&amp;gt;
&amp;lt;/form&amp;gt; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;2. operForm을 submit - 1. 수정하러 갈 때 2. 돌아갈때&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1613988301401&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
  $(document).ready(function (){
     var operForm = $(&quot;#operForm&quot;);
     
     // 수정
     $(&quot;button[data-oper='modify']&quot;).on(&quot;click&quot;, function (e){
        operForm.attr(&quot;action&quot;,&quot;/board/modify&quot;).submit();
     });
     //jQuery ${modify} ??
     
     //리스트 돌아가기
     //http://localhost/board/get?[pageNum=1&amp;amp;amount=10&amp;amp;bno=23] 
     $(&quot;button[data-oper='list']&quot;).on(&quot;click&quot;, function (e){
        operForm.find(&quot;#bno&quot;).remove();
        operForm.attr(&quot;action&quot;,&quot;/board/list&quot;).submit();
     });
  });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;i&gt;&lt;span style=&quot;color: #ef6f53;&quot;&gt;&lt;b&gt;* data-xxx='데이터'&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;:&amp;nbsp;&amp;nbsp;&amp;nbsp;어떤&amp;nbsp;데이터를&amp;nbsp;태그에&amp;nbsp;저장하고자&amp;nbsp;할&amp;nbsp;때&lt;/b&gt;&lt;/span&gt;&lt;/i&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;17.&lt;/p&gt;
&lt;p&gt;게시글을 수정하는 jsp도 수정&lt;/p&gt;
&lt;p&gt;modify.jsp&lt;/p&gt;
&lt;pre id=&quot;code_1613988443898&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;%@ page contentType=&quot;text/html; charset=UTF-8&quot; pageEncoding=&quot;UTF-8&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/core&quot; prefix=&quot;c&quot;%&amp;gt;
&amp;lt;%@ taglib uri=&quot;http://java.sun.com/jsp/jstl/fmt&quot; prefix=&quot;fmt&quot;%&amp;gt;
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
&amp;lt;title&amp;gt;Insert title here&amp;lt;/title&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;

   &amp;lt;h3&amp;gt;Board Modify - p.259&amp;lt;/h3&amp;gt;

   &amp;lt;div class=&quot;panel-body&quot;&amp;gt;

      &amp;lt;form role=&quot;form&quot; action=&quot;/board/modify&quot; method=&quot;post&quot;&amp;gt;
      
        &amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${cri.pageNum }&quot;/&amp;gt;'&amp;gt;
        &amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${cri.amount }&quot;/&amp;gt;'&amp;gt;
        
       &amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${cri.type }&quot;/&amp;gt;'&amp;gt;
      &amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${cri.keyword }&quot;/&amp;gt;'&amp;gt;
       
 
      &amp;lt;div class=&quot;form-group&quot;&amp;gt;
        &amp;lt;label&amp;gt;Bno&amp;lt;/label&amp;gt; 
        &amp;lt;input class=&quot;form-control&quot; name='bno' 
           value='&amp;lt;c:out value=&quot;${board.bno }&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;
      &amp;lt;/div&amp;gt;
      
      &amp;lt;div class=&quot;form-group&quot;&amp;gt;
        &amp;lt;label&amp;gt;Title&amp;lt;/label&amp;gt; 
        &amp;lt;input class=&quot;form-control&quot; name='title' 
          value='&amp;lt;c:out value=&quot;${board.title }&quot;/&amp;gt;' &amp;gt;
      &amp;lt;/div&amp;gt;
      
      &amp;lt;div class=&quot;form-group&quot;&amp;gt;
        &amp;lt;label&amp;gt;Text area&amp;lt;/label&amp;gt;
        &amp;lt;textarea class=&quot;form-control&quot; rows=&quot;3&quot; name='content' &amp;gt;&amp;lt;c:out value=&quot;${board.content}&quot;/&amp;gt;&amp;lt;/textarea&amp;gt;
      &amp;lt;/div&amp;gt;
      
      &amp;lt;div class=&quot;form-group&quot;&amp;gt;
        &amp;lt;label&amp;gt;Writer&amp;lt;/label&amp;gt; 
        &amp;lt;input class=&quot;form-control&quot; name='writer'
          value='&amp;lt;c:out value=&quot;${board.writer}&quot;/&amp;gt;' readonly=&quot;readonly&quot;&amp;gt;            
      &amp;lt;/div&amp;gt;
      
      &amp;lt;div class=&quot;form-group&quot;&amp;gt;
        &amp;lt;label&amp;gt;RegDate&amp;lt;/label&amp;gt; 
        &amp;lt;input class=&quot;form-control&quot; name='regDate'
          value='&amp;lt;fmt:formatDate pattern = &quot;yyyy/MM/dd&quot; value = &quot;${board.regdate}&quot; /&amp;gt;'  readonly=&quot;readonly&quot;&amp;gt;            
      &amp;lt;/div&amp;gt;
      
      &amp;lt;div class=&quot;form-group&quot;&amp;gt;
        &amp;lt;label&amp;gt;Update Date&amp;lt;/label&amp;gt; 
        &amp;lt;input class=&quot;form-control&quot; name='updateDate'
          value='&amp;lt;fmt:formatDate pattern = &quot;yyyy/MM/dd&quot; value = &quot;${board.updateDate}&quot; /&amp;gt;'  readonly=&quot;readonly&quot;&amp;gt;            
      &amp;lt;/div&amp;gt;
   
             
   
     &amp;lt;button type=&quot;submit&quot; data-oper='modify' class=&quot;btn btn-default&quot;&amp;gt;Modify&amp;lt;/button&amp;gt;
     &amp;lt;button type=&quot;submit&quot; data-oper='remove' class=&quot;btn btn-danger&quot;&amp;gt;Remove&amp;lt;/button&amp;gt;
     &amp;lt;button type=&quot;submit&quot; data-oper='list' class=&quot;btn btn-info&quot;&amp;gt;List&amp;lt;/button&amp;gt;
     
   &amp;lt;/form&amp;gt;


   &amp;lt;/div&amp;gt; 

&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
   $(document).ready(function(){
       var formObj = $(&quot;form&quot;);

        $('button').on(&quot;click&quot;, function(e){
          
          e.preventDefault(); 
          
          var operation = $(this).data(&quot;oper&quot;);
          
          console.log(operation);
          
          if(operation === 'remove'){
            formObj.attr(&quot;action&quot;, &quot;/board/remove&quot;);
            
          }else if(operation === 'list'){
            //move to list
            formObj.attr(&quot;action&quot;, &quot;/board/list&quot;).attr(&quot;method&quot;,&quot;get&quot;);
            
            var pageNumTag = $(&quot;input[name='pageNum']&quot;).clone();
            var amountTag = $(&quot;input[name='amount']&quot;).clone();
            var keywordTag = $(&quot;input[name='keyword']&quot;).clone();
            var typeTag = $(&quot;input[name='type']&quot;).clone();      
            
            formObj.empty();
            
            formObj.append(pageNumTag);
            formObj.append(amountTag);
            formObj.append(keywordTag);
            formObj.append(typeTag);          
          }
          
          formObj.submit();
        });
   });
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;위 코딩에서 주요 부분&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;1. hidden으로 페이지 정보(와 검색 정보) 담기&lt;/p&gt;
&lt;pre id=&quot;code_1613988539230&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;input type='hidden' name='pageNum' value='&amp;lt;c:out value=&quot;${cri.pageNum }&quot;/&amp;gt;'&amp;gt;
&amp;lt;input type='hidden' name='amount' value='&amp;lt;c:out value=&quot;${cri.amount }&quot;/&amp;gt;'&amp;gt;
        
&amp;lt;input type='hidden' name='type' value='&amp;lt;c:out value=&quot;${cri.type }&quot;/&amp;gt;'&amp;gt;
&amp;lt;input type='hidden' name='keyword' value='&amp;lt;c:out value=&quot;${cri.keyword }&quot;/&amp;gt;'&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp;2. script&lt;/p&gt;
&lt;pre id=&quot;code_1613988494845&quot; class=&quot;html xml&quot; data-ke-language=&quot;html&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
   $(document).ready(function(){
       var formObj = $(&quot;form&quot;);

        $('button').on(&quot;click&quot;, function(e){
          
          e.preventDefault(); 
          
          var operation = $(this).data(&quot;oper&quot;);
          
          console.log(operation);
          
          if(operation === 'remove'){
            formObj.attr(&quot;action&quot;, &quot;/board/remove&quot;);
            
          }else if(operation === 'list'){
            //move to list
            formObj.attr(&quot;action&quot;, &quot;/board/list&quot;).attr(&quot;method&quot;,&quot;get&quot;);
            
            var pageNumTag = $(&quot;input[name='pageNum']&quot;).clone(); //clone()은 복제
            var amountTag = $(&quot;input[name='amount']&quot;).clone();
            var keywordTag = $(&quot;input[name='keyword']&quot;).clone();
            var typeTag = $(&quot;input[name='type']&quot;).clone();      
            
            formObj.empty();
            
            formObj.append(pageNumTag);
            formObj.append(amountTag);
            formObj.append(keywordTag);
            formObj.append(typeTag);          
          }
          
          formObj.submit();
        });
   });
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;컨트롤러 수정&lt;/p&gt;
&lt;pre id=&quot;code_1613988651053&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;/*
@PostMapping(&quot;/modify&quot;)
public String modify(BoardVO board, RedirectAttributes rttr) {
	log.info(&quot;modify:&quot; + board);
	
	if (service.modify(board)) {
		rttr.addFlashAttribute(&quot;result&quot;, &quot;success&quot;);
	}
	return &quot;redirect:/board/list&quot;;
}
*/

@PostMapping(&quot;/modify&quot;)
public String modify(BoardVO board, @ModelAttribute(&quot;cri&quot;) Criteria cri, RedirectAttributes rttr) {
	log.info(&quot;modify:&quot; + board);
		
	if (service.modify(board)) {
		rttr.addFlashAttribute(&quot;result&quot;, &quot;success&quot;);
	}
		
	rttr.addAttribute(&quot;pageNum&quot;, cri.getPageNum());
	rttr.addAttribute(&quot;amount&quot;, cri.getAmount());
	//rttr.addAttribute(&quot;type&quot;, cri.getType());
	//rttr.addAttribute(&quot;keyword&quot;, cri.getKeyword());
		
	return &quot;redirect:/board/list&quot;;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Spring</category>
      <author>다연</author>
      <guid isPermaLink="true">https://daspace.tistory.com/307</guid>
      <comments>https://daspace.tistory.com/307#entry307comment</comments>
      <pubDate>Mon, 22 Feb 2021 19:15:21 +0900</pubDate>
    </item>
  </channel>
</rss>