<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>병갈이 블록</title>
    <link>https://hilu0318.tistory.com/</link>
    <description></description>
    <language>ko</language>
    <pubDate>Tue, 14 Apr 2026 19:23:54 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>woojang</managingEditor>
    <item>
      <title>[우아한 테크캠프 Pro 2기] JPA 미션 - Mockito 오류 관련 정리.</title>
      <link>https://hilu0318.tistory.com/221</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;연관관계 설정 뒤 Repository까지 수정을 마치고 ServiceTest 클래스의 테스트 코드를 검증 하는 도중 만난 오류이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;우선 오류 내용은 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1622474621482&quot; class=&quot;java&quot; style=&quot;display: block; overflow: auto; padding: 20px; color: #383a42; background: #f8f8f8; font-size: 14px; font-family: 'SF Mono', Menlo, Consolas, Monaco, monospace; border: 1px solid #ebebeb; line-height: 1.71; margin: 20px auto 0px; cursor: default; z-index: 1; font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; text-decoration-thickness: initial; text-decoration-style: initial; text-decoration-color: initial;&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Argument(s) are different! Wanted:
deleteHistoryService.saveAll(
    java.util.Arrays$ArrayList@d3c52ba7
);
-&amp;gt; at qna.service.QnaServiceTest.verifyDeleteHistories(QnaServiceTest.java:95)
Actual invocations have different arguments:
deleteHistoryService.saveAll(
    [DeleteHistory{id=null, contentType=QUESTION, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194201}, DeleteHistory{id=null, contentType=ANSWER, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194427}]
);
-&amp;gt; at qna.service.QnaService.deleteQuestion(QnaService.java:56)

Comparison Failure: 
&amp;lt;Click to see difference&amp;gt;

Argument(s) are different! Wanted:
deleteHistoryService.saveAll(
    java.util.Arrays$ArrayList@d3c52ba7
);
-&amp;gt; at qna.service.QnaServiceTest.verifyDeleteHistories(QnaServiceTest.java:95)
Actual invocations have different arguments:
deleteHistoryService.saveAll(
    [DeleteHistory{id=null, contentType=QUESTION, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194201}, DeleteHistory{id=null, contentType=ANSWER, contentId=1, deletedById=1, createDate=2021-06-01T00:21:25.194427}]
);
-&amp;gt; at qna.service.QnaService.deleteQuestion(QnaService.java:56)

	at qna.service.QnaServiceTest.verifyDeleteHistories(QnaServiceTest.java:95)
	at qna.service.QnaServiceTest.delete_성공(QnaServiceTest.java:55)
	... 이하 생략&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류를 해결한 방법은 예외 발생 지점부터 역으로 찾아가는거였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오류 발생 코드 위치는 아래와 같다.&lt;/p&gt;
&lt;pre id=&quot;code_1622474729636&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;DeleteHistory&amp;gt; deleteHistories = Arrays.asList(
    new DeleteHistory(ContentType.QUESTION, question.getId(), question.getWriterId(), LocalDateTime.now()),
    new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriterId(), LocalDateTime.now())
);
verify(deleteHistoryService).saveAll(deleteHistories);	// &amp;lt;-- 이 라인&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음보는 내용이라 검색을 해보았다. 그리고 아래와 같은 내용을 확인했다.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;- verify(mock).method(param);&lt;br /&gt;&amp;nbsp; &amp;nbsp; = 해당 Mock Object 의 메소드를 호출했는지 검증&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 코드로 이야기를 해보면&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;deleteHistoryService&lt;/b&gt;&lt;/u&gt;에 있는&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;u&gt;&lt;b&gt;saveAll&lt;/b&gt;&lt;/u&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;메서드가 호출되었는지 검증하는 코드이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만 저 코드라인에 도착하기 전에 해당 메서드가 분명히 호출이 되었다. 그래서 다시 한번 에러 내용을 유심히 보았다. 그리고 자꾸 눈에 들어오는 단어.&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;Argument(s)&amp;nbsp;are&amp;nbsp;different!&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래서 다시한번 param으로 넘어가는 값을 세팅하는 부분을 유심히 보았다. 그랬더니....&lt;/p&gt;
&lt;pre id=&quot;code_1622475210117&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;for (Answer answer : answers) {
    answer.setDeleted(true);
    deleteHistories.add(new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriter(), LocalDateTime.now()));
}
deleteHistoryService.saveAll(deleteHistories);

=========================================================================================================

