<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>풍림개발자</title>
    <link>https://khs0806.tistory.com/</link>
    <description>초보 개발자의 기록블로그</description>
    <language>ko</language>
    <pubDate>Fri, 10 Jul 2026 18:40:16 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>풍림개발자</managingEditor>
    <image>
      <title>풍림개발자</title>
      <url>https://tistory1.daumcdn.net/tistory/3528160/attach/7ee2a83d27ed4a7996c4668a8026b207</url>
      <link>https://khs0806.tistory.com</link>
    </image>
    <item>
      <title>구글에서 출시한 프레임워크, 플러터는?</title>
      <link>https://khs0806.tistory.com/33</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2Zbjd/btr1I9nJI7b/FA9eGgIWohjUFobtZ9oEQK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2Zbjd/btr1I9nJI7b/FA9eGgIWohjUFobtZ9oEQK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2Zbjd/btr1I9nJI7b/FA9eGgIWohjUFobtZ9oEQK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2Zbjd%2Fbtr1I9nJI7b%2FFA9eGgIWohjUFobtZ9oEQK%2Fimg.png&quot; width=&quot;100%&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;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;구글에서 2017년5월 출시한 모바일앱,데스크톱앱,웹브라우저(웹은 아직 갈길이 멀다..)&lt;br&gt;에서 전방위로 사용 가능한 크로스플랫폼 SDK이다. 하나의 코드 베이스로 iOS, macOS, 안드로이드,&lt;br&gt;윈도우,리눅스 및 웹브라우저에서 모두 동작되게 만들어졌다. 현재 구글의 차기 운영체제 퓨시아의 UI도&lt;br&gt;플러터로 개발중이다.&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;h4&gt;크로스플랫폼이란?  ️&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;기업은 고객에게 최우선으로 최상의 서비스를 제공하는 앱을 만들고 싶어한다.&lt;br&gt;하지만 iOS, 안드로이드용으로 네이티브 앱을 개발하는 것은 별도의 코드베이스를 따로 관리해야 하며&lt;br&gt;많은 비용과 시간이 투자되어야 하는데 이러한 문제를 해결하기 위해 나온 대책이 크로스플랫폼이다.&lt;br&gt;이러한 크로스플랫폼이 여러가지 있는데 대표적으로 플러터와 리액트 네이티브가 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;인기&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;크로스플랫폼의 인기는 나날이 높아지고 있다. 그중 플러터와 리액트네이티브가 가장 영향력이 높다.&lt;br&gt;리액트 네이티브는 2015년, 플러터는 2017년 출시하여 리액트 네이티브가 좀 더 오래되고 커다란 커뮤니티를&lt;br&gt;지니고 있고, 플러터 또한 2017년 출시 된 이후로 꾸준히 성장세이고 플러터3.0이 나온 지금 리액트 네이티브의&lt;br&gt;인기를 따라잡고 있다.&lt;br&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/EVWZi/btr1HgOuESc/sp0sqNacY1y1qemW36G2nk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/EVWZi/btr1HgOuESc/sp0sqNacY1y1qemW36G2nk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/EVWZi/btr1HgOuESc/sp0sqNacY1y1qemW36G2nk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FEVWZi%2Fbtr1HgOuESc%2Fsp0sqNacY1y1qemW36G2nk%2Fimg.png&quot; width=&quot;100%&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;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;학습&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;어떤 기술이 더 배우기 쉬울까..?&lt;br&gt;리액트 네이티브는 대부분의 개발자에게 익숙한 자바스크립트 기반의 JSC를 사용하고 있기 때문에 접근성이 쉽다.&lt;br&gt;대부분의 리액트 개발자는 역시 별다른 학습 없이 앱개발을 시작할 수 있을것이다.&lt;br&gt;하지만 플러터는 대부분의 개발자에게 생소한 다트(Dart) 언어를 사용하기 때문에&lt;br&gt;플러터를 익히기 위해서는 이 언어를 배워야 한다는 진입장벽이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;성능&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;플러터는 Dart기반의 프레임워크이며, skia2 GUI 와 C/C++ 엔진을 사용한다.&lt;br&gt;이러한 언어적 특성으로 네이티브플랫폼과 플러터간 추가적인 변환이 필요하지 않아서 더 빠른 성능을 보여준다.&lt;br&gt;반면 리액트 네이티브는 JS Bridge라는 자바스크립트 런타임 환경을 사용하여 네이티브플랫폼간의 연결을 만들기&lt;br&gt;때문에 성능에 영향을 미치게 된다. 하지만 여러 커뮤니티에서 이런한 성능을 향상시키기 위한 노력이 꾸준히&lt;br&gt;이야기 되고 있고 페이스북에서 성능을 개선하기 위한 헤르메스라는 새로운 자바스크립트 엔진을 발표하기도 했다.&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>앱개발</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/33</guid>
      <comments>https://khs0806.tistory.com/33#entry33comment</comments>
      <pubDate>Thu, 2 Mar 2023 23:42:42 +0900</pubDate>
    </item>
    <item>
      <title>생성자에 매개변수가 많다면 빌더를 고려하라.</title>
      <link>https://khs0806.tistory.com/32</link>
      <description>&lt;p&gt;&lt;em&gt;#이펙티브 자바&lt;/em&gt;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;정적 팩터리와 생성자에는 매개변수가 많을수록 적절히 대응하기 어렵다는 단점이 있다.&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;&lt;ol&gt;
&lt;li&gt;&lt;p&gt;식품의 영양정보를 표기하는 클래스를 만들어보자.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;영양정보는 1회내용량, 총n회제공량, 1회제공량당 칼로리 같은 필수항목과 총 지방 트랜스지방, 포화지방, 콜레스테롤, 나트륨 등 총 20개가 넘는 항목으로 이루어진다.&lt;/li&gt;
&lt;li&gt;이런 클래스의 생성자 혹은 정적 팩터리는 어떤 모습일까?&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;점층적 생성자 패턴을 주로 사용&lt;/strong&gt;한다. &lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;// 점층적 생성자 패턴기법
public class NutritionFacts{
    private final int servingSize;  // 필수
    private final int servings;     // 필수
    private final int calories;     // 선택
    private final int fat;          // 선택
    private final int sodium;       // 선택
    private final int carbohydrate; // 선택

    public NutritionFacts(int servingSize, int servings){
        this(servingSize, servings, 10);
    }

