<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>hee_jun.log</title>
        <link>https://velog.io/</link>
        <description>반갑습니다. 개발자 변희준입니다.</description>
        <lastBuildDate>Mon, 26 Jun 2023 06:39:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>hee_jun.log</title>
            <url>https://velog.velcdn.com/images/hee_jun/profile/2ef81755-4c93-4883-a6de-78acc7daf742/image.jfif</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. hee_jun.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/hee_jun" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[리눅스 java 폰트 설정]]></title>
            <link>https://velog.io/@hee_jun/%EB%A6%AC%EB%88%85%EC%8A%A4-java-%ED%95%9C%EA%B8%80-%EA%B8%80%EA%BC%B4-%EC%84%A4%EC%A0%95</link>
            <guid>https://velog.io/@hee_jun/%EB%A6%AC%EB%88%85%EC%8A%A4-java-%ED%95%9C%EA%B8%80-%EA%B8%80%EA%BC%B4-%EC%84%A4%EC%A0%95</guid>
            <pubDate>Mon, 26 Jun 2023 06:39:35 GMT</pubDate>
            <description><![CDATA[<p>운영중인 어플리케이션을 Window(NT) 서버에서 Linux(CentOS 7) 서버로 이전하여 구축하는 작업을 진행했다. </p>
<p>리눅스 서버에서는 Window 서버에서 기본으로 제공하는 한글 글꼴을 지원해주지 않는점을 발견했다. 
추가적으로 어플리케이션 출력물 중 바코드가 필요한 출력물이 있는데, 바코드 글꼴 또한 지원하지 않았다. 리눅스에서 글꼴을 설정하는 방법을 정리하고자 한다.</p>
<h3 id="💡-사용할-글꼴-구하기">💡 사용할 글꼴 구하기</h3>
<pre><code>📌 굴림 (gulim.ttc)
📌 바코드 (FRE3OF9X.ttx)</code></pre><ul>
<li>바코드 글꼴은 구글링을 통해서 다운</li>
<li>굴림 글꼴은 로컬 컴퓨터의 C:\Windows\Fonts 경로에 존재</li>
</ul>
<h3 id="💡-usrsharefonts-경로에-다운-받은-글꼴-주입">💡 /usr/share/fonts 경로에 다운 받은 글꼴 주입</h3>
<ul>
<li>파일질라(ftp)를 통해 리눅스 서버 /usr/share/fonts 경로에 폰트주입<ul>
<li>굴림 (gulim.ttf)</li>
<li>바코드 (FRE3OF9X.ttf)</li>
</ul>
</li>
</ul>
<blockquote>
<h4 id="폰트-유틸리티-파일-생성-및-적용된-글꼴-목록-확인">폰트 유틸리티 파일 생성 및 적용된 글꼴 목록 확인</h4>
<p>$ mkfontscale 
$ mkfontdir
$ fc-cache
$ fc-list 
$ fc-list :lang=ko</p>
</blockquote>
<h3 id="💡-어플리케이션에서-사용하는-jre-설치경로의-libfonts-경로로-이동하여-다운-받은-글꼴-주입">💡 어플리케이션에서 사용하는 jre 설치경로의 /lib/fonts 경로로 이동하여 다운 받은 글꼴 주입</h3>
<ul>
<li>파일질라(ftp)를 통해 리눅스 서버에 설치된 ~jre/lib/fonts 경로에 폰트주입</li>
<li>경로 예) /usr/lib/jvm/java-1.8.0-openjdk/jre/lib/fonts<ul>
<li>굴림 글꼴 (gulim.ttf)</li>
<li>바코드 글꼴 (FRE3OF9X.ttf)</li>
</ul>
</li>
</ul>
<blockquote>
<h4 id="추가적으로-libfonts-경로에-폰트-유틸리티-파일을-생성-하고-폰트-캐시-갱신">추가적으로 /lib/fonts 경로에 폰트 유틸리티 파일을 생성 하고 폰트 캐시 갱신</h4>
<p>$ mkfontscale 
$ mkfontdir
$ fc-cache </p>
</blockquote>
<h3 id="💡-fontconfigproperties-파일-생성-및-수정">💡 fontconfig.properties 파일 생성 및 수정</h3>
<ul>
<li>경로 예) /usr/lib/jvm/java-1.8.0-openjdk/jre/lib</li>
<li>Window ~/jre/lib 경로에는 fontconfig.properties.src 파일이 존재한다. <ul>
<li>window 에서 기본적으로 제공하는 font 설정들로 추정.</li>
</ul>
</li>
<li>리눅스 ~/jre/lib 경로에는 해당 properties 파일이 존재하지 않았다.<ul>
<li>리눅스에는 기본적으로 제공되는 font 설정이 없기 때문에 직접 설정을 해줘야한다.</li>
</ul>
</li>
</ul>
<blockquote>
<p>version=1
sequence.allfonts=alphabetic/default,korean,dingbats,symbol
#gulim
serif.plain.korean=gulim
filename.gulim=/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/fonts/gulim.ttf
#바코드 free3_of_9x
serif.plain.korean=FRE3OF9X
filename.FRE3OF9X=/usr/lib/jvm/java-1.8.0-openjdk/jre/lib/fonts/FRE3OF9X.ttf    </p>
</blockquote>
<ul>
<li>마지막으로 캐시 초기화 후 어플리케이션 재기동</li>
</ul>
<blockquote>
<p>$ fc-cache </p>
</blockquote>
<hr/>