List&amp;lt;DeleteHistory&amp;gt; deleteHistories = Arrays.asList(
    new DeleteHistory(ContentType.QUESTION, question.getId(), question.getWriterId(), LocalDateTime.now()),
    new DeleteHistory(ContentType.ANSWER, answer.getId(), answer.getWriterId(), LocalDateTime.now())
);
verify(deleteHistoryService).saveAll(deleteHistories);&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;값을 세팅하는 구조는 틀리지만 그건 중요한게 아니고, 셋팅되고 있는 파라미터를 봐야한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결론부터 이야기 하자면, DeleteHistory의 생성자가 2개 존재하고 위와 아래가 각기 다른 생성자를 호출하고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3번째 파라미터의 getter를 보면 위는 Writer를 가져오고 아래는 WriterId를 가져오고 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;getWriter는 User객체를, getWriterId는 Long을 반환하여 실제 로직상 생성된 DeleteHistory 객체는 User 객체를 주입받아 not null상태이고, 검증용으로 생성된 객체는 User객체가 null인 상태이다. 실제로 입력된 값과 검증용 값이 달랐던 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;문제의 발단은, 연관관계를 설정하면서 기존에 id값을 받던 부분을 객체로 받도록 수정하는 과정에서 과도기적으로 남아있었던 생성자가 존재하면서 생신 문제였다. 미리 생성자를 제거했다면 검증부분에 컴파일 에러가 발생해서 사전에 문제를 인지 할 수 있었을 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘의 교훈! 오류 메시지를 잘 보자! 잘 보면 답이 보인다! 그리고 삭제할 코드는 미리미리...ㅎㅎㅎㅎ&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배운것 하나 - verify(mock).method(param)은 메소드 호출 여부 및 파라미터 일치여부까지 확인을 한다는것!&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;** 파라미터 내용까지는 검색이 잘 안되는데...별도의 설정 없이도 파라미터 값이 검증되는 걸로 봐서는 기본으로 제공하는 기능이 아닌가 싶다. 하지만 생각해 봐야 할 건 값 자체의 일치여부는 아닌 듯 하다.(검증용 코드에 날짜값을 완전 다른 값으로 세팅해도 성공으로 넘어간다.) 상태에 대한 비교인건가....이거는 좀 확인 해 봐야할 것 같다.&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/우테캠Pro2기</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/221</guid>
      <comments>https://hilu0318.tistory.com/221#entry221comment</comments>
      <pubDate>Tue, 1 Jun 2021 00:42:43 +0900</pubDate>
    </item>
    <item>
      <title>[우아한 테크캠프 Pro 2기 - 번외] 스터디 &amp;amp; 페어 프로그래밍 2주차</title>
      <link>https://hilu0318.tistory.com/220</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;1주일간 거의 새벽 2시 반 ~ 4시에 자고 아침에 출근을 반복 했더니 오늘 점심시간까지 기절을 해버렸다. 원래 일정은 일찍 일어나서 빨래와 집안 정리를 하고 스터디로 가는 일정이었으나 30분 전에 급하게 일어나서 씻고 바로 스터디 장소로 이동했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2주차도 동일하게 페어 프로그래밍으로 진행하기로 했다. 오늘은 총 4명이 참석해서 2명씩 나누어 진행하였고, 지난주와는 다른 파트너와 함께 하였다. 이번 주 주제는 [인수테스트 실습 : 1단계 - 지하철 노선 관리]이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;처음에는 ATDD를 이해하는데 시간이 좀 걸렸다. 그래도 함께 참석한 분들과 이야기를 나누면서 이해하는데 도움을 많이 받았고 미션을 진행하면서 자세한 감을 잡기로 했다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;오늘의 진행은 인수 테스트 단위로 순서를 돌아가기로 했다. 진행 과정을 돌이켜 보면 지난주와는 조금 다르게 파트너의 차례에도 서로 많은 개입을 하게 되었다는 것이다.(다른 이유는 아니고 서로 이 미션에 대한 이해가 부족한 상황이었기에 자연스럽게 많은 의견을 나눌 수 밖에 없었다.) 그래서인지 궁금한 내용들을 각자가 찾아보게 되고 알게된 것들을 바로바로 공유하면서 문제를 이해해나가는 과정이 상당히 빨랐던 것 같다. 이런 과정은 막상 미션을 시작하였을 때 겪게 되는 막연함과 막막한 감정들로 부터 빨리 벗어나는 것에 큰 도움이 되었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;실제 코드 작성을 진행하면서는 경험한 것은 내가 작성한 코드에 대한 설명도 함께 하면서 진행하였기에 내가 무엇을, 왜, 어떤 방식으로 만드는지에 대한 이해가 우선되어야 할 수 밖에 없었고, 막연한 코드가 아니라 문제 해결의 컨셉을 가져야만 했다는 것이다.(이게 생각보다 훈련이 많이 되는것 같다) 사실 남에게 설명이 가능해야지만이 진짜 제대로 이해한 것이다라는 말이 있듯이 이렇게 내가 짠 코드를 설명하고 내가 사용한 기능을 설명해 내는 과정이 진짜 그것들을 나의 것으로 만들어 가는 과정이라고 생각한다. 그렇게 설명을 하다보면 나 스스로가 정확하게 이해하고 있지 못한 부분들도 드러나고 무엇이 부족한지도 드러나게 된다. 중요한 건 이러한 부족함(또는 내 지식과 기술의 민낯)이 드러나는 것을 부끄러워하고 감추려 하는게 아니라 모름은 인정하고 물어보고 찾아볼 내용으로 리스트업해두고 따로 공부해 보는 자세인 것 같다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;좋았던 점은 위에 언급했지만 함께 내용을 공유하는 과정만으로도 미션을 이해하는 시간이 많이 단축되었다는것과 내가 짠 코드를 설명을 하기 위해 구현 방향을 머릿속에 자세하게 그려두는 연습이 되었다는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단점은 역시나 시간이지 않을까? 미션을 이해하는 과정이라 오히려 시간이 아껴진 느낌이 있지만, 만약 미션 진행을 이해 한 상태로 페어를 했다면 혼자 하는 것 보다는 시간이 더 걸렸을 거라는 생각이 든다. 서로의 생각을 말로 표현하고 그거를 서로 받아들이거나 설득하는 과정을 거쳐야 하기 때문이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 시간적인 아쉬움이 있음에도 두번째 페어 프로그래밍 또한 이러한 아쉬움이 아깝지 않을 정도로 많은걸 깨닫고 알고 느끼게 되는 시간이었다고 생각한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;(지난주도, 이번주도 시행착오 느낌이 강해서 아쉬움이 남지만 매주 하기로 했으니 점차 진행 룰을 정하고 정확히 지키면서 진행하는 훈련이 되지 않을까 기대해 본다.)&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/우테캠Pro2기</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/220</guid>
      <comments>https://hilu0318.tistory.com/220#entry220comment</comments>
      <pubDate>Sun, 30 May 2021 00:52:07 +0900</pubDate>
    </item>
    <item>
      <title>JPA - H2 초기 설정하기.</title>
      <link>https://hilu0318.tistory.com/215</link>
      <description>&lt;p&gt;초기 설정 순서.(Mac 기준)&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. PC에 DB 설정 파일을 생성한다.&lt;/h4&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. JDBC URL을 에플리케이션에서 접근할 수 있는 주소로 수정한다.&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;** 초기설정 진행&lt;/h4&gt;