    public NutritionFacts(int servingSize, int servings, int calories){
        this(servingSize, servings, calories, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories,
                          int fat){
        this(servingSize, servings, calories, fat, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories,
                          int fat, int sodium){
        this(servingSize, servings, calories, fat, sodium, 0);
    }

    public NutritionFacts(int servingSize, int servings, int calories,
                          int fat, int sodium, int carbohydrate){
        this.servingSize = servingSize;
        this.servings = servings;
        this.calories = calories;
        this.fat = fat;
        this.sodium = sodium;
        this.carbohydrate = carbohydrate;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;이러한 경우 원하는 객체를 만들기 위해 원하는 매개변수를 포함하는 생성자를 골라 호출하면 된다.&lt;/li&gt;
&lt;li&gt;하지만 &lt;strong&gt;매개변수가 늘어나게 되면 금세 걷잡을 수 없게 된다.&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;점층적 생성자 패턴의 대안&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;자바빈즈 패턴&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;class NutritionFacts{

    private int servingSize  = -1;  // 필수
    private int servings     = -1;  // 필수
    private int calories     = 0;   // 선택
    private int fat          = 0;   // 선택
    private int sodium       = 0;   // 선택
    private int carbohydrate = 0;   // 선택

    public NutritionFacts() { }

    public void setServingSize(int servingSize) {
        this.servingSize = servingSize;
    }

    public void setServings(int servings) {
        this.servings = servings;
    }

    public void setCalories(int calories) {
        this.calories = calories;
    }

    public void setFat(int fat) {
        this.fat = fat;
    }

    public void setSodium(int sodium) {
        this.sodium = sodium;
    }

    public void setCarbohydrate(int carbohydrate) {
        this.carbohydrate = carbohydrate;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;NutritionFacts cocaCola = new NutritionFacts();
cocaCola.setServingSize(240);
cocaCola.setServings(8);
cocaCola.setCalories(100);
cocaCola.setSodium(35);
cocaCola.setCarbohydrate(27);&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;자바빈즈 패턴에선 점층적 생성자 패턴의 문제가 보이지 않는다.&lt;/li&gt;
&lt;li&gt;하지만 심각한 단점이 있다.&lt;br&gt;객체 하나를 만들기 위해 여러 메서드를 호출해야하고 객체가 완성되기 전까진 일관성이&lt;br&gt;유지되지 못하게 된다. 이러한 문제로 자바빈즈 패턴에선 불변클래스를 얻을 수 없게 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;빌더 패턴&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;필요한 객체를 직접 만드는 대신 필수 매개변수만으로 생성자를 호출하여 빌더 객체를 얻은 후에 원하는 선택매개변수들을 세터 메서드를 이용하여 설정하고 마지막으로 매개변수가 없는 build()메서드로 원하는 객체를 얻는다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;class NutritionFacts{
    private final int servingSize;
    private final int servings;
    private final int calories;
    private final int fat;
    private final int sodium;
    private final int carbohydrate;

    public static class Builder{
        // 필수 매개변수
        private final int servingSize;
        private final int servings;

        // 선택 매개변수
        private int calories     = 0;
        private int fat          = 0;
        private int sodium       = 0;
        private int carbohydrate = 0;

        public Builder(int servingSize, int servings) {
            this.servingSize = servingSize;
            this.servings = servings;
        }

        public Builder calories(int calories){
            this.calories = calories;
            return this;
        }

        public Builder fat(int fat){
            this.fat = fat;
            return this;
        }

        public Builder sodium(int sodium){
            this.sodium = sodium;
            return this;
        }

        public Builder carbohydrate(int carbohydrate){
            this.carbohydrate = carbohydrate;
            return this;
        }

        public NutritionFacts build(){
            return new NutritionFacts(this);
        }
    }

    private NutritionFacts(Builder builder){
        servingSize  = builder.servingSize;
        servings     = builder.servings;
        calories     = builder.calories;
        fat          = builder.fat;
        sodium       = builder.sodium;
        carbohydrate = builder.carbohydrate;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;빌더패턴을 사용하면 &lt;strong&gt;NutritionFacts&lt;/strong&gt; 클래스는 불변객체로 활용할수 있으며, 코드를 쓰기 쉽게할 수 있으며, 읽기도 쉬워진다. &lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote data-ke-style=&quot;style1&quot;&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;font-family: 'Noto Serif KR';&quot;&gt;&lt;p&gt;필자도 현업에 종사하면서 매개변수가 많은 생성자들을 많이 접해봤고 작성도 해보았다.&lt;br&gt;이러한 코드를 작성할때마다 느꼈지만 복잡하고 난해하기 그지없었다. 매개변수의 순서와 타입까지 맞춰줘야 하니까 말이다. 잘못된 매개변수값을 던지면 런타임시점에서 잡아주지도 못하기 때문에 항상 주된 에러를 일으키는 주범이기도 한데 빌더 패턴을 이용하면 이러한 문제들이 해결될 것으로 본다.&lt;/p&gt;
&lt;/span&gt;&lt;/p&gt;&lt;/blockquote&gt;</description>
      <category>JAVA</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/32</guid>
      <comments>https://khs0806.tistory.com/32#entry32comment</comments>
      <pubDate>Sun, 24 Jul 2022 14:22:26 +0900</pubDate>
    </item>
    <item>
      <title>생성자 대신 정적 팩터리 메서드를 고려하라.</title>
      <link>https://khs0806.tistory.com/31</link>
      <description>&lt;h3&gt;클래스의 객체를 얻는 수단 중 보편적인 방법은 public 생성자를 이용하는 것이다.&lt;/h3&gt;
&lt;h4&gt;하지만 더 좋은 수단이 하나 더 있다.&lt;/h4&gt;
&lt;p&gt;static method를 이용하는 것이다. 정적 팩터리 메서드를 사용한다는 것은 그 클래스의 인스턴스를 반환하는 메서드를 사용하는 것이다. Boolean.valueOf는 boolean 값을 받아 Boolean 객체를 반환해준다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;    public static Boolean valueOf(boolean c) {  
        return c ? Boolean.TRUE : Boolean.FALSE;  
    }&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이 방식에는 public 생성자를 이용하는 방식보다 좋은 점 5가지가 있다.&lt;/p&gt;
&lt;h4&gt;첫번째, 이름을 가질 수 있다.&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;public 생성자만으로는 반환될 객체의 특성을 제대로 설명하기 힘들다.&lt;br&gt;반면 정적 팩터리 메서드는 쉽게 묘사가 가능하다. 예컨대&lt;br&gt;BigInteger(int, int, Random) 와 BigInteger.getPrime 중 &amp;#39;값이 소수인 BigInteger를 반환&amp;#39;&lt;br&gt;의 의미를 더 잘 묘사하고 있는지 생각해보라.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;두번째, 호출할때마다 새로운 인스턴스를 반환할 필요가 없다.&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;불변 클래스와 같이 불필요한 객체 생성을 막을 수 있고 같은 객체가 자주 요청되는 상황에&lt;br&gt;성능을 상당히 끌어올릴 수 있고 인스턴스의 생성주기 통제가 쉬워진다. 이런 클래스를&lt;br&gt;인스턴스 통제(instance-controlled) 클래스라고 한다. 인스턴스를 통제한다는 것은 클래스를&lt;br&gt;싱글톤으로 만들수도, 인스턴스화 불가로 만들수도, 불변클래스의 동치인 인스턴스가 단하나 임을&lt;br&gt;보장할 수 있게된다는 것이다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; public class StaticFactoryMethod {
       private static final StaticFactoryMethod STATIC_FACTORY_METHOD 
                                                   = new StaticFactoryMethod();
       private StaticFactoryMethod() {}
       static public StaticFactoryMethod getNewInstanceByNumber() {
           return STATIC_FACTORY_METHOD;
       }
 }
   public static void main(String args[]){
         StaticFactoryMethod staticFactoryMethod  = StaticFactoryMethod.getNewInstance();
         StaticFactoryMethod staticFactoryMethod2 = StaticFactoryMethod.getNewInstance();

         System.out.println(&amp;quot;staticFactoryMethod == staticFactoryMethod2 :&amp;quot; + (staticFactoryMethod == staticFactoryMethod2) );
   }    &lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;세번째, 반환 타입의 하위 타입객체를 반환할 수 있다.&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;반환할 객체의 타입을 자유롭게 선택할 수 있는 유연성으로 구현할 클래스 공개없이&lt;br&gt;그 객체를 반환할 수 있는 장점이 있다. 예컨대 자바 컬렉션프레임워크는  핵심 인터페이스들에&lt;br&gt;수정 불가나 동기화 등의 기능을 덧붙여 유틸리티적인 구현체를 제공하는데 이 구현체 대부분을&lt;br&gt;하나의 인스턴스화 불가 클래스인 java.util.Collections 에서 정적 팩터리 메서드를 통해 얻도록&lt;br&gt;구현햿다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;     public abstract class StaticFactoryMethod {

         abstract void getName();

         static public StaticFactoryMethod getNewInstance( String code ) {
             StaticFactoryMethod staticFactoryMethod = null;
             if( code.indexOf(&amp;quot;2&amp;quot;) == 1 ) {
                 staticFactoryMethod = new Point();
             } else {
                 staticFactoryMethod = new Coupon();
             }
             return staticFactoryMethod;
         }
     }
     class Coupon extends StaticFactoryMethod {
         public void getName() {
             System.out.println(&amp;quot;쿠폰을 발행합니다.&amp;quot;);
         }
     }

     class Point extends StaticFactoryMethod {
         public void getName() {
             System.out.println(&amp;quot;포인트 1000점을 적립합니다.&amp;quot;);
         }
     }

     public static void main(String args[]){
         StaticFactoryMethod staticFactoryMethod = StaticFactoryMethod.getNewInstance(&amp;quot;223123&amp;quot;);
         StaticFactoryMethod staticFactoryMethod1 = StaticFactoryMethod.getNewInstance(&amp;quot;123123&amp;quot;);
         staticFactoryMethod.getName();
         staticFactoryMethod1.getName();
     }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;네번째, 입력 파라미터의 따라 다른 클래스의 객체를 반환 할 수 있다.&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;EnumSet 클래스는 public 생성자 없이 오직 정적 팩터리 메서드을 통해서만 객체를 반환한다.&lt;br&gt;원소의 수에 따라 64개 이하면 RecularEnumSet의 객체, 65개 이상이면 JunboEnumSet의 객체를&lt;br&gt;반환한다. 클라이언트는 이 객체를 알수도 알 필요도 없다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;     public abstract class StaticFactoryMethodType {
     public abstract void getName();

     static public StaticFactoryMethodType getNewInstance( String code ) {
         return new OneClass();
     }
     static public StaticFactoryMethodType getNewInstance( String code, String name ) {
         return new TwoClass();
     }

     }

     class OneClass extends StaticFactoryMethodType {
         public void getName() {
             System.out.println(&amp;quot;쿠폰을 발행합니다.&amp;quot;);
         }
     }

     class TwoClass extends StaticFactoryMethodType {
         public void getName() {
             System.out.println(&amp;quot;포인트 1000점을 적립합니다.&amp;quot;);
         }
     }
     public static void main(String args[]){
         StaticFactoryMethodType isOneObj = StaticFactoryMethodType.getNewInstance(&amp;quot;code&amp;quot;);
         StaticFactoryMethodType isTwoObj = StaticFactoryMethodType.getNewInstance(&amp;quot;code&amp;quot;,&amp;quot;name&amp;quot;);
         isOneObj.getName();
         isTwoObj.getName();
     }&lt;/code&gt;&lt;/pre&gt;&lt;h4&gt;다섯번째, 정적 팩터리 메서드 작성 시점에서는 해당 클래스가 존재하지 않아도 된다.&lt;/h4&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;대표적으론 JDBC가 있다.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;      public static void main(String[] args) {
       String url = &amp;quot;jdbc:oracle:thin:@localhost:1521:xe&amp;quot;;
       String sql = &amp;quot;select * from employees&amp;quot;;
       Connection conn = null;
       java.sql.Statement st = null; //DB와 소통하는 통로

       ResultSet rs = null; //결과 받아서 처리할때
       try {
           Class.forName(&amp;quot;oracle.jdbc.driver.OracleDriver&amp;quot;);
           System.out.println(&amp;quot;driver load 성공!&amp;quot;);
           conn = DriverManager.getConnection(url, &amp;quot;hr&amp;quot;, &amp;quot;hr&amp;quot;);
           System.out.println(&amp;quot;DB 연결 성공!&amp;quot;);

           st = conn.createStatement();
           rs = st.executeQuery(sql); //쿼리 실행 후 데이터들이 rs 저장
           while(rs.next()){ //한건씩 처리
               int empid = rs.getInt(1); //첫번째 칼럼 조회
               String fname = rs.getString(&amp;quot;first_name&amp;quot;); //컬럼이름도 지정 가능
               int sal = rs.getInt(&amp;quot;salary&amp;quot;);
               Date hireDate =  rs.getDate(&amp;quot;hire_date&amp;quot;);
               System.out.println(empid+ &amp;quot;\t&amp;quot; + fname + &amp;quot;\t&amp;quot; + sal + &amp;quot;\t&amp;quot; + hireDate);
           }
       } catch (ClassNotFoundException e) {
           System.out.println(&amp;quot;driver load 실패!&amp;quot;);
           e.printStackTrace();
       } catch (SQLException e) {
           System.out.println(&amp;quot;DB 연결 실패!&amp;quot;);
           e.printStackTrace();
       } finally {
           try {
               if(rs != null) rs.close();
               if(st != null) st.close();
               if(conn != null) conn.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }    
   }&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>JAVA</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/31</guid>
      <comments>https://khs0806.tistory.com/31#entry31comment</comments>
      <pubDate>Sun, 10 Jul 2022 02:26:23 +0900</pubDate>
    </item>
    <item>
      <title>백트래킹 알고리즘</title>
      <link>https://khs0806.tistory.com/30</link>
      <description>&lt;h3&gt;백트래킹 알고리즘&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.acmicpc.net/problem/15651&quot;&gt;백준15651&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;p&gt;백트래킹으로 푸는 문제.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;백트래킹이란?&lt;ol&gt;
&lt;li&gt;어떤 노드의 유망성을 판단하여, 해당 노드가 유망하지 않으면&lt;br&gt;부모 노드로 돌아가 다른 자식 노드를 찾는 방법.&lt;/li&gt;
&lt;li&gt;즉, 모든 경우의 수를 찾아보지만 가능성이 있는 경우의 수만 찾는 방법&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;문제의 조건 확인&lt;ol&gt;
&lt;li&gt;1 ~ N 까지의 조합한다.&lt;/li&gt;
&lt;li&gt;M개를 선택하여 조합한다.(M이 깊이이다.)&lt;/li&gt;
&lt;li&gt;중복해서 조합할 수 있다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;DFS&lt;ol&gt;
&lt;li&gt;대표적 백트래킹 알고리즘 DFS로 구현한다.&lt;/li&gt;
&lt;li&gt;재귀함수를 사용하여 완전탐색 시전.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;코드&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt; package programmers;

 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStreamReader;
 import java.util.StringTokenizer;

 public class Baek15651 {
     static StringBuilder sb = new StringBuilder();
     static int N;
     static int M;
     static int[] selected;

     static void recFun(int k) {
         // M개를 전부고르면 return
         // 고르지 못했을 때, k번째부터 M번째 원소를 조건에 맞게 고르기.
         if (k == M) {
             for (int i=0; i&amp;lt;M; i++) sb.append(selected[i]).append(&amp;quot; &amp;quot;);
             sb.append(&amp;quot;\n&amp;quot;);
         } else {
             for (int i=1; i&amp;lt;=N; i++) {
                 selected[k] = i;
                 recFun(k+1);
             }
         }
     }
     public static void main(String args[]) throws IOException {
         input();
         recFun(0);
         System.out.println(sb.toString());
     }

     static void input() throws IOException {
         BufferedReader br = new BufferedReader(new InputStreamReader(System.in))
         StringTokenizer st = new StringTokenizer(br.readLine(),&amp;quot; &amp;quot;);
         N = Integer.parseInt(st.nextToken());
         M = Integer.parseInt(st.nextToken());
         selected = new int[M];
     }
 }&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;</description>
      <category>알고리즘</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/30</guid>
      <comments>https://khs0806.tistory.com/30#entry30comment</comments>
      <pubDate>Sun, 17 Oct 2021 20:44:30 +0900</pubDate>
    </item>
    <item>
      <title>git cherry-pick : 원하는 커밋을 가져와야 할때</title>
      <link>https://khs0806.tistory.com/29</link>
      <description>&lt;h4&gt;회사에서 Git 을 사용하는데 개발브랜치에서 소스를 반영하고 테스트 후 운영브랜치에 &lt;strong&gt;git cherry-pick&lt;/strong&gt;으로 반영을 하는데 이 cherry-pick 이 어떤 기능인지 모르고 써왔다. 이번에 운영에 소스를 반영할 때 문제가 생길수 있는 부분을 미연에 방지하고자 좀 더 &lt;strong&gt;git cherry-pick&lt;/strong&gt; 이 어떻게 동작하고 무슨 기능인지 알아 보려고 한다.&lt;/h4&gt;
&lt;h3&gt;git cherry-pick 이란?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;특정 커밋만 가져오는 작업.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;git cherry-pick 을 사용해야 하는 경우&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;여러 브랜치로 작업을 하는 중, 다른 브랜치에 있는 기능을 현재 브랜치에서 확인하고 싶을 때&lt;ul&gt;
&lt;li&gt;그러니까 팀과 협업을 하는 도중, 나는 백엔드작업을 하고 다른 팀원은 프론트작업을 하는 도중&lt;br&gt;css 파일만 commit을 했다고 한다. 이때 나는 merge를 하지 않고 그 css파일만 반영해서 확인하고&lt;br&gt;싶을 떄 그 commit만 &lt;strong&gt;git cherry-pick&lt;/strong&gt;을 하면 된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;버그 수정을 해야할 때&lt;ul&gt;
&lt;li&gt;이번에 주문내역조회 기능을 개발하고 서버에 반영을 했다. 그 후 상품주문하기 기능을 개발하던 도중&lt;br&gt;주문내역조회 기능에 버그가 있다는 무서운 소리를 듣는다. 이 때 빨리 문제가 있는 소스를 수정 후 commit&lt;br&gt;을 한다. 개발 브랜치에서 commit을 운영 브랜치에  &lt;strong&gt;git cherry-pick&lt;/strong&gt; 을 사용하여 이 커밋만 반영하여 문제를&lt;br&gt;해결한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;방법&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# git branch
 master
 develop&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이렇게 두개의 브랜치가 있습니다. master는 지금 운영중인 브랜치고, develop는 개발 후 반영될 코드죠.&lt;br&gt;근데 갑자기 (예를들어)UI상의 오타가 발견되었어요. 이런 경우 master와 develop에 모두 반영되어야 하죠.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# git checkout master
# git commit -am &amp;quot;fixed: typo&amp;quot;
# git log --pretty=oneline
b14b975 fixed: typo
9f57292 ....
....&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;이렇게 master 에 반영이 되었습니다. 이 내용을 develop에 반영하려면 다음과 같이 하면 됩니다&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# git checkout develop
# git cherry-pick b14b975
# git log --pretty=oneline
23fa1e76 fixed: typo
dd0f27c ...
...&lt;/code&gt;&lt;/pre&gt;</description>
      <category>GIT</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/29</guid>
      <comments>https://khs0806.tistory.com/29#entry29comment</comments>
      <pubDate>Tue, 4 May 2021 01:46:59 +0900</pubDate>
    </item>
    <item>
      <title>Jenkins를 이용한 빌드배포 자동화 작업(Git, Maven프로젝트)</title>
      <link>https://khs0806.tistory.com/28</link>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Jenkins는 Java로 빌드 된 오픈 소스 CI (Continuous Integration) 및 CD (Continuous Delivery) 도구 입니다. Jenkins는 기본적으로 소프트웨어 프로젝트를 빌드, 테스트 및 배포합니다. DevOps 개발 도구의 가장 기본적인 도구 중에 하나입니다. 오늘은 Ubuntu 18.04에 Jenkins를 설치하는 방법을 보여 드리겠습니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;저는 Local PC에서 작성된 Maven프로젝트를 Github에 푸쉬하고 Jenkins가 이를 감지하고 자동으로 빌드부터 배포까지 간단하게 자동화하는 작업을 진행 해봤습니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;이글은 배포할 웹프로젝트와 우분투서버, Git, Maven, tomcat8, JDK는 미리 세팅되어 있다는 가정하에 작성되었습니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;b&gt;젠킨스 설치&lt;/b&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;ol&gt;
&lt;li&gt;&lt;b&gt;저장소 Key를 다운로드 후에 source.list에 추가하고 apt-get을 이용하여 jenkins 설치합니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;vim&quot;&gt;&lt;code&gt;$ wget -q -O - https://pkg.jenkins.io/debian/jenkins-ci.org.key | sudo apt-key add -

$ echo deb http://pkg.jenkins.io/debian-stable binary/ | sudo tee /etc/apt/sources.list.d/jenkins.list

$ sudo apt-get install jenkins&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;2&quot;&gt;
&lt;li&gt;&lt;b&gt;젠킨스는 기본 포트를 8080으로 쓰기 때문에 다른 서비스와 충돌날 위험이 있어 변경 해줍니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;lsl&quot;&gt;&lt;code&gt;$ sudo vi /etc/default/jenkins

HTTP_PORT=8080
이 부분을 원하는 포트 번호로 변경해줍니다.

HTTP_PORT=9090
저같은 경우에는 9090으로 작성했습니다.&lt;/code&gt;&lt;/pre&gt;
&lt;ol start=&quot;3&quot;&gt;
&lt;li&gt;&lt;b&gt;Jenkins 서비스 시작&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;routeros&quot;&gt;&lt;code&gt;sudo service jenkins restart&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;4.Jenkins 서비스 접속&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;젠킨스서버의 http:/ip:9090/ 주소를 입력하여 접속합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;처음 접속하게 되면 admin password를 입력해야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/cgRARs/btqQLl7DZI0/VtG2GdxwyZ7aTEeRvZLFyk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cgRARs/btqQLl7DZI0/VtG2GdxwyZ7aTEeRvZLFyk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cgRARs/btqQLl7DZI0/VtG2GdxwyZ7aTEeRvZLFyk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcgRARs%2FbtqQLl7DZI0%2FVtG2GdxwyZ7aTEeRvZLFyk%2Fimg.png&quot; width=&quot;100%&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;pre class=&quot;crystal&quot;&gt;&lt;code&gt;$ sudo cat /var/lib/jenkins/secrets/initialAdminPassword
를 입력하여 password를 복사 붙여넣기 해줍니다.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;양 쪽 선택하는 화면인데요, 오른쪽은 직접 플러그인을 선택하여 설치할 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;왼쪽화면은 몇 몇 필수 플러그인들이 기본 설정되서 처음에 설치가 됩니다. 시간이 다소 오래걸리지만 이 글에선 왼쪽을 선택해주겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/d0NbhS/btqQUYQ6p99/yOkCVt8NcTRRZQLqlPBdyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/d0NbhS/btqQUYQ6p99/yOkCVt8NcTRRZQLqlPBdyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/d0NbhS/btqQUYQ6p99/yOkCVt8NcTRRZQLqlPBdyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fd0NbhS%2FbtqQUYQ6p99%2FyOkCVt8NcTRRZQLqlPBdyK%2Fimg.png&quot; width=&quot;100%&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; width=&quot;100%&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/bHcBq2/btqQUZoWQXb/EQzhbElITS2EOIxFdAUDrK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHcBq2/btqQUZoWQXb/EQzhbElITS2EOIxFdAUDrK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHcBq2/btqQUZoWQXb/EQzhbElITS2EOIxFdAUDrK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHcBq2%2FbtqQUZoWQXb%2FEQzhbElITS2EOIxFdAUDrK%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;설치가 완료되면 계정을 하나 만드는 창이 뜹니다. 이 계정은 Jenkins를 접속할 때 필요한 계정이므로 기억해두세요.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/x7twm/btqQUYQ6qgB/vGluUqX3XeWdAx4gwT9kg1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/x7twm/btqQUYQ6qgB/vGluUqX3XeWdAx4gwT9kg1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/x7twm/btqQUYQ6qgB/vGluUqX3XeWdAx4gwT9kg1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fx7twm%2FbtqQUYQ6qgB%2FvGluUqX3XeWdAx4gwT9kg1%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;계정을 만든 후에 URL은 기본으로 놓고 저장합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/n3x5M/btqQR7guDKS/9ScVQgwCQLHLAkLLmqEhck/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/n3x5M/btqQR7guDKS/9ScVQgwCQLHLAkLLmqEhck/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/n3x5M/btqQR7guDKS/9ScVQgwCQLHLAkLLmqEhck/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fn3x5M%2FbtqQR7guDKS%2F9ScVQgwCQLHLAkLLmqEhck%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;이제 Jenkins를 사용할 준비가 다 됐습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/bH7M25/btqQJE7IUBh/25sz5OUe0x9X5i6KSNHS81/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH7M25/btqQJE7IUBh/25sz5OUe0x9X5i6KSNHS81/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH7M25/btqQJE7IUBh/25sz5OUe0x9X5i6KSNHS81/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH7M25%2FbtqQJE7IUBh%2F25sz5OUe0x9X5i6KSNHS81%2Fimg.png&quot; width=&quot;100%&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;ol start=&quot;5&quot;&gt;
&lt;li&gt;&lt;b&gt;Jenkins 프로젝트 만들기&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;좌측 새로운 Item을 클릭해줍니다.&lt;/b&gt;&lt;/li&gt;
&lt;li&gt;&lt;b&gt;프로젝트 생성 메뉴가 나오면 이름을 입력해주고 Freestyle Project를 만들어줍니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/qINFR/btqQUYKlFXp/dKPeOKM93Pcb1I4Xmeqgu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qINFR/btqQUYKlFXp/dKPeOKM93Pcb1I4Xmeqgu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qINFR/btqQUYKlFXp/dKPeOKM93Pcb1I4Xmeqgu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqINFR%2FbtqQUYKlFXp%2FdKPeOKM93Pcb1I4Xmeqgu0%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;프로젝트를 만들었으면 프로젝트로 들어가 '구성'메뉴를 눌러줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;이제 빌드와 배포 설정을 해줄거에요.&lt;/b&gt;&lt;/p&gt;
&lt;ol start=&quot;6&quot;&gt;
&lt;li&gt;&lt;b&gt;젠킨스 자동빌드 및 자동배포 설정하기&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;b&gt;General , 소스 코드 관리, 빌드 유발, 빌드 환경, Build, 빌드 후 조치 메뉴가 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;소스코드관리 탭을 가줍니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/cnzTgy/btqQIazhOsN/PXzjIHH1bjvNXD5GjyYU21/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnzTgy/btqQIazhOsN/PXzjIHH1bjvNXD5GjyYU21/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnzTgy/btqQIazhOsN/PXzjIHH1bjvNXD5GjyYU21/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnzTgy%2FbtqQIazhOsN%2FPXzjIHH1bjvNXD5GjyYU21%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;젠킨스에서 빌드할 소스를 Git에서 가져오기 위해 리포지토리 URL를 입력해줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Build탭을 가줍니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/dqVNTn/btqQIbLQyYL/fqi11djTVbgHVpheotyQKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dqVNTn/btqQIbLQyYL/fqi11djTVbgHVpheotyQKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dqVNTn/btqQIbLQyYL/fqi11djTVbgHVpheotyQKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdqVNTn%2FbtqQIbLQyYL%2Ffqi11djTVbgHVpheotyQKk%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;Maven Version은 글로벌 설정된 Maven의 이름을 작성해줍니다. (글로벌 설정은 잠시후 진행합니다.)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Goals는 maven이 실행할 작업을 입력해줍니다. 이번에는 clean install만 진행해주겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;빌드 후 조치 탭을 가줍니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;이번 작업은 젠킨스관리 - 플러그인설치 - Deploy to container Plugin 설치 후 진행하셔야 합니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/cuXkkv/btqQIXmc1e9/tFqX00aJcQYdKKxQ4CkMF0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cuXkkv/btqQIXmc1e9/tFqX00aJcQYdKKxQ4CkMF0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cuXkkv/btqQIXmc1e9/tFqX00aJcQYdKKxQ4CkMF0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcuXkkv%2FbtqQIXmc1e9%2FtFqX00aJcQYdKKxQ4CkMF0%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;war/ear files 란에는 war,ear파일의 이름 또는 *표로 이름을 지정해주세요.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Context Path는 배포할 서비스의 (젠킨스의)컨텍스트 패스를 지정해주는거고, 공란으로 두시면 젠킨스 기본 컨텍스트 패스가 적용됩니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/lj6AJ/btqQNq8JEge/tViLDsyEuT7fvVT56E2DU0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lj6AJ/btqQNq8JEge/tViLDsyEuT7fvVT56E2DU0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lj6AJ/btqQNq8JEge/tViLDsyEuT7fvVT56E2DU0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Flj6AJ%2FbtqQNq8JEge%2FtViLDsyEuT7fvVT56E2DU0%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;Containers에는 Tomcat 8.x Remote를 선택한 후 Tomcat URL은 톰켓 경로를 , Credentials에는 Tomcat 메니저에서 설정한 계정및 비밀번호를 적어줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;(톰캣 매니저 설정 및 원격계정설정은 아래 포스팅을 참고해 주세요.)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;a href=&quot;https://janggiraffe.tistory.com/entry/Ubuntu-tomcat8-%EC%84%A4%EC%B9%98-%EB%B0%8F-%EC%A0%A0%ED%82%A8%EC%8A%A4-%EC%9E%90%EB%8F%99%EB%B0%B0%ED%8F%AC%EB%A5%BC-%EC%9C%84%ED%95%9C-tomcat8-manager-%EC%85%8B%ED%8C%85&quot;&gt;Ubuntu tomcat8 설치 및 젠킨스 자동배포를 위한 tomcat8 manager 셋팅&lt;/a&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;이제 Buildnow를 누르면 빌드가 될겁니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/l42cr/btqQJDAXC19/rkmJhZMb5HEWYxEQ2W2RKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l42cr/btqQJDAXC19/rkmJhZMb5HEWYxEQ2W2RKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l42cr/btqQJDAXC19/rkmJhZMb5HEWYxEQ2W2RKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl42cr%2FbtqQJDAXC19%2FrkmJhZMb5HEWYxEQ2W2RKK%2Fimg.png&quot; width=&quot;100%&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;ol start=&quot;7&quot;&gt;
&lt;li&gt;&lt;b&gt;Github push시 자동 빌드하기&lt;/b&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;ul&gt;
&lt;li&gt;&lt;b&gt;Github webhook을 이용하면 github에 push가 되면 jenkins에게 알려주고 빌드를 유발할 수 있습니다.&lt;/b&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;b&gt;본인의 GitHub 프로젝트 Settings &amp;gt;&amp;gt; Webhooks &amp;gt;&amp;gt; Add Webhook 클릭&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/bTjNzF/btqQJE0WSCA/XQuOrk4rlo4gzRoJ0OZeb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTjNzF/btqQJE0WSCA/XQuOrk4rlo4gzRoJ0OZeb1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTjNzF/btqQJE0WSCA/XQuOrk4rlo4gzRoJ0OZeb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTjNzF%2FbtqQJE0WSCA%2FXQuOrk4rlo4gzRoJ0OZeb1%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;Payload URL : &quot;&lt;a href=&quot;http://xn--jenkins-ed92au0z1robkao9m/github-webhook/&quot;&gt;http://본인의Jenkins주소/github-webhook/&lt;/a&gt;&quot;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;나머지 항목은 기본으로 설정하고 &quot;Add webhook&quot; 클릭&lt;/b&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;Github와 Jenkins를 연결하려면 Github Integeration Plugin이 필요하다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Jenkins관리 &amp;gt;&amp;gt; 플러그인 관리&lt;/b&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/dGBamk/btqQIaMO4IC/yTui4RfHTyc97G26HjUCH0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dGBamk/btqQIaMO4IC/yTui4RfHTyc97G26HjUCH0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dGBamk/btqQIaMO4IC/yTui4RfHTyc97G26HjUCH0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdGBamk%2FbtqQIaMO4IC%2FyTui4RfHTyc97G26HjUCH0%2Fimg.png&quot; width=&quot;100%&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;&lt;b&gt;설치 가능 탭 &amp;gt;&amp;gt; Github Integration 검색 &amp;gt;&amp;gt; 설치&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/bB6AQJ/btqQR7t2ORE/ByM1D6f92ZR4QksjjLwONk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bB6AQJ/btqQR7t2ORE/ByM1D6f92ZR4QksjjLwONk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bB6AQJ/btqQR7t2ORE/ByM1D6f92ZR4QksjjLwONk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbB6AQJ%2FbtqQR7t2ORE%2FByM1D6f92ZR4QksjjLwONk%2Fimg.png&quot; width=&quot;100%&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;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;b&gt;Jenkins 설정&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;만들어 놓은 프로젝트로 이동 &amp;rarr; 구성 클릭&lt;/b&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/cGc6iL/btqQIWt4jsx/kq2kxAJlFQWJ3NWBI9DTKK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cGc6iL/btqQIWt4jsx/kq2kxAJlFQWJ3NWBI9DTKK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cGc6iL/btqQIWt4jsx/kq2kxAJlFQWJ3NWBI9DTKK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcGc6iL%2FbtqQIWt4jsx%2Fkq2kxAJlFQWJ3NWBI9DTKK%2Fimg.png&quot; width=&quot;100%&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;pre class=&quot;pgsql&quot;&gt;&lt;code&gt;빌드 유발 탭 이동 &amp;gt;&amp;gt; GitHub hook trigger for GITScm polling 체크&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/rz5Zg/btqQIXTZZWO/auN6nWJhYgyop88LEPaMek/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/rz5Zg/btqQIXTZZWO/auN6nWJhYgyop88LEPaMek/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/rz5Zg/btqQIXTZZWO/auN6nWJhYgyop88LEPaMek/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Frz5Zg%2FbtqQIXTZZWO%2FauN6nWJhYgyop88LEPaMek%2Fimg.png&quot; width=&quot;100%&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;pre class=&quot;armasm&quot;&gt;&lt;code&gt;모든 설정이 완료 되었다면, 이후 설정한 Branch에 Push를 하였을때, 자동으로 jenkins 빌드가 유발되는 것을 볼 수 있다.&lt;/code&gt;&lt;/pre&gt;</description>
      <category>WEB</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/28</guid>
      <comments>https://khs0806.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 20 Dec 2020 20:09:35 +0900</pubDate>
    </item>
    <item>
      <title>자바 커스텀 어노테이션 만들기</title>
      <link>https://khs0806.tistory.com/27</link>
      <description>&lt;h3&gt;어노테이션&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;소스 코드에 메타 데이터를 표현하는 것입니다.&lt;/li&gt;
&lt;li&gt;컴파일 과정, 런타임 과정에서 코드를 어떻게 처리해야할지 명시하는 것입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;자바에서 기본적으로 제공하는 어노테이션&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;@override&lt;/code&gt; 메소드가 오버라이드 됬는지 검증합니다. 만약 부모클래스 또는 인터페이스에서 해당 메서드를 찾을 수 없다면 컴파일 오류가 발생합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Deprecated&lt;/code&gt; 메소드를 사용하지 말도록 유도합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@SupperessWarnings&lt;/code&gt; 컴파일 경고를 무시하도록 합니다.&lt;br&gt;이 외에도 여러가지 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Meta Annotations&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;이 메타 어노테이션을 이용하여 사용자 커스텀 어노테이션을 만들어 낼 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;@Retention&lt;/code&gt; 어노테이션의 범위, 어떤 시점까지 어노테이션이 영향을 미치는지 결정합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Documented&lt;/code&gt; 문서에도 어노테이션 정보가 표현됩니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Target&lt;/code&gt; 어노테이션이 적용될 위치를 결정 합니다. 적용 대상에는 method, fleid, type(class), 생성자, parameter 등이 있습니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;@Inherited&lt;/code&gt; 이 어노테이션을 선언하면 부모클래스에서 어노테이션을 상속 받을 수 있습니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;어노테이션 생성하기&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;자바에서 어노테이션을 생성하는법은 간단합니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public @interface MyAnno {
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;이후에 몇 메타 어노테이션을 선언해줍니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Target(ElementType.METHOD)                        // 적용대상은 method입니다.
@Retention(RetentionPolicy.RUNTIME)                // 유지정책은 runtime입니다. 컴파일 이후에도 JVM이 참조합니다.
public @interface MyAnno {
// String 타입으로 사용 가능합니다.
  public String value();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;어노테이션 적용하기&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;생성해준 어노테이션을 적용할 클래스입니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public class Target {

    @MyAnno(value = &amp;quot;연습입니다.&amp;quot;)
    public void sub() {
        System.out.println(&amp;quot;Target&amp;quot;);
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;실제 어노테이션을 찾는 컨테이너 클래스&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;자바 리플렉션을 이용하여 프로그램 실행 시 커스텀 어노테이션을 사용한 곳과 값들을 얻어옵니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public class MainClass {
    public static void main(String[] args) throws Exception {


        // 특정 메서드의 어노테이션을 가져올 수 있습니다.
        Method method = Target.class.getMethod(&amp;quot;sub&amp;quot;);
        Annotation[] annotations = method.getDeclaredAnnotations();

        for (Annotation anno : annotations) {
            MyAnno myAnno = (MyAnno) anno;
            System.out.println(myAnno.value());
        }

        // 동적 클래스 생성으로 객체를 얻어온 다음
        // 여러 메서드들의 어노테이션 value()를 얻어옵니다.
        String className = &amp;quot;com.java.anno01.Target&amp;quot;;
        Class&amp;lt;?&amp;gt; cls = Class.forName(className);
        Target a = (Target) cls.getDeclaredConstructor().newInstance();
        a.sub();

        Method[] methods = cls.getDeclaredMethods();

        for (int i=0; i&amp;lt;methods.length; i++) {
            if (methods[i].isAnnotationPresent(MyAnno.class)) {
                MyAnno myAnno = methods[i].getAnnotation(MyAnno.class);
                System.out.println(myAnno.value());
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;</description>
      <category>JAVA</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/27</guid>
      <comments>https://khs0806.tistory.com/27#entry27comment</comments>
      <pubDate>Sun, 2 Aug 2020 12:22:40 +0900</pubDate>
    </item>
    <item>
      <title>jQuery - 필터 선택자</title>
      <link>https://khs0806.tistory.com/26</link>
      <description>&lt;h3&gt;jQuery 필터 선택자&lt;/h3&gt;
&lt;p&gt;  &lt;code&gt;(: focus, :gt(), :lt(), :has()) 등이 있습니다.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;  &lt;code&gt;기본선택자 뒤에 : 표시와 함께 붙으며 좀더 섬세한 선택자를 선택할 수 있습니다.&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Basic Filter&lt;/h3&gt;
&lt;p&gt;   &lt;code&gt;:odd&lt;/code&gt; - 홀수 번째에 위치한 요소 선택&lt;br&gt;   &lt;code&gt;:even&lt;/code&gt; - 짝수 번째에 위치한 요소 선택&lt;br&gt;   &lt;code&gt;:first&lt;/code&gt; - 첫번째 위치한 요소 선택&lt;br&gt;   &lt;code&gt;:last&lt;/code&gt; - 마지막에 위치한 요소 선택&lt;br&gt;   &lt;code&gt;:gt(index)&lt;/code&gt; - index값보다 큰 index를 가진 요소를 선택&lt;br&gt;   &lt;code&gt;:lt(index)&lt;/code&gt; - index값보다 작은 index를 가진 요소를 선택&lt;/p&gt;
&lt;h4&gt;기본필터 선택자 예제_&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD HTML 4.01 Transitional//EN&amp;quot; &amp;quot;http://www.w3.org/TR/html4/loose.dtd&amp;quot;&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=UTF-8&amp;quot;&amp;gt;
&amp;lt;title&amp;gt;jQuery - 기본 필터 선택자&amp;lt;/title&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;../jquery.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
    $(document).ready(function(){
        //    선택자 필터
        $(&amp;quot;p:even&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;red&amp;quot;);        // 짝수 (0번지부터 0, 2, 4, 6, ...)
        $(&amp;quot;p:odd&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;green&amp;quot;);    // 홀수
        $(&amp;quot;p:first&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;blue&amp;quot;);
        $(&amp;quot;p:last&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;pink&amp;quot;);
        $(&amp;quot;p:eq(2)&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;yellow&amp;quot;);    // 번지값(인덱스)

        $(&amp;quot;.third &amp;gt; li:gt(2)&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;red&amp;quot;);    // 기준 인덱스보다 큰요소들
        $(&amp;quot;.third &amp;gt; li:lt(2)&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;blue&amp;quot;);    // 기준 인덱스보다 작은요소들
    });
&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;p&amp;gt;1월&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;2월&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;3월&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;4월&amp;lt;/p&amp;gt;
    &amp;lt;p&amp;gt;5월&amp;lt;/p&amp;gt;
    &amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;ul class=&amp;quot;third&amp;quot;&amp;gt;
            &amp;lt;li&amp;gt;커피&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;콜라&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;사이다&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;환타&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;우유&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결과화면&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dHcgCj/btqFTSnKobg/CLg09UTPHN8El5wJnSbZm1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dHcgCj/btqFTSnKobg/CLg09UTPHN8El5wJnSbZm1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dHcgCj/btqFTSnKobg/CLg09UTPHN8El5wJnSbZm1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdHcgCj%2FbtqFTSnKobg%2FCLg09UTPHN8El5wJnSbZm1%2Fimg.png&quot; width=&quot;100%&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;h3&gt;Content Filter&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;:contains(text)&lt;/code&gt; : 특정 텍스트가 포함된 요소를 선택합니다. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;:has(selector)&lt;/code&gt; : 특정 선택자가 최소 하나 이상 포함된 요소를 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:empty&lt;/code&gt; : 자식 노드를 가지고 있지 않는 요소를 선택합니다.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;:parent&lt;/code&gt; : 최소 하나 이상 자식노드를 가지고 있는 요소를 선택합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;내용 선택자 필터 예제_&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;!DOCTYPE html PUBLIC &amp;quot;-//W3C//DTD HTML 4.01 Transitional//EN&amp;quot; &amp;quot;http://www.w3.org/TR/html4/loose.dtd&amp;quot;&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
&amp;lt;meta http-equiv=&amp;quot;Content-Type&amp;quot; content=&amp;quot;text/html; charset=UTF-8&amp;quot;&amp;gt;
&amp;lt;title&amp;gt;jQuery - 내용 필터 선택자&amp;lt;/title&amp;gt;
&amp;lt;style type=&amp;quot;text/css&amp;quot;&amp;gt;
    body{
        font-size:12px;
    }
&amp;lt;/style&amp;gt;
&amp;lt;script type=&amp;quot;text/javascript&amp;quot; src=&amp;quot;../jquery.js&amp;quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
    $(function(){
        $(&amp;quot;li:contains(&amp;#39;ap&amp;#39;)&amp;quot;).css({    // (괄호)내의 텍스트와 일치하는 요소
                color : &amp;quot;red&amp;quot;,
                backgroundColor : &amp;quot;yellow&amp;quot;,
                fontWeight : &amp;quot;bold&amp;quot;,
                fontSize : &amp;quot;30px&amp;quot;
        })
        $(&amp;quot;#sub:has(&amp;#39;li&amp;#39;)&amp;quot;).css({            // 요소 내부에 찾고 싶은 태그를 후손 요소까지 찾아준다.
            color : &amp;quot;pink&amp;quot;,
            backgroundColor : &amp;quot;green&amp;quot;
        })

        $(&amp;quot;li:parent&amp;quot;).css(&amp;quot;color&amp;quot;,&amp;quot;blue&amp;quot;);    // 
        $(&amp;quot;li:empty&amp;quot;).text(&amp;quot;Hello&amp;quot;);

    });
&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div&amp;gt;
        &amp;lt;ul&amp;gt;
            &amp;lt;li&amp;gt;apple&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;banana&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;grape&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;

        &amp;lt;ul id=&amp;quot;sub&amp;quot;&amp;gt;
            &amp;lt;li&amp;gt;lion&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;tiger&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;fox&amp;lt;/li&amp;gt;
            &amp;lt;li&amp;gt;&amp;lt;/li&amp;gt;
        &amp;lt;/ul&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;결과화면&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WuA2Z/btqFRB07NnD/bgJs522t3lUlhkpZzZLiXK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WuA2Z/btqFRB07NnD/bgJs522t3lUlhkpZzZLiXK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WuA2Z/btqFRB07NnD/bgJs522t3lUlhkpZzZLiXK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWuA2Z%2FbtqFRB07NnD%2FbgJs522t3lUlhkpZzZLiXK%2Fimg.png&quot; width=&quot;100%&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;</description>
      <category>WEB/jQuery</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/26</guid>
      <comments>https://khs0806.tistory.com/26#entry26comment</comments>
      <pubDate>Tue, 21 Jul 2020 19:38:39 +0900</pubDate>
    </item>
    <item>
      <title>jQuery 기초 - 시작하기</title>
      <link>https://khs0806.tistory.com/25</link>
      <description>&lt;ul&gt;
&lt;li&gt;
&lt;h4&gt;자바스크립트 라이브러리로 프론트 엔드 조작을 단순화 하도록 설계 되어있다.&lt;/h4&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h4&gt;제이쿼리를 사용하는 이유는 다음과 같다.&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;h5&gt;페이지 내부 요소에 접근하기 쉽다.&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;제이쿼리를 사용하지 않으면 DOM 트리를 이용해서 요소(element)에 접근해야 합니다. 이는 배우기도 어렵고 불편한데, 제이쿼리를 사용하면 CSS의 선택자를 이용해서 간편하게 접근할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h5&gt;페이지의 보여지는 모습을 변경하기 쉽다.&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;동적으로 페이지의 모습(CSS)를 변경하기 위해서는 자바스크립트를 사용해야 합니다. 이를 제이쿼리를 이용하여 작성하면 코드도 간결해지고 직관적으로 작성할 수 있습니다.&lt;/li&gt;
&lt;li&gt;또, 아작스(AJAX)등에서 페이지를 리로딩하지 않고 동적으로 로딩할 때도 자바스크립트를 이용하는데, 이것 역시 제이쿼리를 이용하면 코드도 간결해지고 더 쉽게 구현할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h5&gt;상호작용 처리가 쉽고 애니메이션을 사용할 수 있다.&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;HTML문서의 목적은 페이지의 구조와 데이터를 표현하는 것입니다. 따라서 HTML 태그 속성의 이벤트를 사용하면 이 목적에 어긋난다고 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;이벤트를 제이쿼리를 사용해서 핸들링하면 HTML문서를 변경할 필요도 없고 더 쉽습니다.&lt;br /&gt;또 다양한 애니메이션을 간편하게 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;h5&gt;AJAX의 사용이 쉽다.&lt;/h5&gt;
&lt;ul&gt;
&lt;li&gt;제이쿼리를 사용하면 아작스 기술을 사용하는데 매우 편리합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h4&gt;JQuery 사용 선언&lt;/h4&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!-- 적용방법 1 --&amp;gt;
&amp;lt;script src=&quot;js/jquery.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;!-- 적용방법 2 : cdn --&amp;gt;
&amp;lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;!-- 적용방법 3 --&amp;gt;
&amp;lt;script src=&quot;http://code.jquery.com/jquery-latest.js&quot;&amp;gt;&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;첫번째는 직접 JQuery 라이브러리를 다운받아 사용하는 방법입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;두번째는 외부 cdn을 이용하는 방법입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;세번째는 jquery 사이트에서 제공하는 api를 이용합니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h4&gt;JQuery 시작하기&lt;/h4&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;script&amp;gt;
    var obj = new JQuery(document);           // jquery 객체 생성
    obj.ready(testFun);                         // jquery는 항상 이렇게 시작한다.
    function testFun(){
        alert(&quot;JQuery 시작입니다.&quot;);
    } 
//===================================================================================
     new JQuery(document).ready(function(){    // 위에 것과 동일. 하지만 코드수가 줄어듬.
        alert(&quot;JQuery 시작입니다.&quot;);
    }); 
//===================================================================================
    $(document).ready(function(){            // 위에 문장의 최종 끝판왕. 주로 이렇게 쓴다.
        alert(&quot;JQuery 시작입니다.&quot;);
    });
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ol&gt;
&lt;li&gt;자바처럼 JQuery 객체를 생성하듯이 jquery를 시작할 수 있지만 라이브러리에서 제공하는 강력한 기능으로 $(document).ready()로 시작할 수 있습니다.&lt;/li&gt;
&lt;li&gt;ready() 함수는 document 문서가 로드될 때 발생합니다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;h4&gt;JQuery 선택자&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;JQuery는 CSS의 선택자를 사용해서 DOM의 노드를 반환받을 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;xml&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html PUBLIC &quot;-//W3C//DTD HTML 4.01 Transitional//EN&quot; &quot;http://www.w3.org/TR/html4/loose.dtd&quot;&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;jQuery - 기본 선택자&amp;lt;/title&amp;gt;
&amp;lt;style type=&quot;text/css&quot;&amp;gt;
    .spotlight{
        background-color:#ffff00;
    }
    .redtext{
        color:#ff0000;
    }
&amp;lt;/style&amp;gt;
&amp;lt;script src=&quot;../jquery.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script&amp;gt;
    $(document).ready(function(){
       //var first = document.getElementById(&quot;first&quot;);
       //first.setAttribute(&quot;class&quot;, &quot;spotlight&quot;);      -- javascript
       //위와같은 자바 스크립트 작성을 한줄로 끝낼 수 있습니다.
         $(&quot;#first&quot;).addClass(&quot;spotlight&quot;);            // -- JQuery

        $(&quot;#second&quot;).addClass(&quot;redtext&quot;);
        $(&quot;#third&quot;).addClass(&quot;spotlight redtext&quot;);

        var arr = new Array();
        arr.push($(&quot;#first&quot;).text());
        arr.push($(&quot;#second&quot;).text());
        arr.push($(&quot;#third&quot;).text());
        alert(arr);
    });
&amp;lt;/script&amp;gt;
&amp;lt;body&amp;gt;    
    &amp;lt;div id=&quot;first&quot;&amp;gt;사과&amp;lt;/div&amp;gt;
    &amp;lt;div id=&quot;second&quot;&amp;gt;바나나&amp;lt;/div&amp;gt;
    &amp;lt;div id=&quot;third&quot;&amp;gt;딸기&amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;브라우저 화면&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;100%&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/sTrU9/btqFOMI1lfy/IrXBj5JeLVKPjXCywjN8O0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/sTrU9/btqFOMI1lfy/IrXBj5JeLVKPjXCywjN8O0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/sTrU9/btqFOMI1lfy/IrXBj5JeLVKPjXCywjN8O0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FsTrU9%2FbtqFOMI1lfy%2FIrXBj5JeLVKPjXCywjN8O0%2Fimg.png&quot; width=&quot;100%&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;</description>
      <category>WEB/jQuery</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/25</guid>
      <comments>https://khs0806.tistory.com/25#entry25comment</comments>
      <pubDate>Mon, 20 Jul 2020 19:23:16 +0900</pubDate>
    </item>
    <item>
      <title>검색 처리와 동적 SQL</title>
      <link>https://khs0806.tistory.com/24</link>
      <description>&lt;ul&gt;
&lt;li&gt;&lt;p&gt;지난 페이징 처리에 이어서 페이징처리와 함께 쓰이는 검색처리를 작성해봤습니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;페이징 처리의 마지막 단계는 검색 조건과 검색 키워드를 입력하고, 이에 맞는 검색 데이터를 추출하여 화면에 출력해주는 작업입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;검색 처리에서 가장 어려운 부분은 JSP단이 아닌 SQL문의 처리부분 입니다. 이를 위해서 MyBatis의 동적 SQL을 이용하여 처리할 것입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;검색에 필요한 데이터, SearchCriteria&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;h4&gt;사용자가 게시물을 검색 후, 목록 페이지에서 필요한 데이터는 다음과 같습니다.&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;현재 페이지의 번호(page)&lt;/li&gt;
&lt;li&gt;페이지당 보여지는 데이터의 수(perPageNum)&lt;/li&gt;
&lt;li&gt;검색의 종류(searchType)&lt;/li&gt;
&lt;li&gt;검색의 키워드(keyword)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;&lt;h4&gt;이 4개의 데이터를 전달하기 위한 객체를 만들어 줍니다.&lt;/h4&gt;
&lt;h4&gt;SearchCriteria.java&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public class SearchCriteria extends Criteria{

    private String searchType;
    private String keyword;

    public String getSearchType() {
        return searchType;
    }
    public void setSearchType(String searchType) {
        this.searchType = searchType;
    }
    public String getKeyword() {
        return keyword;
    }
    public void setKeyword(String keyword) {
        this.keyword = keyword;
    }
    @Override
    public String toString() {
        return super.toString() + &amp;quot; SearchCriteria &amp;quot;
                + &amp;quot;[searchType=&amp;quot; + searchType + &amp;quot;, keyword=&amp;quot;
                + keyword + &amp;quot;]&amp;quot;;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;검색조건과 검색키워드를 전달하는 객체입니다.&lt;/p&gt;
&lt;p&gt;Criteria를 상속받습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;검색조건(searchType)과 검색키워드(keyword)에 대한 링크를 처리하기 위한 PageMaker.java&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;페이징 처리를 하기위한 PageMaker.java 에서의 검색조건과 키워드를 처리하는 메서드입니다.&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public String makeSearch(int page) {

    UriComponents uriComponents = 
    UriComponentsBuilder.newInstance()
    .queryParam(&amp;quot;page&amp;quot;, page)
    .queryParam(&amp;quot;perPageNum&amp;quot;, cri.getPerPageNum())
    .queryParam(&amp;quot;searchType&amp;quot;, ((SearchCriteria) cri).getSearchType())
    .queryParam(&amp;quot;keyword&amp;quot;, ((SearchCriteria) cri).getKeyword())
    .build();

    return uriComponents.toUriString();
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;UriComponentBuilder 객체는 url 생성을 도와주어 페이징 처리에 도움을 줍니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;?page=1&amp;amp;perPageNum=10&amp;amp;searchType=t&amp;amp;keyword=테스트&lt;/code&gt; 이런식으로 URL이 생성됩니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;JSP에서의 페이징 처리&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;h4&gt;화면단에서 페이징을 담당하는 부분을 pageMaker를 이용하여 처리합니다.&lt;/h4&gt;
&lt;pre&gt;&lt;code&gt; &amp;lt;ul class=&amp;quot;pagination&amp;quot;&amp;gt;
 &amp;lt;c:if test=&amp;quot;${pageMaker.prev}&amp;quot;&amp;gt;
     &amp;lt;li&amp;gt;
         &amp;lt;a href=&amp;quot;list${pageMaker.makeSearch(pageMaker.startPage - 1) }&amp;quot;&amp;gt;&amp;amp;laquo;&amp;lt;/a&amp;gt;
     &amp;lt;/li&amp;gt;
 &amp;lt;/c:if&amp;gt;

 &amp;lt;c:forEach begin=&amp;quot;${pageMaker.startPage }&amp;quot; end=&amp;quot;${pageMaker.endPage }&amp;quot; var=&amp;quot;idx&amp;quot;&amp;gt;
     &amp;lt;li &amp;lt;c:out value=&amp;quot;${pageMaker.cri.page == idx?&amp;#39;class =active&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
         &amp;lt;a href=&amp;quot;list${pageMaker.makeSearch(idx)}&amp;quot;&amp;gt;${idx}&amp;lt;/a&amp;gt;
     &amp;lt;/li&amp;gt;
 &amp;lt;/c:forEach&amp;gt;

 &amp;lt;c:if test=&amp;quot;${pageMaker.next &amp;amp;&amp;amp; pageMaker.endPage &amp;gt; 0}&amp;quot;&amp;gt;
     &amp;lt;li&amp;gt;
         &amp;lt;a href=&amp;quot;list${pageMaker.makeSearch(pageMaker.endPage +1) }&amp;quot;&amp;gt;&amp;amp;raquo;&amp;lt;/a&amp;gt;
     &amp;lt;/li&amp;gt;    
 &amp;lt;/c:if&amp;gt;
 &amp;lt;/ul&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
&lt;li&gt;&lt;h4&gt;검색처리를 담당하는 부분은 자바스크립트로 작성해줍니다.&lt;/h4&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code class=&quot;language-html&quot;&gt;&amp;lt;div class=&amp;#39;box&amp;#39;&amp;gt;
   &amp;lt;div class=&amp;quot;box-header with-border&amp;quot;&amp;gt;
       &amp;lt;h3 class=&amp;quot;box-title&amp;quot;&amp;gt;Board List&amp;lt;/h3&amp;gt;
   &amp;lt;/div&amp;gt;
&amp;lt;div class=&amp;#39;box-body&amp;#39;&amp;gt;

   &amp;lt;select name=&amp;quot;searchType&amp;quot;&amp;gt;
       &amp;lt;option value=&amp;quot;n&amp;quot;
   &amp;lt;c:out value=&amp;quot;${cri.searchType == null?&amp;#39;selected&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
   ---&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;t&amp;quot;
   &amp;lt;c:out value=&amp;quot;${cri.searchType eq &amp;#39;t&amp;#39;?&amp;#39;selected&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
   제목&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;c&amp;quot;
   &amp;lt;c:out value=&amp;quot;${cri.searchType eq &amp;#39;c&amp;#39;?&amp;#39;selected&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
   내용&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;w&amp;quot;
   &amp;lt;c:out value=&amp;quot;${cri.searchType eq &amp;#39;w&amp;#39;?&amp;#39;selected&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
   작성자&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;tc&amp;quot;
   &amp;lt;c:out value=&amp;quot;${cri.searchType eq &amp;#39;tc&amp;#39;?&amp;#39;selected&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
   제목 OR 내용&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;cw&amp;quot;
   &amp;lt;c:out value=&amp;quot;${cri.searchType eq &amp;#39;cw&amp;#39;?&amp;#39;selected&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
   내용 OR 작성자&amp;lt;/option&amp;gt;
   &amp;lt;option value=&amp;quot;tcw&amp;quot;
   &amp;lt;c:out value=&amp;quot;${cri.searchType eq &amp;#39;tcw&amp;#39;?&amp;#39;selected&amp;#39;:&amp;#39;&amp;#39;}&amp;quot;/&amp;gt;&amp;gt;
   제목 OR 내용 OR 작성자&amp;lt;/option&amp;gt;
   &amp;lt;/select&amp;gt; &amp;lt;input type=&amp;quot;text&amp;quot; name=&amp;#39;keyword&amp;#39; id=&amp;quot;keywordInput&amp;quot;
   value=&amp;#39;${cri.keyword }&amp;#39;&amp;gt;
   &amp;lt;button id=&amp;#39;searchBtn&amp;#39;&amp;gt;Search&amp;lt;/button&amp;gt;
   &amp;lt;button id=&amp;#39;newBtn&amp;#39;&amp;gt;New Board&amp;lt;/button&amp;gt;
   &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;script&amp;gt;
$(document).ready(function() {
   $(&amp;#39;#searchBtn&amp;#39;).on(&amp;quot;click&amp;quot;,function(event) {
       str = &amp;quot;list&amp;quot;
               + &amp;#39;${pageMaker.makeQuery(1)}&amp;#39;
               + &amp;quot;&amp;amp;searchType=&amp;quot;
               + $(&amp;quot;select option:selected&amp;quot;).val()
               + &amp;quot;&amp;amp;keyword=&amp;quot;
               + encodeURIComponent($(&amp;#39;#keywordInput&amp;#39;).val());
       alert(str);
       self.location = str;
   });
   $(&amp;#39;#newBtn&amp;#39;).on(&amp;quot;click&amp;quot;, function(evt) {
       self.location = &amp;quot;register&amp;quot;;
   });
});
&amp;lt;/script&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;makeSearch() 메서드로 페이징링크에 대한 조작을 할수 있습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;MyBatis의 동적 SQL&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;화면단에서의 검색조건에 따라 SQL문이 달라지기 때문에 이를 처리하기 위해 MyBatis의 동적 SQL을 활용할 것입니다.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;XML Mapper&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-XML&quot;&gt;&amp;lt;sql id=&amp;quot;search&amp;quot;&amp;gt;
 &amp;lt;if test=&amp;quot;searchType != null&amp;quot; &amp;gt; 
   &amp;lt;if test=&amp;quot;searchType == &amp;#39;t&amp;#39;.toString()&amp;quot;&amp;gt;
     and title like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;)
   &amp;lt;/if&amp;gt;
   &amp;lt;if test=&amp;quot;searchType == &amp;#39;c&amp;#39;.toString()&amp;quot;&amp;gt;
     and content like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;)
   &amp;lt;/if&amp;gt;
   &amp;lt;if test=&amp;quot;searchType == &amp;#39;w&amp;#39;.toString()&amp;quot;&amp;gt;
     and writer like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;)
   &amp;lt;/if&amp;gt;     
   &amp;lt;if test=&amp;quot;searchType == &amp;#39;tc&amp;#39;.toString()&amp;quot;&amp;gt;
     and ( title like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;) OR content like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;))
   &amp;lt;/if&amp;gt;        
   &amp;lt;if test=&amp;quot;searchType == &amp;#39;cw&amp;#39;.toString()&amp;quot;&amp;gt;
     and ( content like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;) OR writer like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;))
   &amp;lt;/if&amp;gt;        
   &amp;lt;if test=&amp;quot;searchType == &amp;#39;tcw&amp;#39;.toString()&amp;quot;&amp;gt;
     and (   title like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;) 
           OR 
             content like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;) 
           OR 
             writer like CONCAT(&amp;#39;%&amp;#39;, #{keyword}, &amp;#39;%&amp;#39;))
   &amp;lt;/if&amp;gt;              
 &amp;lt;/if&amp;gt;  
&amp;lt;/sql&amp;gt;

&amp;lt;select id=&amp;quot;listSearch&amp;quot; resultType=&amp;quot;BoardVO&amp;quot;&amp;gt;
    &amp;lt;![CDATA[  
       select * 
       from tbl_board 
       where bno &amp;gt; 0 
     ]]&amp;gt;  
 &amp;lt;include refid=&amp;quot;search&amp;quot;&amp;gt;&amp;lt;/include&amp;gt;
    &amp;lt;![CDATA[    
       order by bno desc
       limit #{pageStart}, #{perPageNum}
     ]]&amp;gt;  
&amp;lt;/select&amp;gt;

&amp;lt;select id=&amp;quot;listSearchCount&amp;quot; resultType=&amp;quot;int&amp;quot;&amp;gt;
    &amp;lt;![CDATA[  
       select count(bno) 
       from tbl_board 
       where bno &amp;gt; 0 
     ]]&amp;gt;
    &amp;lt;include refid=&amp;quot;search&amp;quot;&amp;gt;&amp;lt;/include&amp;gt;

&amp;lt;/select&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;MyBatis의 SQL 문을 동일 처리하고 재사용할 수 있는 태그인 &lt;code&gt;&amp;lt;sql&amp;gt;&lt;/code&gt;로 중복된 코드를 줄일 수 있습니다.&lt;/p&gt;
&lt;p&gt;사용할 땐 &lt;code&gt;&amp;lt;include&amp;gt;&lt;/code&gt;태그로 id값으로 불러오면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;&amp;lt;if&amp;gt;&lt;/code&gt;태그로 파라미터값인 검색조건(searchType) 에 따라 실행되는 SQL 구문이 달라지게 했습니다.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;화면과 DB의 처리가 끝났으니 컨트롤러와 DAO 를 작성해줍니다&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;h4&gt;Controller&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;public class SearchBoardController {

    private static final Logger logger = LoggerFactory.getLogger(SearchBoardController.class);

    @Inject
    private BoardService service;

    @RequestMapping(value = &amp;quot;/list&amp;quot;, method = RequestMethod.GET)
    public void listPage(@ModelAttribute(&amp;quot;cri&amp;quot;) SearchCriteria scri, Model model) throws Exception {

        logger.info(scri.toString());

        model.addAttribute(&amp;quot;list&amp;quot;, service.listSearchCriteria(scri));
        PageMaker pageMaker = new PageMaker();
        pageMaker.setCri(scri);
        pageMaker.setTotalCount(service.listSearchCount(scri));

        logger.info(pageMaker.makeSearch(scri.getPage()));

        model.addAttribute(&amp;quot;pageMaker&amp;quot;, pageMaker);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;&lt;h4&gt;DAO&lt;/h4&gt;
&lt;pre&gt;&lt;code class=&quot;language-java&quot;&gt;@Repository
public class BoardDAOImpl implements BoardDAO{
    @Inject
    private SqlSession session;

    @Override
    public List&amp;lt;BoardVO&amp;gt; listSearch(SearchCriteria cri) throws Exception {
        return session.selectList(namespace + &amp;quot;.listSearch&amp;quot;, cri);
    }

    @Override
    public int listSearchCount(SearchCriteria cri) throws Exception {
        return session.selectOne(namespace + &amp;quot;.listSearchCount&amp;quot;, cri);
    }

}&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>스프링</category>
      <author>풍림개발자</author>
      <guid isPermaLink="true">https://khs0806.tistory.com/24</guid>
      <comments>https://khs0806.tistory.com/24#entry24comment</comments>
      <pubDate>Sun, 19 Jul 2020 18:11:51 +0900</pubDate>
    </item>
  </channel>
</rss>