<h3 id="📌-바코드-글꼴-적용-전">📌 바코드 글꼴 적용 전</h3>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/162f099b-78be-4922-b141-56da8e837b5b/image.png" alt=""></p>
<h3 id="📌-바코드-글꼴-적용-후">📌 바코드 글꼴 적용 후</h3>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/f834b27e-3fcd-48a3-8ac0-9f3c6bc3048b/image.png" alt=""></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[공공데이터 API 활용하기]]></title>
            <link>https://velog.io/@hee_jun/%EA%B3%B5%EA%B3%B5%EB%8D%B0%EC%9D%B4%ED%84%B0-API-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0</link>
            <guid>https://velog.io/@hee_jun/%EA%B3%B5%EA%B3%B5%EB%8D%B0%EC%9D%B4%ED%84%B0-API-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0</guid>
            <pubDate>Sat, 08 Apr 2023 13:26:04 GMT</pubDate>
            <description><![CDATA[<h3 id="💡-공공데이터-포털-이란">💡 공공데이터 포털 이란?</h3>
<p>공공데이터포털은 공공기관이 생성하고 관리하고 있는 데이터를 
모든 국민들이 쉽고 편리하게 이용할 수 있도록 파일데이터, 오픈API, 시각화 등 다양한 방식으로 제공하는 사이트이다.</p>
<hr/>

<h3 id="💡-공공데이터-api-신청하기">💡 공공데이터 API 신청하기</h3>
<p>공공데이터 오픈 API를 활용하기전 신청을 해보자.
👉 <a href="https://www.data.go.kr/">공공데이터 포털 홈페이지</a>
API를 활용하려면 위 홈페이지에 회원가입을 하고 로그인이 필요하다.</p>
<p>로그인 후 원하는 오픈 API를 선정 후 활용신청을 작성한다.
미세먼지가 좋지 않은 요즘 한국환경공단에서 제공하는 전국 대기오염정보 API를 사용해보자.
<img src="https://velog.velcdn.com/images/hee_jun/post/cbbf9107-e3f5-495a-b0b0-1c9bb9ac5106/image.GIF" alt=""></p>
<p>활용신청 버튼을 클릭하면 활용목적 / 상세API / 동의여부 등 간단한 정보를 입력한 후 신청을 할 수 있다.
<em>(참고문서는 개발에 필요한 정보들이 많기 때문에 정독하는 것을 추천한다.)</em></p>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/9bf7d59c-c234-4318-852a-5e5f130f3d85/image.GIF" alt=""></p>
<p>개발 시 참고할 수 있는 샘플코드를 각 언어별로 제공하고있다.</p>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/d10ad12a-c922-4b49-bc25-dbba7462ad86/image.GIF" alt=""></p>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/f8c1adad-0e41-4c0c-9b53-09af6cde68bb/image.GIF" alt=""></p>
<p>상세목록으로 이동하면 개발에 필요한 인증키와 함께 데이터를 미리 확인할 수 있는 호출 Form 을 확인할 수 있다.
<em>(단, API는 신청 후 1~2시간 뒤에 호출이 가능하기 때문에 바로 확인 할 경우 데이터가 조회되지 않는다.)</em></p>
<hr/>

<h3 id="💡-공공데이터-api-활용하기">💡 공공데이터 API 활용하기</h3>
<hr/>

<p>Spring Boot와 Thymeleaf를 사용하여 위 샘플소스를 이용해 전국의 실시간 미세먼지 정보를 조회할 수 있는 화면을 만들어보자</p>
<h4 id="👉-apartmentdetailcontrollerjava">👉 ApartmentDetailController.java</h4>
<pre><code class="language-java">@Controller
@RequestMapping(&quot;/api/apartment&quot;)
public class ApartmentDetailController {

    @Autowired
    ApartmentDetailService apartmentDetailService = new ApartmentDetailService();

    @GetMapping(&quot;/view&quot;)
    public String view() {
        return &quot;public/apartment&quot;;
    }

    @PostMapping(&quot;/search&quot;)
    public String search(Model model, @RequestBody(required = false) String searchDate) {
        List&lt;Map&lt;String, Object&gt;&gt; result = new ArrayList&lt;&gt;();
        try {
            SimpleDateFormat sf = new SimpleDateFormat(&quot;yyyy-MM-dd&quot;);
            Date date = new Date();
            if (searchDate == null) searchDate = sf.format(date);
            System.out.println(&quot;searchDate = &quot; + searchDate);
            result = apartmentDetailService.detailApiCall(searchDate);
            model.addAttribute(&quot;apiData&quot;, result);
        } catch (IOException | ParserConfigurationException | SAXException e) {
            System.out.println(&quot;e.getMessage() = &quot; + e.getMessage());
        }
        return &quot;public/apartment :: #apiTable&quot;;
    }

}</code></pre>
<h4 id="👉-apartmentdetailservice-java">👉 ApartmentDetailService .java</h4>
<pre><code class="language-java">@Service
public class ApartmentDetailService {

    public List&lt;Map&lt;String, Object&gt;&gt; detailApiCall(String searchDate) throws IOException, ParserConfigurationException, SAXException {
        StringBuilder urlBuilder = new StringBuilder(&quot;http://apis.data.go.kr/B552584/ArpltnInforInqireSvc/getMinuDustFrcstDspth&quot;); /*URL*/
        urlBuilder.append(&quot;?&quot; + URLEncoder.encode(&quot;serviceKey&quot;,&quot;UTF-8&quot;) + &quot;=service Key&quot;); /*Service Key*/
        urlBuilder.append(&quot;&amp;&quot; + URLEncoder.encode(&quot;returnType&quot;,&quot;UTF-8&quot;) + &quot;=&quot; + URLEncoder.encode(&quot;xml&quot;, &quot;UTF-8&quot;)); /*xml 또는 json*/
        urlBuilder.append(&quot;&amp;&quot; + URLEncoder.encode(&quot;numOfRows&quot;,&quot;UTF-8&quot;) + &quot;=&quot; + URLEncoder.encode(&quot;100&quot;, &quot;UTF-8&quot;)); /*한 페이지 결과 수(조회 날짜로 검색 시 사용 안함)*/
        urlBuilder.append(&quot;&amp;&quot; + URLEncoder.encode(&quot;pageNo&quot;,&quot;UTF-8&quot;) + &quot;=&quot; + URLEncoder.encode(&quot;1&quot;, &quot;UTF-8&quot;)); /*페이지번호(조회 날짜로 검색 시 사용 안함)*/
        urlBuilder.append(&quot;&amp;&quot; + URLEncoder.encode(&quot;searchDate&quot;,&quot;UTF-8&quot;) + &quot;=&quot; + URLEncoder.encode(searchDate, &quot;UTF-8&quot;)); /*통보시간 검색(조회 날짜 입력이 없을 경우 한달동안 예보통보 발령 날짜의 리스트 정보를 확인)*/
        urlBuilder.append(&quot;&amp;&quot; + URLEncoder.encode(&quot;InformCode&quot;,&quot;UTF-8&quot;) + &quot;=&quot; + URLEncoder.encode(&quot;PM10&quot;, &quot;UTF-8&quot;)); /*통보코드검색(PM10, PM25, O3)*/
        URL url = new URL(urlBuilder.toString());
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        conn.setRequestMethod(&quot;GET&quot;);
        conn.setRequestProperty(&quot;Content-type&quot;, &quot;application/json&quot;);
        // System.out.println(&quot;Response code: &quot; + conn.getResponseCode());
        BufferedReader rd;
        if(conn.getResponseCode() &gt;= 200 &amp;&amp; conn.getResponseCode() &lt;= 300) {
            rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        } else {
            rd = new BufferedReader(new InputStreamReader(conn.getErrorStream()));
        }
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = rd.readLine()) != null) {
            sb.append(line);
        }
        rd.close();
        conn.disconnect();
        // System.out.println(sb.toString());

        // Document Parsing
        /**
        DocumentBuilderFactory dbFactoty = DocumentBuilderFactory.newInstance();
        DocumentBuilder dBuilder = dbFactoty.newDocumentBuilder();
        Document doc = dBuilder.parse(String.valueOf(url));
        // 파싱할 tag
        NodeList nList = doc.getElementsByTagName(&quot;item&quot;);
        // for 문..
        for (int temp = 0; temp &lt; nList.getLength(); temp++) {
        Node nNode = nList.item(temp);
        Element eElement = (Element) nNode;
        if (nNode.getNodeType() == Node.ELEMENT_NODE) {
            map.put(&quot;dataTime&quot;, getTagValue(&quot;gradeType&quot;, eElement));
            ...
            // DB Insert
        }
        */

        //XML -&gt; Json Parsing
        JSONObject jsonObj = XML.toJSONObject(sb.toString());
        String xmlObjectStr = jsonObj.toString();

        //item 항목 추출
        ObjectMapper objectMapper = new ObjectMapper();
        Map&lt;String, Object&gt; map = objectMapper.readValue(xmlObjectStr, new TypeReference&lt;Map&lt;String, Object&gt;&gt;() {}); //모든 JSON 데티어를 MAP 형식으로 변경
        Map&lt;String, Object&gt; dataResponse = (Map&lt;String, Object&gt;) map.get(&quot;response&quot;);
        Map&lt;String, Object&gt; body = (Map&lt;String, Object&gt;) dataResponse.get(&quot;body&quot;);
        Map&lt;String, Object&gt; items  = (Map&lt;String, Object&gt;) body.get(&quot;items&quot;);
        List&lt;Map&lt;String, Object&gt;&gt; itemList = (List&lt;Map&lt;String, Object&gt;&gt;) items.get(&quot;item&quot;);
        return itemList;
    }

}</code></pre>
<h4 id="👉-apartmenthtml">👉 apartment.html</h4>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&gt;
&lt;head&gt;
    &lt;meta charset=&quot;UTF-8&quot;&gt;
    &lt;title&gt;공공데이터&lt;/title&gt;
    &lt;link th:href=&quot;@{/css/table.css}&quot;
          href=&quot;../css/table.css&quot; rel=&quot;stylesheet&quot;&gt;
    &lt;script src=&quot;https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js&quot;&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;br/&gt;
    &lt;label for=&quot;startDate&quot;&gt;조회일자 &lt;/label&gt;
    &lt;input type=&quot;date&quot; id=&quot;startDate&quot; class=&quot;startDate&quot; name=&quot;trip-start&quot; value=&quot;&quot;&gt;
    &lt;button id=&quot;apiCallBtn&quot; onclick=&quot;apiCall(document.getElementById(&#39;startDate&#39;).value);&quot;&gt;조회&lt;/button&gt;
    &lt;br/&gt;&lt;br/&gt;
    &lt;div id=&quot;apiTable&quot;&gt;
    &lt;table&gt;
        &lt;colgroup&gt;
            &lt;col style=&quot;width: 10%&quot;&gt;
            &lt;col style=&quot;width: 5%&quot;&gt;
            &lt;col style=&quot;width: 20%&quot;&gt;
            &lt;col style=&quot;width: 20%&quot;&gt;
            &lt;col style=&quot;width: 20%&quot;&gt;
            &lt;col style=&quot;width: 25%&quot;&gt;
        &lt;/colgroup&gt;
        &lt;tr&gt;
            &lt;th&gt;통보시간&lt;/th&gt;
            &lt;th&gt;통보코드&lt;/th&gt;
            &lt;th&gt;예보개황&lt;/th&gt;
            &lt;th&gt;발생원인&lt;/th&gt;
            &lt;th&gt;예보등급&lt;/th&gt;
            &lt;th&gt;예측모델이미지&lt;/th&gt;
        &lt;/tr&gt;
        &lt;th:block th:each=&quot;map : ${apiData}&quot;&gt;
            &lt;tr&gt;
                &lt;td th:text=&quot;${map.dataTime}&quot;&gt;&lt;/td&gt;
                &lt;td th:text=&quot;${map.informCode}&quot;&gt;&lt;/td&gt;
                &lt;td th:text=&quot;${map.informOverall}&quot;&gt;&lt;/td&gt;
                &lt;td th:text=&quot;${map.informCause}&quot;&gt;&lt;/td&gt;
                &lt;td th:text=&quot;${map.informGrade}&quot;&gt;&lt;/td&gt;
                &lt;td&gt;
                    &lt;img id=&quot;imgId1&quot; th:src=&quot;${map.imageUrl1}&quot; alt=&quot;첨부이미지&quot; th:if=&quot;${map.imageUrl1 != null}&quot; /&gt;
                    &lt;img id=&quot;imgId2&quot; th:src=&quot;${map.imageUrl2}&quot; alt=&quot;첨부이미지&quot; th:if=&quot;${map.imageUrl2 != null}&quot; /&gt;
                    &lt;img id=&quot;imgId3&quot; th:src=&quot;${map.imageUrl3}&quot; alt=&quot;첨부이미지&quot; th:if=&quot;${map.imageUrl3 != null}&quot; /&gt;
                &lt;/td&gt;
            &lt;/tr&gt;
        &lt;/th:block&gt;
    &lt;/table&gt;
    &lt;/div&gt;
&lt;/body&gt;
&lt;script th:inline=&quot;javascript&quot;&gt;
    function apiCall(date) {
        //Ajax 호출
        var inputData = { searchDate : date };
        $.ajax({
            contentType:&quot;application/json;charset=UTF-8&quot;,
            url: &quot;/api/apartment/search&quot;,
            type: &quot;POST&quot;,
            data: date,
            success: function(data){
               console.log(data);
               $(&quot;#apiTable&quot;).replaceWith(data);
            },
            error: function(xhr, status, error){
               alert(xhr.responseText);
            }
        });
    }
&lt;/script&gt;
&lt;/html&gt;</code></pre>
<br/>

<p>😂 미세먼지 나쁨
<img src="https://velog.velcdn.com/images/hee_jun/post/903a8202-8468-4cfe-8628-377fc73b9216/image.png" alt=""></p>
<p>😊 미세먼지 좋음
<img src="https://velog.velcdn.com/images/hee_jun/post/4d8a3ccc-7e63-43c4-b6f7-732f707c834a/image.png" alt=""></p>
<hr/>

]]></description>
        </item>
        <item>
            <title><![CDATA[관계형 데이터 모델링 (정규화)]]></title>
            <link>https://velog.io/@hee_jun/%EA%B4%80%EA%B3%84%ED%98%95-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81-%EC%A0%95%EA%B7%9C%ED%99%94</link>
            <guid>https://velog.io/@hee_jun/%EA%B4%80%EA%B3%84%ED%98%95-%EB%8D%B0%EC%9D%B4%ED%84%B0-%EB%AA%A8%EB%8D%B8%EB%A7%81-%EC%A0%95%EA%B7%9C%ED%99%94</guid>
            <pubDate>Mon, 05 Dec 2022 16:13:22 GMT</pubDate>
            <description><![CDATA[<h3 id="정규화-normalization">정규화 (Normalization)</h3>
<blockquote>
</blockquote>
<h4 id="불필요한-데이터data-redundancy를-제거하여-중복-최소화">불필요한 데이터(data redundancy)를 제거하여 중복 최소화</h4>
<h4 id="데이터베이스의-데이터들을-최대한-중복-제거하여-이상-현상--anomaly--제거">데이터베이스의 데이터들을 최대한 중복 제거하여 이상 현상 ( Anomaly ) 제거</h4>
<ul>
<li>갱신 이상 ( Modification Anomaly )
중복된 데이터 중 일부를 갱신할 때 의도치 않은 데이터가 갱신됨으로써 생기는 데이터의 불일치</li>
<li>삽입 이상 ( Insertion Anomaly )
새 데이터를 삽입할 때 의도치 않은 데이터가 삽입됨으로써 생기는 데이터의 불일치</li>
<li>삭제 이상 ( Deletion Anomaly )
데이터를 삭제할 때 의도치 않은 데이터까지 삭제됨으로써 생기는 데이터의 불일치</li>
</ul>
<h4 id="😃-제-1-정규화-1nf">😃 제 1 정규화 (1NF)</h4>
<blockquote>
</blockquote>
<ul>
<li>도메인 원자값</li>
<li>반복 그룹은 존재 하지 않는다</li>
<li>모든행은 식별자로 완전하게 구분</li>
</ul>
<h4 id="🤔-before">🤔 Before</h4>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/f8cd8fc4-0d5c-4498-b614-3bff91ccbcb5/image.GIF" alt=""></p>
<p>위의 테이블은 제 1정규화의 원자성을 만족하지 않는다.
컬럼 hash_tag에는 하나의 row 에 book, knowledge, graffiti 등 하나 이상의 값이 존재</p>
<p><span style='background-color: #00BFFF'>select * from goods where hash_tag = &#39;free&#39;</span></p>
<p><span style='background-color: #00BFFF'> select * from goods order by hash_tag </span></p>
<p>위와 같은 쿼리를 사용할 경우 원하는 데이터를 조회불가</p>
<p>또한, 테이블과 join 할 경우 값이 하나의 컬럼 안에 여러 개의 값이 있다면, 조인하는 것이 어렵거나 불가능</p>
<h4 id="😊-after">😊 After</h4>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/d50e58f4-b438-4123-9ab0-d87b004548d9/image.GIF" alt=""></p>
<p>goods table, tag table 을 나눈 후 이 두 테이블을 연결하는 goods_tag 테이블 추가</p>
<p>hash_tag는 title이 무엇이느냐에 따라서 hash_tag가 book, knowledge, graffiti 인지 달라진다</p>
<h4 id="😃-제-2-정규화-2nf">😃 제 2 정규화 (2NF)</h4>
<blockquote>
</blockquote>
<ul>
<li>부분종속성이 없어야한다</li>
<li>중복키 여부 확인</li>
</ul>
<h4 id="🤔-before-1">🤔 Before</h4>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/1fa80729-83c5-4c72-9de5-05ab8a442d01/image.GIF" alt=""></p>
<p>type 이라는 칼럼을 삭제하여 중복 데이터를 제거하여 테이블화를 한다.</p>
<h4 id="😊-after-1">😊 After</h4>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/11b61786-60e7-4e82-89f5-49b6a77aad1e/image.GIF" alt=""></p>
<p>goods 테이블에는 더이상 중복되는 데이터가 존재하지 않는다.
title 과 type에 의존하는 type 테이블을 생성하여 관계를 형성한다.</p>
<h4 id="😃-제-3-정규화-3nf">😃 제 3 정규화 (3NF)</h4>
<blockquote>
</blockquote>
<ul>
<li>이행종속성을 제거</li>
</ul>
<p>goods 테이블의 행은 title의 기본키에 종속되어있다. book 이나 pencil 이 행 전체를 대표하는 칼럼이다. 단, author_name 과 author_profile 칼럼은 author_id 에 의존하고 있는 관계도 존재한다. 이를 이행종속성 관계라고한다.</p>
<h4 id="🤔-before-2">🤔 Before</h4>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/bd459f39-f5a4-4df4-a96a-acdce5ed8606/image.GIF" alt=""></p>
<h4 id="😊-after-2">😊 After</h4>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/7da00bf8-73b0-4536-b271-f9cd8efc3dd6/image.GIF" alt=""></p>
<p><em>cf) <a href="https://www.youtube.com/watch?v=aS9FoCNlt3o&amp;t=166s">생활코딩 정규화 시리즈</a></em></p>
]]></description>
        </item>
        <item>
            <title><![CDATA[github repository 생성]]></title>
            <link>https://velog.io/@hee_jun/github-repository-%EC%83%9D%EC%84%B1</link>
            <guid>https://velog.io/@hee_jun/github-repository-%EC%83%9D%EC%84%B1</guid>
            <pubDate>Tue, 22 Nov 2022 13:14:04 GMT</pubDate>
            <description><![CDATA[<h3 id="github-repository-원격-저장소-만들기">github repository (원격 저장소) 만들기</h3>
<ul>
<li><a href="https://github.com/">www.githib.com</a>
<img src="https://velog.velcdn.com/images/hee_jun/post/34538c60-804a-435f-a6ca-5c6e363826b5/image.png" alt=""></li>
<li>깃허브 홈페이지에 접속 후 <span style="background-color: rgba(242,179,188,0.5)">회원가입 및 로그인</span></li>
<li><span style="background-color: rgba(242,179,188,0.5)">Repositories</span> 탭 선택 후 <span style="background-color: rgba(242,179,188,0.5)">New</span> 버튼을 클릭한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/52310bab-07df-4dfb-ae48-f9227aa2f1ff/image.png" alt=""></p>
<ul>
<li><span style="background-color: rgba(242,179,188,0.5)">Repository name</span> 항목에 원격 저장소 이름을 입력한다.<br> 올리고자 하는 프로젝트의 폴더의 이름과 달라도 상관없지만, 헷갈리지 않도록 동일한 이름으로 지정한다.</li>
<li>저장소에 간단한 설명은 <span style="background-color: rgba(242,179,188,0.5)">Description</span> 항목에 작성하고, <br>저장소에 자세한 설명을 원한다면  <span style="background-color: rgba(242,179,188,0.5)">Add a README file</span> 을 체크한다.</li>
<li>나의 저장소를 모든 사람들에게 공유하고 싶다면 <span style="background-color: rgba(242,179,188,0.5)">Public</span> 를 선택한다. <br> 혼자만의 저장소로 간직하고 싶다면 <span style="background-color: rgba(242,179,188,0.5)">Private</span> 선택한다.</li>
<li>git repository 나 staging area 에 추가하고 싶지 않은 폴더나 파일을 정의하고 싶다면 <br> <span style="background-color: rgba(242,179,188,0.5)">.gitignore template</span> 를 선택한다.</li>
<li>모든 설정이 끝났다면 <span style="background-color: rgba(242,179,188,0.5)">Create repository</span> 를 선택하여 저장소를 생성한다.</li>
</ul>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/b01088ea-fad1-4bcf-84e3-b3cb02f22fa1/image.png" alt=""></p>
<ul>
<li>생성된 원격 저장소를 확인할 수 있다.</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[FileUpload Multipart 설정 (Tomcat)]]></title>
            <link>https://velog.io/@hee_jun/FileUpload-Multipart-%EC%84%A4%EC%A0%95-Tomcat</link>
            <guid>https://velog.io/@hee_jun/FileUpload-Multipart-%EC%84%A4%EC%A0%95-Tomcat</guid>
            <pubDate>Fri, 04 Nov 2022 02:58:19 GMT</pubDate>
            <description><![CDATA[<p>✔ Multipart 파일 업로드를 위한 프로젝트 설정 및 Tomcat 설정</p>
<h3 id="1-maven-dependency-주입">1. maven dependency 주입</h3>
<ul>
<li><p><em>pom.xml</em></p>
<pre><code>&lt;!-- File upload --&gt;
&lt;dependency&gt;
  &lt;groupId&gt;commons-fileupload&lt;/groupId&gt;
  &lt;artifactId&gt;commons-fileupload&lt;/artifactId&gt;
  &lt;version&gt;1.3.2&lt;/version&gt;
&lt;/dependency&gt;

&lt;dependency&gt;
  &lt;groupId&gt;commons-io&lt;/groupId&gt;
  &lt;artifactId&gt;commons-io&lt;/artifactId&gt;
  &lt;version&gt;2.5&lt;/version&gt;
&lt;/dependency&gt;</code></pre><h3 id="2-multipartfilter-선언-및-url-pattern-지정">2. MultipartFilter 선언 및 url-pattern 지정</h3>
<ul>
<li><em>프로젝트/src/webapp/WEB-INF/web.xml</em><pre><code>&lt;filter&gt;
&lt;filter-name&gt;MultipartFilter&lt;/filter-name&gt;
&lt;filter-class&gt;org.springframework.web.multipart.support.MultipartFilter&lt;/filter-class&gt;
&lt;/filter&gt;
&lt;filter-mapping&gt;
&lt;filter-name&gt;MultipartFilter&lt;/filter-name&gt;
&lt;url-pattern&gt;/*&lt;/url-pattern&gt;
&lt;/filter-mapping&gt;</code></pre><h3 id="3-multipartresolver-bean-주입">3. MultipartResolver bean 주입</h3>
</li>
</ul>
</li>
<li><p><em>dispatcher-servlet.xml</em></p>
<pre><code>  &lt;bean id=&quot;multipartResolver&quot; class=&quot;org.springframework.web.multipart.commons.CommonsMultipartResolver&quot;&gt;
      &lt;!-- &lt;property name=&quot;maxUploadSize&quot; value=&quot;100000000&quot; /&gt;
      &lt;property name=&quot;maxInMemorySize&quot; value=&quot;100000000&quot; /&gt; --&gt;
  &lt;/bean&gt;</code></pre></li>
</ul>
<h3 id="-파일-업로드-시-오류-발생">※ 파일 업로드 시 오류 발생</h3>
<ul>
<li>오류내용<pre><code>      org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nested exception is java.lang.IllegalStateException: 어떤 multi-part 설정도 제공되지 않았기 때문에, part들을 처리할 수 없습니다.
          at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:112)
          at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.&lt;init&gt;(StandardMultipartHttpServletRequest.java:86)
          at org.springframework.web.multipart.support.StandardServletMultipartResolver.resolveMultipart(StandardServletMultipartResolver.java:80)
          at org.springframework.web.multipart.support.MultipartFilter.doFilterInternal(MultipartFilter.java:112)
          at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
          at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
          at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
          at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202)
          at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97)
          at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:542)
          at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:143)
          at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)
          at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
          at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78)
          at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
          at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:374)
          at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
          at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:880)
          at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1601)
          at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
          at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
          at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
          at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
          at java.lang.Thread.run(Unknown Source)
      Caused by: java.lang.IllegalStateException: 어떤 multi-part 설정도 제공되지 않았기 때문에, part들을 처리할 수 없습니다.
          at org.apache.catalina.connector.Request.parseParts(Request.java:2803)
          at org.apache.catalina.connector.Request.getParts(Request.java:2771)
          at org.apache.catalina.connector.RequestFacade.getParts(RequestFacade.java:1098)
          at org.springframework.web.multipart.support.StandardMultipartHttpServletRequest.parseRequest(StandardMultipartHttpServletRequest.java:93)
          ... 23 more코드를 입력하세요</code></pre></li>
</ul>
<ul>
<li><p>오류가 난 이유</p>
<p>Tomcat이 multipart/form-data 요청 본문을 분석하지 못하여 경로를 찾지 못함</p>
</li>
</ul>
<h3 id="4-tomcat---contextxml">4. tomcat - context.xml</h3>
<pre><code>&lt;Context allowCasualMultipartParsing=&quot;true&quot; path=&quot;/&quot;&gt;
    &lt;Resources cachingAllowed=&quot;true&quot; cacheMaxSize=&quot;100000&quot; /&gt;
    &lt;!-- Default set of monitored resources. If one of these changes, the    --&gt;
    &lt;!-- web application will be reloaded.                                   --&gt;
    &lt;WatchedResource&gt;WEB-INF/web.xml&lt;/WatchedResource&gt;
    &lt;WatchedResource&gt;WEB-INF/tomcat-web.xml&lt;/WatchedResource&gt;
    &lt;WatchedResource&gt;${catalina.base}/conf/web.xml&lt;/WatchedResource&gt;
    &lt;!-- Uncomment this to disable session persistence across Tomcat restarts --&gt;
    &lt;!--
    &lt;Manager pathname=&quot;&quot; /&gt;
    --&gt;
&lt;/Context&gt;</code></pre><h3 id="5-tomcat---webxml">5. tomcat - web.xml</h3>
<pre><code>    &lt;servlet&gt;
        ...
        &lt;multipart-config&gt;
            &lt;!-- 50MB max --&gt;
            &lt;max-file-size&gt;52428800&lt;/max-file-size&gt;
            &lt;max-request-size&gt;52428800&lt;/max-request-size&gt;
            &lt;file-size-threshold&gt;0&lt;/file-size-threshold&gt;
        &lt;/multipart-config&gt;
    &lt;/servlet&gt;</code></pre><h3 id="6-tomcat---serverxml">6. tomcat - server.xml</h3>
<pre><code>&lt;Connector ... maxPostSize=&quot;52428800&quot; ... /&gt;</code></pre><ul>
<li><em>Post 전송 시 데이터 크기 최대 사이즈 지정</em><blockquote>
<p>maxPostSize=&quot;52428800&quot; // 50MB 
maxPostSize=&quot;-1&quot; // 디폴트값 해제</p>
</blockquote>
</li>
</ul>
]]></description>
        </item>
        <item>
            <title><![CDATA[log4j 설정]]></title>
            <link>https://velog.io/@hee_jun/log4j</link>
            <guid>https://velog.io/@hee_jun/log4j</guid>
            <pubDate>Thu, 03 Nov 2022 02:02:29 GMT</pubDate>
            <description><![CDATA[<p>최근 회사에서 한창 진행중인 프로젝트에 BackEnd 개발인력으로 중간에 투입되었다.</p>
<p>프로젝트의 큰틀은 안드로이드 앱 (FrontEnd) 과 Java (BackEnd) 를 구분하여 개발하고, FrontEnd에서 API를 호출하여 BackEnd에서 결과값을 json 형태로 return 해주는 방식이였다. 
프로젝트 IDE를 설정하고, 소스를 받아서 확인해보니 문제점들이 꽤나 많이 보였다.</p>
<p>그 중 하나가 log 관련 설정이 전혀 되지 않아서 불필요한 로그들이 출력되고
필요한 로그들은 출력이 되지 않는 상태였다.
log4j 관련 설정을 먼저 해야겠다고 생각했다.</p>
<h4 id="-log4j-설정-변경-전-console-log"># log4j 설정 변경 전 console log</h4>
<p><img src="https://velog.velcdn.com/images/hee_jun/post/a9d40344-b764-423d-b53b-00c15cb78e50/image.png" alt=""></p>
<p>처음 위에 log4j 출력 설정을 보았을 때 로그관련해서는 아무도 신경을 못 썼다는 생각이 들었다.</p>
<h4 id="-pomxml"># pom.xml</h4>
<p>pom.xml 의 maven jar파일 주입부터 설정 파일을 수정하기 시작했다.</p>
<blockquote>
<pre><code>    &lt;properties&gt;
        ...
        &lt;org.apache.logging.log4j&gt;2.17.1&lt;/org.apache.logging.log4j&gt;
        &lt;org.slf4j&gt;1.7.7&lt;/org.slf4j&gt;
        ...
    &lt;/properties&gt;</code></pre></blockquote>
<pre><code>    &lt;!-- Log4J --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
        &lt;artifactId&gt;log4j-core&lt;/artifactId&gt;
        &lt;version&gt;${org.apache.logging.log4j}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
        &lt;artifactId&gt;log4j-api&lt;/artifactId&gt;
        &lt;version&gt;${org.apache.logging.log4j}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.apache.logging.log4j&lt;/groupId&gt;
        &lt;artifactId&gt;log4j-slf4j-impl&lt;/artifactId&gt;
        &lt;version&gt;${org.apache.logging.log4j}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
        &lt;artifactId&gt;log4j-over-slf4j&lt;/artifactId&gt;
        &lt;version&gt;${org.slf4j}&lt;/version&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
        &lt;artifactId&gt;jcl-over-slf4j&lt;/artifactId&gt;
        &lt;version&gt;${org.slf4j}&lt;/version&gt;
    &lt;/dependency&gt;</code></pre><blockquote>
<pre><code>    &lt;!-- log4jdbc --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;com.googlecode.log4jdbc&lt;/groupId&gt;
        &lt;artifactId&gt;log4jdbc&lt;/artifactId&gt;
        &lt;version&gt;1.2&lt;/version&gt;
        &lt;exclusions&gt;
            &lt;exclusion&gt;
                &lt;artifactId&gt;slf4j-api&lt;/artifactId&gt;
                &lt;groupId&gt;org.slf4j&lt;/groupId&gt;
            &lt;/exclusion&gt;
        &lt;/exclusions&gt;
    &lt;/dependency&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.bgee.log4jdbc-log4j2&lt;/groupId&gt;
        &lt;artifactId&gt;log4jdbc-log4j2-jdbc4.1&lt;/artifactId&gt;
        &lt;version&gt;1.16&lt;/version&gt;
    &lt;/dependency&gt;               </code></pre></blockquote>
<pre><code>    &lt;!-- Log4j Remix --&gt;
    &lt;dependency&gt;
        &lt;groupId&gt;org.lazyluke&lt;/groupId&gt;
        &lt;artifactId&gt;log4jdbc-remix&lt;/artifactId&gt;
        &lt;version&gt;0.2.7&lt;/version&gt;
    &lt;/dependency&gt;</code></pre><h4 id="-log4jdbclog4j2properties"># log4jdbc.log4j2.properties</h4>
<p>pom.xml jar 파일 주입 후 log4jdbc.log4j2.properties 파일을 생성하여 아래 properties를 작성한다.
경로 project/src/main/resource</p>
<blockquote>
<p>log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator
log4jdbc.dump.sql.maxlinelength=0</p>
</blockquote>
<h4 id="-log4j2xml"># log4j2.xml</h4>
<p>경로 project/src/main/resource
log4j2.xml 파일은 어떤 로그 파일들을 어느 레벨에서만 출력을 할 것인지 설정하는 곳이다.
설정 level은 아래와 같다.</p>
<p>DEGUG    디버그를 위한 용도로 일반 정보도 상세하게 출력 
INFO    상태 변경과 같이 일반적인 정보를 출력
WRAN    경고성 메시지 (처리가능한 문제 또는 향후 에러의 원인이 될 수 있는 경고성 메시지)
ERROR    일반적인 에러로 처리가 반드시 필요ㄷ
FATAL    시스템적으로 아주 심각한 에러가 발생, 어플리케이션 작동 불가</p>
<h4 id="변경-전"><strong>[변경 전]</strong></h4>
<blockquote>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;Configuration&gt;
    &lt;Appenders&gt;
        &lt;Console name=&quot;console&quot; target=&quot;SYSTEM_OUT&quot;&gt;
            &lt;PatternLayout pattern=&quot;%d %5p [%c] %m%n&quot; /&gt;
        &lt;/Console&gt;
    &lt;/Appenders&gt;
    &lt;Loggers&gt;
        &lt;Logger name=&quot;java.sql&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;jdbc.resultset&quot; level=&quot;ERROR&quot; additivity=&quot;false&quot;&gt;
            &lt;appender-ref ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;egovframework&quot; level=&quot;DEBUG&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
          &lt;!-- log SQL with timing information, post execution --&gt;
        &lt;Logger name=&quot;jdbc.sqltiming&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Root level=&quot;INFO&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Root&gt;
    &lt;/Loggers&gt;
&lt;/Configuration&gt;</code></pre></blockquote>
<h4 id="변경-후"><strong>[변경 후]</strong></h4>
<pre><code>&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;Configuration&gt;
    &lt;Properties&gt;
        &lt;Property name=&quot;name&quot;&gt;consultingSvr&lt;/Property&gt;
        &lt;property name=&quot;log-path&quot;&gt;/usr/local/tomcat9/logs/backup&lt;/property&gt;
        &lt;Property name=&quot;pattern&quot;&gt;%d %5p [%c] %m%n&lt;/Property&gt;
    &lt;/Properties&gt;
    &lt;Appenders&gt;
        &lt;Console name=&quot;console&quot; target=&quot;org.apache.log4j.ConsoleAppender&quot;&gt;
            &lt;PatternLayout pattern=&quot;${pattern}&quot; /&gt;
        &lt;/Console&gt;
        &lt;RollingFile name=&quot;RollingFile&quot; fileName=&quot;${log-path}/${name}.log&quot;
            filePattern=&quot;${log-path}/$${date:yyyy-MM}/${name}_%d{yyyyMMddHH}_%i.log.gz&quot;&gt;
            &lt;PatternLayout&gt;
                &lt;Pattern&gt;${pattern}&lt;/Pattern&gt;
            &lt;/PatternLayout&gt;
            &lt;Policies&gt;
                &lt;TimeBasedTriggeringPolicy /&gt;
                &lt;SizeBasedTriggeringPolicy size=&quot;250 MB&quot; /&gt;
            &lt;/Policies&gt;
            &lt;DefaultRolloverStrategy max=&quot;100&quot;&gt;
                &lt;!-- Nested conditions: the inner condition is only evaluated on files
                    for which the outer conditions are true. --&gt;
                &lt;Delete basePath=&quot;${log-path}&quot; maxDepth=&quot;2&quot;&gt;
                    &lt;IfFileName glob=&quot;*/${name}-*.log.gz&quot;&gt;
                        &lt;IfLastModified age=&quot;30d&quot;&gt;
                            &lt;IfAny&gt;
                                &lt;IfAccumulatedFileSize exceeds=&quot;100 GB&quot; /&gt;
                                &lt;IfAccumulatedFileCount exceeds=&quot;10&quot; /&gt;
                            &lt;/IfAny&gt;
                        &lt;/IfLastModified&gt;
                    &lt;/IfFileName&gt;
                &lt;/Delete&gt;
            &lt;/DefaultRolloverStrategy&gt;
        &lt;/RollingFile&gt;
    &lt;/Appenders&gt;

    &lt;Loggers&gt;
        &lt;Logger name=&quot;java.sql&quot; level=&quot;DEBUG&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;jdbc.sqlonly&quot; level=&quot;WARN&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;        
        &lt;Logger name=&quot;jdbc.sqltiming&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;        
        &lt;Logger name=&quot;jdbc.resultset&quot; level=&quot;WARN&quot; additivity=&quot;false&quot;&gt;
            &lt;appender-ref ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;jdbc.resultsettable&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;        
        &lt;logger name=&quot;jdbc.audit&quot; level=&quot;WARN&quot; additivity=&quot;false&quot;&gt; 
            &lt;appender-ref ref=&quot;console&quot;/&gt; 
        &lt;/logger&gt;
        &lt;Logger name=&quot;jdbc.connection&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;net.sf.log4jdbc&quot; level=&quot;DEBUG&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;        

        &lt;Logger name=&quot;egovframework&quot; level=&quot;DEBUG&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;        
        &lt;Logger name=&quot;org.springframework.core&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.web&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;!-- DEBUG이면 myBatis에서 오류를 찾을수 있음. --&gt;
        &lt;Logger name=&quot;org.springframework.beans&quot; level=&quot;DEBUG&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.jndi&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.context&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.ui&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.aop&quot; level=&quot;INFO&quot; additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.security&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.transaction&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.springframework.jdbc&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;        
        &lt;Logger name=&quot;org.mybatis.spring.mapper&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.mybatis.spring.SqlSessionFactoryBean&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.mybatis.spring.SqlSessionUtils&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;
        &lt;Logger name=&quot;org.apache.ibatis.logging.LogFactory&quot; level=&quot;INFO&quot;
            additivity=&quot;false&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
        &lt;/Logger&gt;        

        &lt;Root level=&quot;DEBUG&quot;&gt;
            &lt;AppenderRef ref=&quot;console&quot; /&gt;
            &lt;AppenderRef ref=&quot;RollingFile&quot; /&gt;
        &lt;/Root&gt;
    &lt;/Loggers&gt;
&lt;/Configuration&gt;
</code></pre><p>작년 이맘때쯤 log4j 보안 이슈로 인해 많은 국내 개발자들이 log4j 취약점을 해결했던걸로 기억한다. 그만큼 국내 IT기업에서 가장 많이 사용되는 log 라이브러리는 log4j라고 생각된다. 
아래링크는 전자정부 표준프레임워크센터에서 안내하는 log4j 보안 이슈 해결법 링크이다.
<a href="https://www.egovframe.go.kr/home/ntt/nttRead.do?menuNo=74&amp;bbsId=6&amp;nttId=1838">Log4j 보안 업데이트 공지</a></p>
]]></description>
        </item>
    </channel>
</rss>