&lt;p&gt;&lt;b&gt;1.&lt;/b&gt; h2 설치폴더 아래 bin 폴더 아래 h2.sh파일을 실행한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; - ..../h2/bin/h2.sh&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2.&lt;/b&gt; 그러면 브라우저를 통해서 콘솔이 실행된다.&lt;/p&gt;
&lt;p&gt;(브라우저에서 콘솔이 나오지 않을 경우 브라우저에서 보이는 ip 주소를 localhost로 바꾸어 보자)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; width=&quot;412&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/bDdIiK/btq4diJPyte/vsSGbhFhJH5HioF689ag11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bDdIiK/btq4diJPyte/vsSGbhFhJH5HioF689ag11/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bDdIiK/btq4diJPyte/vsSGbhFhJH5HioF689ag11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbDdIiK%2Fbtq4diJPyte%2FvsSGbhFhJH5HioF689ag11%2Fimg.png&quot; width=&quot;412&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;3.&lt;/b&gt; JDBC URL이 &quot;jdbc:h2:~/{스키마}&quot; 형식으로 세팅되어 있는데 이 상태에서 스키마 명을 수정하고 [연결]버튼을 누른다.&lt;/p&gt;
&lt;p&gt;그러면 pc에 &lt;b&gt;~/{스키마}.mv.db&lt;/b&gt; 형식의 파일이 생성된다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4.&lt;/b&gt; 이후 콘솔에서 JDBC URL을 &quot;&lt;span style=&quot;color: #333333;&quot;&gt;jdbc:h2:tcp://localhost/~/{스키마}&lt;/span&gt;&quot;로 수정하고 연결을 하면 DB에 접속이 되고 JPA셋팅 시 해당 URL을 세팅해서 사용하면 된다.&lt;/p&gt;
&lt;p&gt;* 접속 전 콘솔 모습&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;486&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cnI24r/btq4btZ2j9a/po2rfSTM0bSVVe9E6rJII1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cnI24r/btq4btZ2j9a/po2rfSTM0bSVVe9E6rJII1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cnI24r/btq4btZ2j9a/po2rfSTM0bSVVe9E6rJII1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcnI24r%2Fbtq4btZ2j9a%2Fpo2rfSTM0bSVVe9E6rJII1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;486&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;* 콘솔에서 DB 접속한 뒤 화면&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;598&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ddVCVu/btq4ct579Zo/Rh4mFael1chBMHb01tsOk0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ddVCVu/btq4ct579Zo/Rh4mFael1chBMHb01tsOk0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ddVCVu/btq4ct579Zo/Rh4mFael1chBMHb01tsOk0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FddVCVu%2Fbtq4ct579Zo%2FRh4mFael1chBMHb01tsOk0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;598&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;* 프로젝트에서 JPA 설정.&lt;/p&gt;
&lt;pre id=&quot;code_1620202418357&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;property name=&quot;javax.persistence.jdbc.url&quot; value=&quot;jdbc:h2:tcp://localhost/~/{스키마명}}&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;** 새로운 스키마로 시작하고 싶은 경우 다른 이름의 스키마로 1번부터 시작하거나 3번의 파일을 삭제한 뒤 다시 1번부터 시작을 한다.&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/JPA</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/215</guid>
      <comments>https://hilu0318.tistory.com/215#entry215comment</comments>
      <pubDate>Wed, 5 May 2021 17:21:05 +0900</pubDate>
    </item>
    <item>
      <title>스키마 생성 및 관리.</title>
      <link>https://hilu0318.tistory.com/200</link>
      <description>&lt;p&gt;1. 스키마 조회(root 외 사용자는 자신에게 속한 스키마만 조회)&lt;/p&gt;
&lt;pre id=&quot;code_1614270338953&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt;&amp;nbsp;show&amp;nbsp;databases;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. 스키마 생성&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614270349871&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; create database 스키마명 default character set utf8;
mysql&amp;gt; create schema 스키마명 default character set utf8;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&lt;span&gt;3. 스키마 삭제&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1614270359070&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql&amp;gt; drop database 스키마명;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT(Old)/MySQL 공부</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/200</guid>
      <comments>https://hilu0318.tistory.com/200#entry200comment</comments>
      <pubDate>Fri, 26 Feb 2021 01:26:30 +0900</pubDate>
    </item>
    <item>
      <title>JAVA, Node.js - 배치관리 사이트 만들어보자(0)</title>
      <link>https://hilu0318.tistory.com/198</link>
      <description>&lt;p&gt;배치 이력, 로그 조회 사이트를 만들려고 한다.(추후에는 배치 스케줄도 관리하는 버전으로 업그레이드 할 계획)&lt;/p&gt;
&lt;p&gt;사이트 서버는 &lt;span style=&quot;color: #333333;&quot;&gt;NAS 안에 Dokcer에 설치된 Ubuntu에 올려야 하고, 실제 배치 프로그램 및 로그, crontab파일은 NAS에 설치된 Linux에 존재한다. 아.....그러니까 NAS에 설치된 Docker 안에 설치된 Ubuntu에서 위에위에 존재하는 NAS파일에 접근을 해야 하는 것이다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;음.....이걸 어떻게 처리해야하나 고민을 좀 했는데, 이왕 이런 환경인거 NAS에 있는 배치관련 파일에 접근해서 해당 정보를 전송하는 간단한 API를 Node.js로 NAS에 만들어 두고 Ubuntu안에 톰캣에서 API통신으로 필요한 정보를 받아오는걸로 하기로 했다. 차라리 파일접근 API와 서비스로직을 분리하게 되는 모양이 되어서 API개발 연습도 해볼 겸 괜찮을 것 같다는 생각이 들었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;우선, 외부IP로 접근할 이유는 없어보였기에 내부IP로 NAS에 실행중인 Node.js서버에 접속이 되는지 확인을 했는데 잘 된다. Ubuntu에서도 잘 되는지는 차후에 다시 테스트 해보기로 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;사이트 구성&lt;/h4&gt;
&lt;p&gt;사이트 구성은 아주 간단하게 로그인 페이지와 현황페이지, 에러페이지 이렇게 딱 3개 페이지 정도로만 구성할 예정이다.(이마저도 매우 투박하고 촌스러울것 같다. UI에 시간빼앗기기 싫어...;;;)&lt;/p&gt;
&lt;p&gt;기능은 관리자 로그인 시 현황조회 및 로그파일 관리(삭제)기능을 부여할 것이고 (스케줄 편집과 같은 기능은 추후에 업데이트 할 예정) 게스트로 들어왔을 경우 배치 현황, 로그확인 정도만 가능하도록 할 것이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;API 구성&lt;/h4&gt;
&lt;p&gt;NAS쪽 API는 파일목록 조회(파일명 리스트 조회), 특정 로그파일 내용 조회(파일 내용을 읽어 문자열 전송이 될 것 같다.), 특정 로그파일 삭제 기능을 우선 구현할 예정이다. 파일을 삭제하는 부분에 있어서 사용자 권한 인증을 해야할 것 같은데...요건 추후에 생각을 해보기로 한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;UI쪽은 재능도 없고 손대면 시간대비 결과물이 너무 초라하기에 UI쪽 기술들은 우선 아주 기본적인것들만 가지고 가기로 한다.&lt;/p&gt;
&lt;p&gt;아마 ajax는 사용할 것 같고, 리스트 처리를 위해서 예전에 사용해봤던 Handlebars를 사용할 예정.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Node는 대략 알고만 있지 잘 알지는 못해서 필요한 부분에 대한 공부를 병행하며 만들어야 할 것 같다. 그래도 기본 javascript로 작성하는거라 개발 자체가 어려울 것 같지는 않다. Node.js의 프로젝트 구조나 express프레임워크를 쓰면서 사용하게 될 라이브러리 호출방법, 효과적인 프로젝트 구성 등을 좀 봐야할 것 같다. 구현할 기능 자체가 단순하니 많은 시간이 들어갈 것 같지는 않다는 판단이 Node.js를 선택한 이유이기도 하다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;자, 대략적인 구상은 끝난 듯 하니...그림은 대충 그리고 시작을 해봐야지. 몇일이 걸릴까....글쎄.ㅎㅎㅎ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;ps.&lt;/p&gt;
&lt;p&gt;지금 톰캣 서버는 NAS 안에 Dokcer에 설치된 Ubuntu에 위치하고 있다.&lt;/p&gt;
&lt;p&gt;왜 저곳에 넣었는지 정확히 기억은 안나는데, 일단 NAS에 설치된 Linux 버전이 일반적으로 돌아다니는 버전이 아닌걸로 알고있다. 뭐 패키지 관리 명령어 도구도 (거의)없어서 패키지 하나 설치하는것도 어렵고, 하더라고 복잡한 과정을 거쳐야 하는 것 같았다.(괜히 잘못 설치해서 NAS 설정이 꼬이거나 데이터에 영향이 가면 윽!!!!) Node.js 같은 경우는 시놀로지 관리 프로그램에서 설치할 수 있도록 기능제공을 해주고 있어서 설치할 수 있었다. 그때 같이 설치된 npm으로 이것저것 필요한걸 설치중이긴 하다.(;;;) 무튼, 이런한 이유들로 Ubuntu안에 설치했던것 같은데 정확히 기억은 안난다. 최대한 개발관련된 환경과 NAS환경의 분리 라고나 할까...?ㅎㅎㅎ&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/이것 저것 만들어보자</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/198</guid>
      <comments>https://hilu0318.tistory.com/198#entry198comment</comments>
      <pubDate>Tue, 23 Feb 2021 00:27:53 +0900</pubDate>
    </item>
    <item>
      <title>NAS - 비밀번호 변경 후 SSH 접속 오류.</title>
      <link>https://hilu0318.tistory.com/193</link>
      <description>&lt;p&gt;나의 환경은 Mac + KT공유기 + Synology NAS이다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일단, 한번 튕기면 재접속을 멈추어야한다. (저의 개인 NAS의 설정이 접속오류 3회 이상이면 IP차단되도록 해뒀기에...)&lt;/p&gt;
&lt;p&gt;내가 해놓은 설정을 까먹고 여러번 하면서 IP가 차단되어 버렸다.&lt;/p&gt;
&lt;p&gt;2가지를 기록해둔다.&lt;/p&gt;
&lt;p&gt;1. ip 차단 시 ip차단 해제하기.&lt;/p&gt;
&lt;p&gt;2. ssh 키젠 재설정.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. IP&lt;span style=&quot;color: #333333;&quot;&gt;차단 시 차단 해제하기.&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;우선 내가 차단된 IP를 알아야 하고, 차단해제를 위한 NAS 접속은 다른 인터넷 망을 통해서 접속을 한다. 간단하게 집에 있는 공유기가 아닌 폰의 핫스팟으로 인터넷을 연결해서 접속하면 된다.&lt;/p&gt;
&lt;p&gt;IP주소는 공유기에 들어가서 외부 IP주소를 확인하거나, Synology에서 [제어판&amp;gt;외부 액세스&amp;gt;DDNS 탭]에 보면 보이는 리스트 중 &quot;서비스 공급자&quot;와 &quot;호스트이름&quot;을 확인하고 해당 &quot;외부주소&quot;를 보면 된다.&lt;/p&gt;
&lt;p&gt;그리고 [제어판&amp;gt;보안&amp;gt;계정 탭]에서 [허용/차단목록]을 누르면 팝업이 뜨는데 거기서 [차단목록 탭]을 누르고 위에서 알아낸 IP주소를 검색한 뒤 [제거]버튼을 누른다. 그리고 접속 확인하면 끝.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. ssh 키젠 재설정.&lt;/p&gt;
&lt;p&gt;아래 명령어로 해당 IP에 대한 키잰을 재설정 한다.&lt;/p&gt;
&lt;pre id=&quot;code_1613789726097&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ssh-keygen -R [ IP or DomainName]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위 방법으로도 안된다면 터미널에서 아래 파일을 열어 해당 IP주소 or 도메인에 할당된 키, 값을 삭제한다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613789712280&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ vi /User/사용자/.ssh/known_hosts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 SSH 접속을 시도하면 새로 키젠을 받는과정이 진행되고 정상 접속된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>IT(Old)/Linux 서버관련</category>
      <category>keygen</category>
      <category>NAS</category>
      <category>ssh</category>
      <category>synology</category>
      <category>나스</category>
      <category>비밀번호변경</category>
      <category>시놀로지</category>
      <category>접속오류</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/193</guid>
      <comments>https://hilu0318.tistory.com/193#entry193comment</comments>
      <pubDate>Sat, 20 Feb 2021 12:05:20 +0900</pubDate>
    </item>
    <item>
      <title>JAVA - 백업파일 일괄 수정 배치프로그램 개발(3)</title>
      <link>https://hilu0318.tistory.com/191</link>
      <description>&lt;p&gt;오늘의 작업.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;프로그램 개선.&lt;/li&gt;
&lt;li&gt;쉘 실행환경 설정&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. 프로그램 개선작업 진행.&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;- 어떠한 문제로 파일 목록에 포함되어 프로그램이 읽었으나 .exists() 실행 시 false가 떨어지는 파일들이 존재했다. 이에 대한 예외사항 추가 진행.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 이미지 확장자 추가. iPhone Raw 이미지파일 확장자 DNG 추가.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;- 프로그램 처리 시 로그 추가.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;590&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtAdDr/btqXFgrYGIK/7oYdkGCPkEIqItYZ4EPDA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtAdDr/btqXFgrYGIK/7oYdkGCPkEIqItYZ4EPDA0/img.png&quot; data-alt=&quot;log파일 기록.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtAdDr/btqXFgrYGIK/7oYdkGCPkEIqItYZ4EPDA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtAdDr%2FbtqXFgrYGIK%2F7oYdkGCPkEIqItYZ4EPDA0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;590&quot; height=&quot;NaN&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;log파일 기록.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 쉘 실행환경 설정&lt;/h4&gt;
&lt;p&gt;&amp;nbsp;터미널에서 쉘 스크립트를 실행하면 정상적으로 java를 실행하여 프로그램이 수행된다. 그런데 crontab으로 실행될 때만 꼭 java: command not found 에러가 발생을 한다. 동일한 쉘 스크립트를 수행했는데 왜 java를 인식하지 못할까? 구글링을 좀 해보니 crontab은 PATH를 스케줄 설정 파일 내에 별도로 두고 있었다. 그리고 그 PATH에 있는 경로만 접근 가능한 것 같다. java의 bin 경로가 해당 파일 내에 없어서 생긴 문제다.&lt;/p&gt;
&lt;p&gt;먼저 /usr/local/bin 경로 아래 임의로 심볼릭 링크를 하나 걸어둔다.(혹시 몰라서 심볼릭 링크를 만들어서 그 경로를 crontab에 추가했다.)&lt;/p&gt;
&lt;pre id=&quot;code_1613574935943&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;$ ln -s /자바폴더경로/bin /usr/local/bin/자바임의폴더명/bin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;blockquote data-ke-style=&quot;style2&quot;&gt;crontab 파일&amp;gt;&lt;br /&gt;MAILTO=&quot;&quot;&lt;br /&gt;PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/syno/sbin:/usr/syno/bin:/usr/local/sbin:/usr/local/bin&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;:/usr/local/bin/자바임의폴더명/bin&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;...&lt;/blockquote&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;저렇게 추가해준다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그러고 실행해보면 빰~ 실행됨.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;자, 우선 전체 파일을 한번 돌려본다.&lt;/p&gt;
&lt;p&gt;약 15초 정도가 걸렸다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;정상 실행되는걸 확인 했으니, 이제 운영을 위해서 매일 새벽 5시에 스케줄을 걸어두었다.&lt;/p&gt;
&lt;p&gt;그리고 로그파일도 날짜별로 생성되도록 수정하였다.&lt;/p&gt;
&lt;blockquote data-ke-size=&quot;size18&quot; data-ke-style=&quot;style2&quot;&gt;backup_photo_rename_$(date '+%Y-%m-%d').log&lt;/blockquote&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;이제, 눈 뜨고 나서 백업해둔 파일도 잘 분류되어 들어갔는지 확인해보면 끝.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;추가적으로 개선해야 할 부분들도 계속 체크하고 리스트업을 해서 수정할 예정이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/이것 저것 만들어보자</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/191</guid>
      <comments>https://hilu0318.tistory.com/191#entry191comment</comments>
      <pubDate>Thu, 18 Feb 2021 00:30:47 +0900</pubDate>
    </item>
    <item>
      <title>JAVA - 백업파일 일괄 수정 배치프로그램 개발(2)</title>
      <link>https://hilu0318.tistory.com/190</link>
      <description>&lt;p&gt;오늘의 작업.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;NAS 환경셋팅.(JAVA 설치 및 환경설정, 폴더 및 파일권한 설정 등)&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;color: #333333;&quot;&gt;crontab 설정.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;jar파일 배포 및 정식 운영 전 실행 테스트.&lt;/li&gt;
&lt;/ol&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;1. NAS 환경셋팅.&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;docker에 우분투를 설치하면서 java와 tomcat을 설치했었지만, NAS에 직접 설치를 진행해 본 적이 없었다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;일단, yum, apt-get, brew, rpm 등등...패키지 매니저가 없었기에 직접 파일을 wget을 통해서 다운받고, gzip을 통해서 .tar파일로 만들고 tar를 통해서 설치를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;다운로드URL은 계속 바뀐다. 다운로드 클릭하고 오라클에 로그인을 하면 파일이 다운로드가 되는데 chrome 개발자도구를 통해서 Network를 확인해보면 잠깐 유효한 URL이 확인 가능하다. 그 URL을 통해서 아래 명령어로 다운로드 및 압축풀기를 진행한다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #9d9d9d;&quot;&gt;&lt;i&gt;(근데 생각해보기에...어차피 받은 파일을 푸는 과정이라면, PC에 받고 NAS로 옮겨도 될거 같다. 나중에 확인해보기로.)&lt;/i&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1613493045129&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//파일 다운로드
$ wget '다운로드URL' -O 다운로드파일명.tar.gz
//ex) wget 'https://download.oracle.com/otn/java/jdk/8u281-b09/89d678f2be164786b292527658ca1605/jdk-8u281-linux-i586.tar.gz?AuthParam=1613491011_05fca647665e0efc194c4247cd64916b' -O jdk-8u281-linux-i586.tar.gz

//파일 풀기
$ gzip -d 다운로드파일명.tar.gz	//.tar 파일로 풀기
$ tar xvf 다운로드파일명.tar	//폴더로 풀기

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;그리고 환경설정을 진행해준다.&lt;/p&gt;
&lt;pre id=&quot;code_1613493512583&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//profile 수정.
$ vi /etc/profile

/* 아래 코드를 파일 제일 아래에 추가.
export JAVA_HOME=위에서_풀린_폴더의_절대경로
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=$CLASSPATH:$JAVA_HOME/jre/lib/ext:$JAVA_HOME/lib/tools.jar
*/

//아래 명령어로 수정된 profile 반영.
$ source /etc/profile

//java, javac 버전 확인
$ java -version
// java version &quot;1.8.0_281&quot;
// Java(TM) SE Runtime Environment (build 1.8.0_281-b09)
// Java HotSpot(TM) Server VM (build 25.281-b09, mixed mode)
$ javac -version
// javac 1.8.0_281&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;저렇게 자바 버전을 확인하게 되면 성공.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;2. crontab 설정.&lt;/span&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;이거는 뭐...스케줄 등록은 문제가 없었는데, 파일을 실행 할 권한이 없던 상태에서 조금 삽질을 했다. 권한문제인줄 모르고 있다가 파일 색이 다른걸 보고 권한을 보니 실행권한이 빠져있었다는...;;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;권한 수정 후 정상적으로 실행되는것 확인하였다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. jar파일 배포 및 정식 운영 전 실행 테스트.&lt;/h4&gt;
&lt;p&gt;그러면, 이제 NAS에 올려둔 jar 파일을 실행해본다.&lt;/p&gt;
&lt;p&gt;테스트 폴더의 내용을 한번 돌려보았다. 그리고 그 결과가 아래처림 수행되었다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignLeft&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;506&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAs238/btqXrCpeJXW/2eAzVzCwMsbgMRSV353Jjk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAs238/btqXrCpeJXW/2eAzVzCwMsbgMRSV353Jjk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAs238/btqXrCpeJXW/2eAzVzCwMsbgMRSV353Jjk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAs238%2FbtqXrCpeJXW%2F2eAzVzCwMsbgMRSV353Jjk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;506&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;/p&gt;
&lt;p&gt;다만, iPhone의 LivePhoto의 확장자를 누락해서 옮겨지지 않았다.&lt;/p&gt;
&lt;p&gt;실제로 대량 파일을 한번 돌려보니 개선사항들이 나타난다. 그것까지 수정/반영해서 내일(오늘...) 배포해서 실제로 운영 하는것을 목표로 잡고 작업을 진행해야 겠다. 끝이 보인다.&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/이것 저것 만들어보자</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/190</guid>
      <comments>https://hilu0318.tistory.com/190#entry190comment</comments>
      <pubDate>Wed, 17 Feb 2021 01:34:54 +0900</pubDate>
    </item>
    <item>
      <title>Crontab - 배치 스케줄 관련 정리.</title>
      <link>https://hilu0318.tistory.com/189</link>
      <description>&lt;p&gt;나의 개발 환경은 Mac, Synology, Ubuntu 이렇게 된다.&lt;/p&gt;
&lt;p&gt;Mac은 내가 사용하는 PC환경에서 필요할 듯 해서 같이 정리해 두고,&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Sysnology는 백업용 NAS이기에 파일 관리를 배치로 정리할 필요가 있다고 느꼈고,&lt;/p&gt;
&lt;p&gt;Ubuntu는 Docker에 올려 서비스 배포 및 테스트 환경이기에 쓸 일이 있을 것 같아 같이 정리해둔다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. Mac&lt;/p&gt;
&lt;pre id=&quot;code_1613495614627&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//&amp;nbsp;1.&amp;nbsp;스케줄&amp;nbsp;등록
$&amp;nbsp;crontab -e

//&amp;nbsp;2.&amp;nbsp;실행&amp;nbsp;목록&amp;nbsp;조회
$ crontab -l

//&amp;nbsp;3.&amp;nbsp;시작/종료/재시작
??&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. Synology&lt;/p&gt;
&lt;pre id=&quot;code_1613485909640&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;// 1. 스케줄 등록
$ vi /etc/crontab

// 2. 실행 목록 조회


// 3. 시작/종료/재시작
$ synoservicectl --start crond
$ synoservicectl --stop crond
$ synoservicectl --restart crond&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;3. Ubuntu&lt;/p&gt;
&lt;pre id=&quot;code_1613486850629&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//&amp;nbsp;1.&amp;nbsp;스케줄&amp;nbsp;등록
$&amp;nbsp;crontab -e

//&amp;nbsp;2.&amp;nbsp;실행&amp;nbsp;목록&amp;nbsp;조회
$ crontab -l

//&amp;nbsp;3.&amp;nbsp;시작/종료/재시작
$&amp;nbsp;sudo service&amp;nbsp;cron start
$&amp;nbsp;sudo service&amp;nbsp;cron stop
$&amp;nbsp;sudo service&amp;nbsp;cron restart&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/Linux (리눅스)</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/189</guid>
      <comments>https://hilu0318.tistory.com/189#entry189comment</comments>
      <pubDate>Wed, 17 Feb 2021 01:17:39 +0900</pubDate>
    </item>
    <item>
      <title>JAVA - 백업파일 일괄 수정 배치프로그램 개발(1)</title>
      <link>https://hilu0318.tistory.com/188</link>
      <description>&lt;p&gt;우선, File, Date와 관련된 유틸을 만들면서 진행하였다.&lt;/p&gt;
&lt;p&gt;큰 구조는 아래와 같이 구성하였다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;FileRename : 파일 명을 일괄 변경하기 위한 클래스.&lt;/p&gt;
&lt;p&gt;FileMove : 파일을 일괄 이동하기 위한 클래스.&lt;/p&gt;
&lt;p&gt;FileInfoInstance : 하나의 File객체에 대해서 상위폴더 경로, 전체경로, 확장자, 파일명, 생성일자 등 새로운 파일명을 만들기 위해 필요한 부가 데이터들을 가져올 수 있도록 구성된 클래스. File 객체를 받아서 초기화된다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;초기화를 통해 &lt;span style=&quot;color: #333333;&quot;&gt;각각의 클래스 &lt;/span&gt;객체를 생성하게 되면, 대상 폴더 정보를 가지고 있다가 대상 타입이 세팅되고, 실제로 처리프로세스를 실행하면 대상폴더에 있는 파일 목록 중 추가한 파일유형들만 리스트로 뽑아서 작업을 진행한다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>개발공부 이야기(New)/이것 저것 만들어보자</category>
      <author>woojang</author>
      <guid isPermaLink="true">https://hilu0318.tistory.com/188</guid>
      <comments>https://hilu0318.tistory.com/188#entry188comment</comments>
      <pubDate>Tue, 16 Feb 2021 00:38:25 +0900</pubDate>
    </item>
  </channel>
</rss>