<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Jun, Log</title>
    <link>https://junlab.tistory.com/</link>
    <description>프로그래밍, 코딩 학습을 위한 기록 저장소입니다.
(파이썬, 자바스크립트, 데이터베이스, 오라클, 오픈소스, 모질라, PostgreSQL)</description>
    <language>ko</language>
    <pubDate>Wed, 12 Aug 2026 08:23:25 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>junngo</managingEditor>
    <image>
      <title>Jun, Log</title>
      <url>https://tistory1.daumcdn.net/tistory/2990003/attach/6232b465a6774a2d863beafb17dd87ff</url>
      <link>https://junlab.tistory.com</link>
    </image>
    <item>
      <title>[Spring Batch] 스프링 배치 로직 담당 processor 학습</title>
      <link>https://junlab.tistory.com/276</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 스프링 배치에서 비즈니스 로직을 담당하고 있는 processor를 학습 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;read 부분은 앞에서의 포스트 부분과 동일합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://junlab.tistory.com/274&quot;&gt;https://junlab.tistory.com/274&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649724173124&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[Spring Batch] 스프링 배치를 활용 하여 파일 읽기 (reader)&quot; data-og-description=&quot;이번 포스트에서는 스프링 배치를 활용하여 파일을 읽어 보겠습니다. 1. sample 파일을 하나 만들어주세요. ID,lastName,firstName,position,birthYear,debutYear AbduKa00,Abdul-Jabbar,Karim,rb,1974,1996 AbduR..&quot; data-og-host=&quot;junlab.tistory.com&quot; data-og-source-url=&quot;https://junlab.tistory.com/274&quot; data-og-url=&quot;https://junlab.tistory.com/274&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/m9yEl/hyN0gHmB5Z/K2VbHKvyPab3K2I64mbmE0/img.png?width=800&amp;amp;height=131&amp;amp;face=0_0_800_131,https://scrap.kakaocdn.net/dn/PjiCQ/hyN0kJLtMe/K2IvlP6NhqQV77YYOXBm21/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/jOyv0/hyN1xAHZos/9HGWqmbfoclwRXlIZB9mq1/img.png?width=800&amp;amp;height=131&amp;amp;face=0_0_800_131&quot;&gt;&lt;a href=&quot;https://junlab.tistory.com/274&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junlab.tistory.com/274&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/m9yEl/hyN0gHmB5Z/K2VbHKvyPab3K2I64mbmE0/img.png?width=800&amp;amp;height=131&amp;amp;face=0_0_800_131,https://scrap.kakaocdn.net/dn/PjiCQ/hyN0kJLtMe/K2IvlP6NhqQV77YYOXBm21/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/jOyv0/hyN1xAHZos/9HGWqmbfoclwRXlIZB9mq1/img.png?width=800&amp;amp;height=131&amp;amp;face=0_0_800_131');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[Spring Batch] 스프링 배치를 활용 하여 파일 읽기 (reader)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;이번 포스트에서는 스프링 배치를 활용하여 파일을 읽어 보겠습니다. 1. sample 파일을 하나 만들어주세요. ID,lastName,firstName,position,birthYear,debutYear AbduKa00,Abdul-Jabbar,Karim,rb,1974,1996 AbduR..&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;junlab.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;processor는 생략이 가능한데, job에 추가를 하도록 하겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. processor 추가&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649724390440&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@JobScope
@Bean
public Step flatFileStep(FlatFileItemReader&amp;lt;PlayerDto&amp;gt; playerFileItemReader,
                         ItemProcessor&amp;lt;PlayerDto, PlayerSalaryDto&amp;gt; playerSalaryItemProcessor
) {
    return stepBuilderFactory.get(&quot;flatFileStep&quot;)
            .&amp;lt;PlayerDto, PlayerSalaryDto&amp;gt;chunk(5)
            .reader(playerFileItemReader)
            .processor(playerSalaryItemProcessor)
            .writer(new ItemWriter&amp;lt;&amp;gt;() {
                @Override
                public void write(List&amp;lt;? extends PlayerSalaryDto&amp;gt; items) throws Exception {
                    items.forEach(System.out::println);
                }
            })
            .build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;playerSalaryItemProcessor는 아직 만들지 않았습니다. 일단은 processor를 추가하였는데요. 읽을 때는 PlayerDto로 읽고, 쓸 때는 PlayerSalaryDto로 쓰게 되겠습니다. 프로세스 단에서 작업을 처리하고 PlayerSalaryDto로 변경을 해주고 write로 넘겨 주시면 되겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. playerSalaryItemProcessor 작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649724696713&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@StepScope
@Bean
public ItemProcessor&amp;lt;PlayerDto, PlayerSalaryDto&amp;gt; playerSalaryItemProcessor(
	PlayerSalaryService playerSalaryService) {
    
    return new ItemProcessor&amp;lt;PlayerDto, PlayerSalaryDto&amp;gt;() {
        @Override
        public PlayerSalaryDto process(PlayerDto item) throws Exception {
            return playerSalaryService.calcSalary(item);
        }
    };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ItemProcessor에서는 ItemProcessor를 반환해주면 되고, ItemReader에서는 ItemReader를 반환 해주시면 되겠습니다. 특정 기능이 추가 되는 내용이 있다면 각각의 스텝 안에서 ItemReader나 ItemProcessor를 구현한 객체를 사용해서 반환해주면 되고요. 스프링 배치는 큰 틀을 익히게 되면 필요로 하는 기능은 문서들을 보고 찾아서 사용을 해주시면 되겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ItemProcessor에서는 연봉을 추가 하였고 서비스단을 만들어서 PlayerSalaryDto를 반환 하도록 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 서비스단 로직 작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649725097572&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Service
public class PlayerSalaryService {

    public PlayerSalaryDto calcSalary(PlayerDto player) {
        int salary = (Year.now().getValue() - player.getBirthYear()) * 1000000;
        return PlayerSalaryDto.of(player, salary);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 로직을 분리 하였습니다. 서비스 로직을 분리 후에 호출은 배치 내의 프로세스에서 호출만 하도록 하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-12 10-00-22.png&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cJKCmK/btry7tWoxnA/YGHTXSKAe2JpJsrwEKuSv1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cJKCmK/btry7tWoxnA/YGHTXSKAe2JpJsrwEKuSv1/img.png&quot; data-alt=&quot;salary(연봉) 추가&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cJKCmK/btry7tWoxnA/YGHTXSKAe2JpJsrwEKuSv1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcJKCmK%2Fbtry7tWoxnA%2FYGHTXSKAe2JpJsrwEKuSv1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1246&quot; height=&quot;224&quot; data-filename=&quot;Screenshot from 2022-04-12 10-00-22.png&quot; data-origin-width=&quot;1246&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;salary(연봉) 추가&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;호출을 하게 되면 연봉 부분이 추가 된 모습을 보실 수 있습니다.&lt;/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;프로세스에는 프로세스를 작성해서 사용할 수도 있지만 adapter를 사용할 수도 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1649725399299&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@StepScope
@Bean
public ItemProcessorAdapter playerSalaryItemProcessorAdapter(
	PlayerSalaryService playerSalaryService) {
    
    ItemProcessorAdapter&amp;lt;PlayerDto, PlayerSalaryDto&amp;gt; adapter = new ItemProcessorAdapter&amp;lt;&amp;gt;();
    adapter.setTargetObject(playerSalaryService);
    adapter.setTargetMethod(&quot;calcSalary&quot;);      // playerSalaryService의 메소드명을 명시
    return adapter;

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Adapter를 사용하면 구현이 되어 있는 서비스 로직을 adapter를 부착 시켜주시고 step에서 호출을 해주시면 되겠습니다.&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>ItemProcessor</category>
      <category>Process</category>
      <category>Spring Batch</category>
      <category>스프링 배치</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/276</guid>
      <comments>https://junlab.tistory.com/276#entry276comment</comments>
      <pubDate>Tue, 12 Apr 2022 10:04:51 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] 스프링 배치를 활용 하여 파일 읽기 (reader)</title>
      <link>https://junlab.tistory.com/274</link>
      <description>&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. sample 파일을 하나 만들어주세요.&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649636973326&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ID,lastName,firstName,position,birthYear,debutYear
AbduKa00,Abdul-Jabbar,Karim,rb,1974,1996
AbduRa00,Abdullah,Rabih,rb,1975,1999
AberWa00,Abercrombie,Walter,rb,1959,1982
AbraDa00,Abramowicz,Danny,wr,1945,1967
AdamBo00,Adams,Bob,te,1946,1969
AdamCh00,Adams,Charlie,wr,1979,2003&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 구성은 csv 형태로 되어 있으며 첫줄 은 제목이 작성이 되어 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 잡을 생성 하겠습니다.&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649637391635&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;

@Bean
public Job flatFileJob(Step flatFileStep) {
    return jobBuilderFactory.get(&quot;flatFileJob&quot;)
            .incrementer(new RunIdIncrementer())
            .start(flatFileStep)
            .build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잡을 만드는 방법은 앞에서의 학습과 동잉ㄹ합니다. 잡 / 스텝 빌더 팩도리를 주입 받고, flatFileJob이라는 잡을 생성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;start 부분에는 스텝을 생성하였는데, 아직 스텝은 만들지 않았으니 스텝을 생성하겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 스텝 코드 작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649637573010&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@JobScope
@Bean
public Step flatFileStep(FlatFileItemReader&amp;lt;PlayerDto&amp;gt; playerFileItemReader) {
    return stepBuilderFactory.get(&quot;flatFileStep&quot;)
            .&amp;lt;PlayerDto, PlayerDto&amp;gt;chunk(5)
            .reader(playerFileItemReader)
            .writer(new ItemWriter&amp;lt;&amp;gt;() {
                @Override
                public void write(List&amp;lt;? extends PlayerDto&amp;gt; items) throws Exception {
                    items.forEach(System.out::println);
                }
            })
            .build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;chunk는 작업을 처리하는 개수입니다. 스텝에서는 chunk단위로 작업을 처리하게 되는데 현재 5개 단위로 작업을 처리 하겠습니다. 즉, 5개 아이템을 읽고, 이렇게 읽은 5개 아이템을 처리 한 다음에 5개 아이템을 기록 하겠습니다. 5개 작업 단위로 커밋이 쳐지는 걸 알 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;lt;PlayerDto, PlyerDto&amp;gt;는&amp;nbsp; PlayerDto 타입으로 읽어 드리고, PlayerDto 타입으로 쓰여지겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;reader()에는 파일을 읽어 들일 수 있는 FlatFileItemReader을 등록 하였고, writer()에는 이렇게 읽은 파일 내용을 콘솔에 출력하는 모습입니다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. playerFileItemReader작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649638780430&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@StepScope
@Bean
public FlatFileItemReader&amp;lt;PlayerDto&amp;gt; playerFileItemReader() {
    return new FlatFileItemReaderBuilder&amp;lt;PlayerDto&amp;gt;()
            .name(&quot;playerFileItemReader&quot;)
            .lineTokenizer(new DelimitedLineTokenizer())
            .linesToSkip(1)
            .fieldSetMapper(new PlayerFieldSetMapper())
            .resource(new FileSystemResource(&quot;player-list.txt&quot;))
            .build();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DelimitedLineTokenizer을 작성하면 디폴트로 콤마로 파일을 나눌 수 있습니다. 첫번째 줄은 제목임으로 스킵을 하고 읽어들인 데이터를 매퍼를 통해서 PlayerDto로 만들게 됩니다.&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;DTO)&lt;/p&gt;
&lt;pre id=&quot;code_1649639442834&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Data
public class PlayerDto {
    private String ID;
    private String lastName;
    private String firstName;
    private String position;
    private int birthYear;
    private int debutYear;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 매퍼 함수 작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1649639309327&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class PlayerFieldSetMapper implements FieldSetMapper&amp;lt;PlayerDto&amp;gt; {
    @Override
    public PlayerDto mapFieldSet(FieldSet fieldSet) throws BindException {
        PlayerDto dto = new PlayerDto();
        dto.setID(fieldSet.readString(0));
        dto.setLastName(fieldSet.readString(1));
        dto.setFirstName(fieldSet.readString(2));
        dto.setPosition(fieldSet.readString(3));
        dto.setBirthYear(fieldSet.readInt(4));
        dto.setDebutYear(fieldSet.readInt(5));

        return dto;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;읽어들인 파일 내용을 객체로 변경하기 위해서 FieldSetMapper를 구현한 매퍼를 작성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-11 10-12-06.png&quot; data-origin-width=&quot;1480&quot; data-origin-height=&quot;244&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Gq5BP/btryYnB0fNj/1PjyOQSmB7Ajko1CHIz1X1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Gq5BP/btryYnB0fNj/1PjyOQSmB7Ajko1CHIz1X1/img.png&quot; data-alt=&quot;스프링 배치 파일 읽기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Gq5BP/btryYnB0fNj/1PjyOQSmB7Ajko1CHIz1X1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FGq5BP%2FbtryYnB0fNj%2F1PjyOQSmB7Ajko1CHIz1X1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1480&quot; height=&quot;244&quot; data-filename=&quot;Screenshot from 2022-04-11 10-12-06.png&quot; data-origin-width=&quot;1480&quot; data-origin-height=&quot;244&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;스프링 배치 파일 읽기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스프링 배치를 사용하지 않고 파일을 읽어들이는 것은 A부터 Z까지 개발을 해야 되지만, 스프링 배치를 사용하면 주어진 기능을 사용하면 되겠습니다. 또한 형식이 정형화가 되어 있기 때문에 장기적으로 본다면 유지보수에도 유리 하겠습니다.&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;a href=&quot;https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#flatFileItemReader&quot;&gt;https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#flatFileItemReader&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1649638874904&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;website&quot; data-og-title=&quot;ItemReaders and ItemWriters&quot; data-og-description=&quot;So far, only delimited files have been discussed in much detail. However, they represent only half of the file reading picture. Many organizations that use flat files use fixed length formats. An example fixed length file follows: The following example sho&quot; data-og-host=&quot;docs.spring.io&quot; data-og-source-url=&quot;https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#flatFileItemReader&quot; data-og-url=&quot;https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#flatFileItemReader&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/ccNTS8/hyN0jXknUV/35wUqeKjxoYKtXnqptkttk/img.png?width=726&amp;amp;height=507&amp;amp;face=0_0_726_507,https://scrap.kakaocdn.net/dn/4wVyF/hyN0hFcKXt/W5SJGknzXpgtJJ7eFiBOcK/img.png?width=642&amp;amp;height=491&amp;amp;face=0_0_642_491,https://scrap.kakaocdn.net/dn/l9k6F/hyN0j34Fkv/u7FOZCsXTh2jbrF0uttq60/img.png?width=642&amp;amp;height=491&amp;amp;face=0_0_642_491&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#flatFileItemReader&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://docs.spring.io/spring-batch/docs/current/reference/html/readersAndWriters.html#flatFileItemReader&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/ccNTS8/hyN0jXknUV/35wUqeKjxoYKtXnqptkttk/img.png?width=726&amp;amp;height=507&amp;amp;face=0_0_726_507,https://scrap.kakaocdn.net/dn/4wVyF/hyN0hFcKXt/W5SJGknzXpgtJJ7eFiBOcK/img.png?width=642&amp;amp;height=491&amp;amp;face=0_0_642_491,https://scrap.kakaocdn.net/dn/l9k6F/hyN0j34Fkv/u7FOZCsXTh2jbrF0uttq60/img.png?width=642&amp;amp;height=491&amp;amp;face=0_0_642_491');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;ItemReaders and ItemWriters&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;So far, only delimited files have been discussed in much detail. However, they represent only half of the file reading picture. Many organizations that use flat files use fixed length formats. An example fixed length file follows: The following example sho&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;docs.spring.io&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>Reader</category>
      <category>Spring Batch</category>
      <category>스프링 배치</category>
      <category>예제</category>
      <category>튜토리얼</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/274</guid>
      <comments>https://junlab.tistory.com/274#entry274comment</comments>
      <pubDate>Mon, 11 Apr 2022 10:13:50 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] job, step 작업 전-후 확인을 위한 listener(리스너)</title>
      <link>https://junlab.tistory.com/273</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 스프링 배치(spring batch)의 job 과 step이 실행 되었을 때, 상태 확인 및 무언가 작업을 추가하기 위한 리스너 사용법을 학습하겠습니다.&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;잡 리스너는 JobExecutionListener를 반환하는 메소드를 만들고 Job에 listener로 등록을 해주시면 되는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아래 코드를 보도록 하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1649295646549&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Bean
public Job advancedJob(JobExecutionListener jobExecutionListener,
                       Step advancedStep) {
    return jobBuilderFactory.get(&quot;advancedJob&quot;)
            .incrementer(new RunIdIncrementer())
            .validator(new LocalDateParameterValidator(&quot;targetDate&quot;))
            .listener(jobExecutionListener)
            .start(advancedStep)
            .build();
}

@JobScope
@Bean
public JobExecutionListener jobExecutionListener() {
    return new JobExecutionListener() {
        @Override
        public void beforeJob(JobExecution jobExecution) {
            log.info(&quot;[JobExecutionListener#beforeJob] jobExecution is &quot; + jobExecution.getStatus());
        }

        @Override
        public void afterJob(JobExecution jobExecution) {
            if (jobExecution.getStatus() == BatchStatus.FAILED) {
                log.error(&quot;[JobExecutionListener#afterJob] jobExecution is &quot; + jobExecution.getStatus());
            }

            log.info(&quot;[JobExecutionListener#afterJob] jobExecution is &quot; + jobExecution.getStatus());
        }
    };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;jobExecutionListener() 메소드를 만들고 JobExecutionListener를 반환합니다. 리스너를 통해서 필요로 하는 작업을 구현 해주셔야 되는데요. job이 실행되기 전에는 beforeJob이 실행이 되고 job이 끝난 이후에는 aftetJob이 실행이 되겠습니다.&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;step의 작업의 리스턴도 job과 유사합니다.&lt;/p&gt;
&lt;pre id=&quot;code_1649296744512&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@JobScope
@Bean
public Step advancedStep(StepExecutionListener stepExecutionListener,
                         Tasklet advancedTasklet) {
    return stepBuilderFactory.get(&quot;advancedStep&quot;)
            .listener(stepExecutionListener)
            .tasklet(advancedTasklet)
            .build();
}

@StepScope
@Bean
public StepExecutionListener stepExecutionListener() {
    return new StepExecutionListener() {
        @Override
        public void beforeStep(StepExecution stepExecution) {
            log.info(&quot;[StepExecutionListener#beforeStep] stepExecution is &quot; + stepExecution.getStatus());
        }

        @Override
        public ExitStatus afterStep(StepExecution stepExecution) {
            log.info(&quot;[StepExecutionListener#afterStep] stepExecution is &quot; + stepExecution.getStatus());
            return stepExecution.getExitStatus();
        }
    };
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;StepExecutionListener를 반환하하는 메소드를 만들고 step설정에 listener를 등록 해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-07 11-00-54.png&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;289&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UFoX3/btryzC7Ivvv/66Wpi7kNoRPCwjfBbN8uw1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UFoX3/btryzC7Ivvv/66Wpi7kNoRPCwjfBbN8uw1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UFoX3/btryzC7Ivvv/66Wpi7kNoRPCwjfBbN8uw1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUFoX3%2FbtryzC7Ivvv%2F66Wpi7kNoRPCwjfBbN8uw1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1037&quot; height=&quot;289&quot; data-filename=&quot;Screenshot from 2022-04-07 11-00-54.png&quot; data-origin-width=&quot;1037&quot; data-origin-height=&quot;289&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;#beforeJog이 실행이 되고 step 작업 후에 마지막으로 #afterJob이 실행이 되는 모습을 보실 수 있겠습니다.&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>Job</category>
      <category>listener</category>
      <category>Spring Batch</category>
      <category>STEP</category>
      <category>리스너</category>
      <category>스프링 배치</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/273</guid>
      <comments>https://junlab.tistory.com/273#entry273comment</comments>
      <pubDate>Thu, 7 Apr 2022 11:03:23 +0900</pubDate>
    </item>
    <item>
      <title>[css] css의 단위 (px, %, em, rem, vw, vh)</title>
      <link>https://junlab.tistory.com/272</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;간략하게 css의 단위에 대해서 정리를 하겠습니다.&lt;/h3&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;b&gt;px&lt;/b&gt;: 픽셀이라고 부릅니다. 보통 화면의 크기는 1920 * 1080을 많이 사용하는데 px은 가로 1920개의 px이 있고&amp;nbsp; 세로는 1080개의 px이 있겠습니다. 즉, 하나의 점을 의미합니다.&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;b&gt;%&lt;/b&gt;: &lt;b&gt;상대적으로&lt;/b&gt; 나타내는 백분율을 나타냅니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;em&lt;/b&gt;: 요소의 글꼴의 크기(font-size)가 되겠습니다. 글씨 크기가 10px이면 1em은 10px을 의미하겠습니다.&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;b&gt;rem&lt;/b&gt;: r의 의미는 루트인 최상위 글씨 크기를 의미하겠습니다.&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;b&gt;vw&lt;/b&gt;: 뷰포트의 세로 너비의 백분율을 의미 합니다. 뷰포트라 함은 브라우저, 즉 페이지 전체를 의미하겠습니다. 1vw라 함은 가로 너비의 백분의 1만큼의 너비입니다. 50vw를 주면 부모가 어떻든지 간에 절반을 차지하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;665&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dDKOMK/btrywXwNgF6/QRCGPiXVrJkanuJ0OYNXVK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dDKOMK/btrywXwNgF6/QRCGPiXVrJkanuJ0OYNXVK/img.png&quot; data-alt=&quot;50vw 값&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dDKOMK/btrywXwNgF6/QRCGPiXVrJkanuJ0OYNXVK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdDKOMK%2FbtrywXwNgF6%2FQRCGPiXVrJkanuJ0OYNXVK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;542&quot; height=&quot;320&quot; data-origin-width=&quot;1126&quot; data-origin-height=&quot;665&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;50vw 값&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;vh&lt;/b&gt;: vw와 내용은 동일하며 세로 너비를 의미합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;codepen&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;WNdMwdX&quot; data-user=&quot;junngo&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/junngo/pen/WNdMwdX&quot;&gt; 단위&lt;/a&gt; by Myeongjun Go (&lt;a href=&quot;https://codepen.io/junngo&quot;&gt;@junngo&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script src=&quot;https://cpwebassets.codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;</description>
      <category>Programming/HTML, CSS</category>
      <category>css</category>
      <category>PX</category>
      <category>VH</category>
      <category>vw</category>
      <category>단위</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/272</guid>
      <comments>https://junlab.tistory.com/272#entry272comment</comments>
      <pubDate>Tue, 5 Apr 2022 22:57:52 +0900</pubDate>
    </item>
    <item>
      <title>[VSCode] 우분투에서 한글 입력이 정상적이지 않을 때 (받침 문제)</title>
      <link>https://junlab.tistory.com/271</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;안녕하세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;VSCode를 우분투 환경에서 사용을 하고 있는데요. 글자 입력은 되는데 특정 글자들이 톡톡 안되는 문제가 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;예를 들면 다음과 같은 문제입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-05 16-40-16.png&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kQ8UD/btrywxdrtzL/HQUj1q0vlbz5ngWSKbegQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kQ8UD/btrywxdrtzL/HQUj1q0vlbz5ngWSKbegQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kQ8UD/btrywxdrtzL/HQUj1q0vlbz5ngWSKbegQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkQ8UD%2FbtrywxdrtzL%2FHQUj1q0vlbz5ngWSKbegQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;254&quot; height=&quot;61&quot; data-filename=&quot;Screenshot from 2022-04-05 16-40-16.png&quot; data-origin-width=&quot;254&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;같이 코딩해요를 입력하면 &quot;같&quot; 이라는 글자는 &quot;가ㅌ&quot;로 입력되는 문제가 있습니다.&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;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1.&amp;nbsp; Crtl + Shift + p를 누른신 다음에 setting을 입력하고 세팅 화면으로가주세요.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-05 16-46-26.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;233&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Cjpq3/btryyf3UK99/yk0ThV7M5bMsKNc43SOAC0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Cjpq3/btryyf3UK99/yk0ThV7M5bMsKNc43SOAC0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Cjpq3/btryyf3UK99/yk0ThV7M5bMsKNc43SOAC0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCjpq3%2Fbtryyf3UK99%2Fyk0ThV7M5bMsKNc43SOAC0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;640&quot; height=&quot;233&quot; data-filename=&quot;Screenshot from 2022-04-05 16-46-26.png&quot; data-origin-width=&quot;640&quot; data-origin-height=&quot;233&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 세팅 화면에서 font family를 입력해주세요.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-05 16-47-23.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;189&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/m7wW5/btryt437Jlz/Ghyy4RXWf5IRd8Zwk1UJoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/m7wW5/btryt437Jlz/Ghyy4RXWf5IRd8Zwk1UJoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/m7wW5/btryt437Jlz/Ghyy4RXWf5IRd8Zwk1UJoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fm7wW5%2Fbtryt437Jlz%2FGhyy4RXWf5IRd8Zwk1UJoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;733&quot; height=&quot;189&quot; data-filename=&quot;Screenshot from 2022-04-05 16-47-23.png&quot; data-origin-width=&quot;733&quot; data-origin-height=&quot;189&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 그리고 'Droid Sans Fallback' 을 제거 해주시면 되겠습니다.&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-05 16-48-19.png&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;194&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/VV0Er/btryx3WJfZV/R767gNcgRQcFwOLd6aRm40/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/VV0Er/btryx3WJfZV/R767gNcgRQcFwOLd6aRm40/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/VV0Er/btryx3WJfZV/R767gNcgRQcFwOLd6aRm40/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVV0Er%2Fbtryx3WJfZV%2FR767gNcgRQcFwOLd6aRm40%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;723&quot; height=&quot;194&quot; data-filename=&quot;Screenshot from 2022-04-05 16-48-19.png&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;194&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 나면 정상적으로 한글 입력이 되겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;감사합니다 :)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-05 16-49-02.png&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;59&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dU54Td/btryxbBcNR1/tN9Lv2A2Tie1KMq7MngbV0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dU54Td/btryxbBcNR1/tN9Lv2A2Tie1KMq7MngbV0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dU54Td/btryxbBcNR1/tN9Lv2A2Tie1KMq7MngbV0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdU54Td%2FbtryxbBcNR1%2FtN9Lv2A2Tie1KMq7MngbV0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;228&quot; height=&quot;59&quot; data-filename=&quot;Screenshot from 2022-04-05 16-49-02.png&quot; data-origin-width=&quot;228&quot; data-origin-height=&quot;59&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Tools</category>
      <category>vsC</category>
      <category>vscode</category>
      <category>리눅스</category>
      <category>받침</category>
      <category>우분투</category>
      <category>폰트</category>
      <category>한글 깨짐</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/271</guid>
      <comments>https://junlab.tistory.com/271#entry271comment</comments>
      <pubDate>Tue, 5 Apr 2022 16:49:52 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] 스프링 배치 파라미터 입력 및 검증</title>
      <link>https://junlab.tistory.com/270</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 스프링 배치 구동 시 파라미터 입력과 파라미터 검증을 위한 validator를 학습 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에서의 학습으로 인해서 조금 더 수월한 학습을 진행하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;job, step 그리고 tasklet을 활용하여 만든 배치를 살펴 보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;private final JobBuilderFactory jobBuilderFactory;
private final StepBuilderFactory stepBuilderFactory;

@Bean
public Job advancedJob(Step advancedStep) {
    return jobBuilderFactory.get(&quot;advancedJob&quot;)
            .incrementer(new RunIdIncrementer())
            //.validator(new LocalDateParameterValidator(&quot;targetDate&quot;))
            .start(advancedStep)
            .build();
}

@JobScope
@Bean
public Step advancedStep(Tasklet advancedTasklet) {
    return stepBuilderFactory.get(&quot;advancedStep&quot;)
            .tasklet(advancedTasklet)
            .build();
}

@StepScope
@Bean
public Tasklet advancedTasklet(
		@Value(&quot;#{jobParameters['targetDate']}&quot;) String targetDate) {
        
    return (contribution, chunkContext) -&amp;gt; {
        log.info(&quot;[AdvancedJobConfig] targetDate = &quot; + targetDate);
        log.info(&quot;[AdvancedJobConfig] excuted advancedTasklet&quot;);
        
        return RepeatStatus.FINISHED;
    };

}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;작업 내용이 없는 job으로써 배치가 수행만 되겠습니다. 그리고 tasklet에 보면 targetDate라는 파라미터를 입력 받는데요. 파라미터 추가를 위해서는 배치 작업 실행 시 다음 예시 처럼 파라미터를 추가를 해주시면 되겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1649119968638&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;--spring.batch.job.names=advancedJob -targetDate=2022-02-07&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;targetDate라는 파라미터를 추가를 해주었습니다. 실행을 하면 스텝 내에서 파라미터 값을 받아 오신걸 확인 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-05 09-53-41.png&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;121&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/va1Lz/btryrXwDt3J/nQZj0ZLKwoAb4YkOksD3mK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/va1Lz/btryrXwDt3J/nQZj0ZLKwoAb4YkOksD3mK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/va1Lz/btryrXwDt3J/nQZj0ZLKwoAb4YkOksD3mK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fva1Lz%2FbtryrXwDt3J%2FnQZj0ZLKwoAb4YkOksD3mK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;478&quot; height=&quot;121&quot; data-filename=&quot;Screenshot from 2022-04-05 09-53-41.png&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;121&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로 파라미터 검증을 위한 validator을 만들어 보겠습니다.&lt;/p&gt;
&lt;pre class=&quot;java&quot; data-ke-language=&quot;java&quot;&gt;&lt;code&gt;public class LocalDateParameterValidator implements JobParametersValidator {

    private String parameterName;

    @Override
    public void validate(JobParameters parameters) throws JobParametersInvalidException {
        String localDate = parameters.getString(parameterName);

        if (!StringUtils.hasText(localDate)) {
            throw new JobParametersInvalidException(parameterName + &quot;가 빈 문자열이거나 존재하지 않습니다.&quot;);
        }

        try {
            LocalDate.parse(localDate);
        } catch (DateTimeParseException e) {
            throw new JobParametersInvalidException(parameterName + &quot;가 날짜 형식의 문자열이 아닙니다.&quot;);
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;validator을 활용하면 step 단계에서 파라미터를 검증 하는 것이 아닌, job 단계에서 배치 수행 전에 검증을 할 수 있습니다. 검증 작업은 빠른면 빠를 수록 좋겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobParametersValidator를 구현 해주시면 되겠습니다. 파라미터를 받고 파라미터의 대한 검증 코드를 작성해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그리고 Job 메서드에 validator을 등록해주시면 되겠습니다. 첫번째 코드에서는 validator 주석을 풀어주세요 :)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-05 10-02-49.png&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;61&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2F51Z/btryrWRZJIx/rxWI1fJCFPdzGpFjwhJRrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2F51Z/btryrWRZJIx/rxWI1fJCFPdzGpFjwhJRrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2F51Z/btryrWRZJIx/rxWI1fJCFPdzGpFjwhJRrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2F51Z%2FbtryrWRZJIx%2FrxWI1fJCFPdzGpFjwhJRrk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;630&quot; height=&quot;61&quot; data-filename=&quot;Screenshot from 2022-04-05 10-02-49.png&quot; data-origin-width=&quot;630&quot; data-origin-height=&quot;61&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잘못된 파라미터가 들어오면 위와 같은 예외가 발생하겠습니다.&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>JobParametersValidator</category>
      <category>Spring Batch</category>
      <category>Validator</category>
      <category>검증</category>
      <category>스프링 배치</category>
      <category>파라미터</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/270</guid>
      <comments>https://junlab.tistory.com/270#entry270comment</comments>
      <pubDate>Tue, 5 Apr 2022 10:03:57 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] 스프링 배치 테스트 코드 작성</title>
      <link>https://junlab.tistory.com/269</link>
      <description>&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;h4 data-ke-size=&quot;size20&quot;&gt;1. 테스트 환경은 h2 데이터베이스를 사용하기 위해서 &lt;b&gt;application.yml 파일 내용을 추가&lt;/b&gt;해주세요.&lt;/h4&gt;
&lt;pre id=&quot;code_1648774726852&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  config:
    activate:
      on-profile: test
  jpa:
    database: h2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테스트 코드에서 @ActiveProfiles(&quot;test&quot;) 어노테이션을 통해서 테스트 환경을 구성하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 테스트 내에서도 Batch 구동을 위해 &lt;b&gt;Config 파일&lt;/b&gt;을 만들었습니다.&lt;/h4&gt;
&lt;pre id=&quot;code_1648774837897&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@EnableBatchProcessing
@EnableAutoConfiguration
public class BatchTestConfig {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;test 코드 내에 위의 코드를 작성해주세요. 배치 작업을 위한 설정 어노테이션을 작성하였습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. &lt;b&gt;테스트 코드&lt;/b&gt; 작성&lt;/h4&gt;
&lt;pre id=&quot;code_1648774970173&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@SpringBatchTest    // JobLauncherTestUtils 사용을 위해서 필수
@SpringBootTest
@ExtendWith(SpringExtension.class)
@ActiveProfiles(&quot;test&quot;)
@ContextConfiguration(classes = {HelloJobConfig.class, BatchTestConfig.class})
public class HelloJobConfigTest {

    @Autowired
    private JobLauncherTestUtils jobLauncherTestUtils;

    @Test
    public void success() throws Exception {
        // 실행이 잘되는지 확인
        // when
        JobExecution execution = jobLauncherTestUtils.launchJob();

        // then
        Assertions.assertEquals(execution.getExitStatus(), ExitStatus.COMPLETED);
    }
}&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;지금은 HelloJobConfig를 어노테이션에 등록함으로써 HelloJob이 Job으로 등록이 되었습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잡 런쳐는 스프링일 통해서 HelloJob 잡이 등록이 되었는데요. 혹시나 다른 Job도 여기서 한번에 테스트를 하신다고 ContextConfiguration에 여러개의 잡을 등록 하신다면 빈이 여러개 있어 에러가 발생하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-04-01 10-06-23.png&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kNvvb/btrx8MhlxdD/UGZcpmxwV5q4ZKS3k6ePT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kNvvb/btrx8MhlxdD/UGZcpmxwV5q4ZKS3k6ePT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kNvvb/btrx8MhlxdD/UGZcpmxwV5q4ZKS3k6ePT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkNvvb%2Fbtrx8MhlxdD%2FUGZcpmxwV5q4ZKS3k6ePT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1210&quot; height=&quot;260&quot; data-filename=&quot;Screenshot from 2022-04-01 10-06-23.png&quot; data-origin-width=&quot;1210&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>Spring Batch</category>
      <category>스프링 배치</category>
      <category>테스트 코드</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/269</guid>
      <comments>https://junlab.tistory.com/269#entry269comment</comments>
      <pubDate>Fri, 1 Apr 2022 10:07:20 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch]  스프링 배치로 데이터를 읽고 쓰기 예제 (itemXXX 사용)</title>
      <link>https://junlab.tistory.com/268</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;step을 구성하는 요소는 크게 2가지가 있습니다. tasklet 방식과, itemXXX방식을 사용하여 처리하는 방식입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앞에 포스트에서는 tasklet을 사용하여 hello world를 봤습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 ItemReader / ItemProcessor / ItemWriter 을 사용하는 예제를 살펴보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A라는 테이블에서 데이터를 읽어온 후에 B라는 테이블에 데이터를 입력하는 내용입니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 데이터를 읽은 후에 데이터 저장을 할 수 있도록 테이블을 생성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1648690833615&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;-- 데이터를 읽을 타겟 테이블
CREATE TABLE `test`.`plain_text` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `text` VARCHAR(100) NOT NULL,
  PRIMARY KEY (`id`));
  
 -- 읽은 데이터를 저장할 타겟 테이블
  CREATE TABLE `test`.`house_text` (
  `id` INT NOT NULL AUTO_INCREMENT,
  `text` VARCHAR(100) NOT NULL,
  PRIMARY KEY (`id`));

-- 기본 데이터 입력
INSERT INTO `test`.`plain_text` (`text`) VALUES ('hi');
INSERT INTO `test`.`plain_text` (`text`) VALUES ('good');
INSERT INTO `test`.`plain_text` (`text`) VALUES ('good!!');
INSERT INTO `test`.`plain_text` (`text`) VALUES ('bye');
INSERT INTO `test`.`plain_text` (`text`) VALUES ('hehe');
INSERT INTO `test`.`plain_text` (`text`) VALUES ('hello!!');&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;테이블 생성과, 읽어 올 데이터를 생성 하였습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 데이터베이스를 읽을 수 있도록 도메인 및 레파지토리 생성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;도메인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648692842213&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Entity
@Getter
@Setter
@DynamicUpdate
@AllArgsConstructor
@NoArgsConstructor
@Table(name=&quot;plain_text&quot;)
public class PlainText {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;

    @Column(nullable=false)
    private String text;
}&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;&lt;b&gt;레파지토리 생성&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648692868425&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public interface PlainTextRepository extends JpaRepository&amp;lt;PlainText, Integer&amp;gt; {
    Page&amp;lt;PlainText&amp;gt; findBy(Pageable pageable);
}&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;result_text 도메인과 레파지토리도 plain_text와 같이 생성해주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. Job 생성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1648693067305&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@RequiredArgsConstructor
public class PlainTextJobConfig {

    private final JobBuilderFactory jobBuilderFactory;

    private final StepBuilderFactory stepBuilderFactory;

    private final PlainTextRepository plainTextRepository;

    private final ResultTextRepository resultTextRepository;

    @Bean
    public Job plainTextJob(Step plainTextStep) {
        return jobBuilderFactory.get(&quot;plainTextJob&quot;)
                .incrementer(new RunIdIncrementer())
                .start(plainTextStep)
                .build();
    }

    @JobScope
    @Bean
    public Step plainTextStep(
            ItemReader plainTextReader,
            ItemProcessor plainTextProcessor,
            ItemWriter plainTextWriter) {
        return stepBuilderFactory.get(&quot;plainTextStep&quot;)
                .&amp;lt;PlainText, String&amp;gt;chunk(5)
                .reader(plainTextReader)
                .processor(plainTextProcessor)
                .writer(plainTextWriter)
                .build();
    }

    @StepScope
    @Bean
    public RepositoryItemReader&amp;lt;PlainText&amp;gt; plainTextReader() {
        return new RepositoryItemReaderBuilder&amp;lt;PlainText&amp;gt;()
                .name(&quot;plainTextReader&quot;)
                .repository(plainTextRepository)
                .methodName(&quot;findBy&quot;)
                .pageSize(5)
                .arguments(List.of())   // 전달할 파라미터 있으면 리스트로 넘겨주기.
                .sorts(Collections.singletonMap(&quot;id&quot;, Sort.Direction.DESC))
                .build();
    }

    @StepScope
    @Bean
    public ItemProcessor&amp;lt;PlainText, String&amp;gt; plainTextProcessor() {
        return new ItemProcessor&amp;lt;PlainText, String&amp;gt;() {
            @Override
            public String process(PlainText item) throws Exception {
                return &quot;processed: &quot; + item.getText();
            }
        };
    }

    @StepScope
    @Bean
    public ItemWriter&amp;lt;String&amp;gt; plainTextWriter() {
        return items -&amp;gt; {
            items.forEach(
            	item -&amp;gt; resultTextRepository.save(new ResultText(null, item))
            );
            System.out.println(&quot;===== chunk is finished ====&quot;);
        };
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Job과 Step을 생성하고, Step에는 ItemReader / ItemProcessor / ItemWriter 을 구현하여 연결 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Job이 실행 되고 -&amp;gt; Step이 실행되면서 ItemReader / ItemProcessor / ItemWriter 구성이 각각 수행이 되겠습니다.&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;b&gt;배치 실행 결과)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-31 11-21-39.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;312&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bqvMfd/btrx07GBt11/hH7Hbm2OXsBhkMLLBSPGa1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bqvMfd/btrx07GBt11/hH7Hbm2OXsBhkMLLBSPGa1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bqvMfd/btrx07GBt11/hH7Hbm2OXsBhkMLLBSPGa1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbqvMfd%2Fbtrx07GBt11%2FhH7Hbm2OXsBhkMLLBSPGa1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1272&quot; height=&quot;312&quot; data-filename=&quot;Screenshot from 2022-03-31 11-21-39.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;312&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Chunk is finished가 2번이 출력된 모습을 보실 수 있습니다. chunk 사이즈를 5로 하였기 때문에 데이터는 5개씩 처리가 되겠습니다. 총 데이터는 6개가 존재합니다. 5개가 처리되고 나머지 1개도 처리가 되기 때문에 wirter는 총 2번이 호출이 되었습니다.&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;b&gt;result_text 실행 결과)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-31 11-19-43.png&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;172&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH4o7Y/btrx3Zt32kA/Eo9QXxoxb0XlbPyA2LSZN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH4o7Y/btrx3Zt32kA/Eo9QXxoxb0XlbPyA2LSZN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH4o7Y/btrx3Zt32kA/Eo9QXxoxb0XlbPyA2LSZN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH4o7Y%2Fbtrx3Zt32kA%2FEo9QXxoxb0XlbPyA2LSZN1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;259&quot; height=&quot;172&quot; data-filename=&quot;Screenshot from 2022-03-31 11-19-43.png&quot; data-origin-width=&quot;259&quot; data-origin-height=&quot;172&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;타겟 테이블에 우리가 원하는 데이터가 입력이 된 모습을 보실 수 있습니다.&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>Spring Batch</category>
      <category>스프링 배치</category>
      <category>예제</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/268</guid>
      <comments>https://junlab.tistory.com/268#entry268comment</comments>
      <pubDate>Thu, 31 Mar 2022 11:03:01 +0900</pubDate>
    </item>
    <item>
      <title>[리액트] react 절대 경로를 위한 NODE_PATH 설정 (및 에러 case)</title>
      <link>https://junlab.tistory.com/267</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;절대 경로 사용을 위해서 루트 경로에 .env 파일을 만들고 NODE_PATH=src 입력을 하였는데 에러가 발생하였습니다. 더이상 이 구문은 지원을 안한다고 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;절대 경로 설정&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. jsconfig.json 파일을 루트 경로에 만들어 주세요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 아래 코드 입력&lt;/p&gt;
&lt;pre id=&quot;code_1648548817456&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;{
    &quot;compilerOptions&quot;: {
        &quot;baseUrl&quot;: &quot;src&quot;
    },
    &quot;include&quot;: [
        &quot;src&quot;
    ]
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-29 19-14-10.png&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;203&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVOyqH/btrxVlROmBV/vBSZpEt2i8GDDbH9ppn8fK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVOyqH/btrxVlROmBV/vBSZpEt2i8GDDbH9ppn8fK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVOyqH/btrxVlROmBV/vBSZpEt2i8GDDbH9ppn8fK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVOyqH%2FbtrxVlROmBV%2FvBSZpEt2i8GDDbH9ppn8fK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;316&quot; height=&quot;203&quot; data-filename=&quot;Screenshot from 2022-03-29 19-14-10.png&quot; data-origin-width=&quot;316&quot; data-origin-height=&quot;203&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 이제 컴포넌트에서 상대 경로가 아닌 절대 경로를 사용해주셔도 되겠습니다.&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;</description>
      <category>Programming/React js</category>
      <category>NODE_PATH</category>
      <category>SRC</category>
      <category>에러</category>
      <category>절대경로</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/267</guid>
      <comments>https://junlab.tistory.com/267#entry267comment</comments>
      <pubDate>Tue, 29 Mar 2022 19:14:52 +0900</pubDate>
    </item>
    <item>
      <title>[자바] java stream(스트림) 필터링(distinct, filter) 및 매핑(map)</title>
      <link>https://junlab.tistory.com/266</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;필터링(distinct, filter)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림 사용시 필터링 방법을 사용하여 데이터를 걸러낼 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1648516388979&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    List&amp;lt;String&amp;gt; names = Arrays.asList(&quot;홍길동&quot;, &quot;신용권&quot;, &quot;감자바&quot;, &quot;신용권&quot;, &quot;신민철&quot;);

    names.stream()
        .distinct()
        .forEach(n-&amp;gt;System.out.println(n));
    System.out.println();

    names.stream()
        .filter(n-&amp;gt;n.startsWith(&quot;신&quot;))
        .forEach(n-&amp;gt;System.out.println(n));
    System.out.println();

    names.stream()
        .distinct()
        .filter(n-&amp;gt;n.startsWith(&quot;신&quot;))
        .forEach(n-&amp;gt;System.out.println(n));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;첫번째는 distinct()함수를 통해서 중복을 제거 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;두번째는 filter() 함수를 통해서 신으로 시작하는 값만 필터링 하였으며, 세번째는 중복을 제거 하고 필터링을 적용 하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-29 10-14-27.png&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;267&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJGXwV/btrxoHWORud/qrTuVIx3AfHirAYOfoeAl0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJGXwV/btrxoHWORud/qrTuVIx3AfHirAYOfoeAl0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJGXwV/btrxoHWORud/qrTuVIx3AfHirAYOfoeAl0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJGXwV%2FbtrxoHWORud%2FqrTuVIx3AfHirAYOfoeAl0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;245&quot; height=&quot;267&quot; data-filename=&quot;Screenshot from 2022-03-29 10-14-27.png&quot; data-origin-width=&quot;245&quot; data-origin-height=&quot;267&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;매핑(map)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;매핑은 스트림의 요소들을 &lt;b&gt;다른 요소로 대체&lt;/b&gt;를 합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;flatMap()&lt;/h4&gt;
&lt;pre id=&quot;code_1648517033221&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    List&amp;lt;String&amp;gt; inputList1 = Arrays.asList(&quot;java8 lambda&quot;, &quot;stream mapping&quot;);

    inputList1.stream()
            .flatMap(data -&amp;gt; Arrays.stream(data.split(&quot; &quot;)))
            .forEach(word -&amp;gt; System.out.println(word));
    System.out.println();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List&amp;lt;String&amp;gt;이 있습니다. List&amp;lt;Sgring&amp;gt;을 flatMap을 활용하여 Stream&amp;lt;String&amp;gt; 요소로 대체를 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Arrays.Stream()을 사용하면 Stream&amp;lt;String&amp;gt;이 만들어지고, 이 값이 flatMap을 통해서 &lt;b&gt;하나의 Stream&amp;lt;String&amp;gt;으로 리턴&lt;/b&gt;이되겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;String 스트림을 다시 forEach를 활용하여 출력하는 모습입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-29 10-27-29.png&quot; data-origin-width=&quot;76&quot; data-origin-height=&quot;100&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/PoTl8/btrxQ4vgqAm/xbj2WvGwNz1yQ7HXDrR77k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/PoTl8/btrxQ4vgqAm/xbj2WvGwNz1yQ7HXDrR77k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/PoTl8/btrxQ4vgqAm/xbj2WvGwNz1yQ7HXDrR77k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FPoTl8%2FbtrxQ4vgqAm%2Fxbj2WvGwNz1yQ7HXDrR77k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;76&quot; height=&quot;100&quot; data-filename=&quot;Screenshot from 2022-03-29 10-27-29.png&quot; data-origin-width=&quot;76&quot; data-origin-height=&quot;100&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;flatMapToInt()&lt;/h4&gt;
&lt;pre id=&quot;code_1648517610064&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    List&amp;lt;String&amp;gt; inputList2 = Arrays.asList(&quot;10, 20, 30&quot;, &quot;40, 50, 60&quot;);

    inputList2.stream()
            .flatMapToInt(data -&amp;gt; {
                String[] strArray = data.split(&quot;,&quot;);
                int[] intArr = new int[strArray.length];
                for (int i = 0; i &amp;lt; strArray.length; i++) {
                    intArr[i] = Integer.parseInt(strArray[i].trim());
                }
                return Arrays.stream(intArr);
            })
            .forEach(number -&amp;gt; System.out.println(number));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;List&amp;lt;String&amp;gt;타입을 flatMapToInt()을 활용하여 int 타입의 스트림으로 변경하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-29 10-39-37.png&quot; data-origin-width=&quot;111&quot; data-origin-height=&quot;147&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cr176s/btrxO9iWjIm/tE8UWvGnKBPSoVh78IiHRk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cr176s/btrxO9iWjIm/tE8UWvGnKBPSoVh78IiHRk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cr176s/btrxO9iWjIm/tE8UWvGnKBPSoVh78IiHRk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcr176s%2FbtrxO9iWjIm%2FtE8UWvGnKBPSoVh78IiHRk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;111&quot; height=&quot;147&quot; data-filename=&quot;Screenshot from 2022-03-29 10-39-37.png&quot; data-origin-width=&quot;111&quot; data-origin-height=&quot;147&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;mapToInt()&lt;/h4&gt;
&lt;pre id=&quot;code_1648518305199&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    List&amp;lt;Student&amp;gt; studentList = Arrays.asList(
        new Student(&quot;홍길동&quot;, 10),
        new Student(&quot;신용권&quot;, 20),
        new Student(&quot;유미선&quot;, 30)
    );

    studentList.stream()
        .mapToInt(Student::getScore)
        .forEach(score-&amp;gt;System.out.println(score));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mapToInt를 활용하여 기존의 List&amp;lt;Student&amp;gt; 리스트를 IntStream으로 만들어 주고 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-29 10-48-42.png&quot; data-origin-width=&quot;74&quot; data-origin-height=&quot;68&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dV48kx/btrxHZhamX7/TRh3nwzf5Q1lQhKipxuhUK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dV48kx/btrxHZhamX7/TRh3nwzf5Q1lQhKipxuhUK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dV48kx/btrxHZhamX7/TRh3nwzf5Q1lQhKipxuhUK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdV48kx%2FbtrxHZhamX7%2FTRh3nwzf5Q1lQhKipxuhUK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;74&quot; height=&quot;68&quot; data-filename=&quot;Screenshot from 2022-03-29 10-48-42.png&quot; data-origin-width=&quot;74&quot; data-origin-height=&quot;68&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;flatMap()과 mapTo()의 차이점은 flatMap은 기존의 요소를 평평하게 펴주는 역할을 합니다. 하지만 mapTo()는 새로운 요소로 만들어 줍니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;asDoubleStream()과 boxed() 메소드&lt;/h4&gt;
&lt;pre id=&quot;code_1648518881017&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public static void main(String[] args) {
    int[] intArray = {1, 2, 3, 4, 5};

    IntStream intStream = Arrays.stream(intArray);
    intStream.asDoubleStream().forEach(d-&amp;gt;System.out.println(d));

    System.out.println();

    intStream = Arrays.stream(intArray);
    intStream.boxed().forEach(obj-&amp;gt;System.out.println(obj.intValue()));
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;asDoubleStream()을 활용하여 int 타입을 double타입의 DoubleStream을 생성하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;boxed() 메소드를 활용하여 Stream&amp;lt;Integer&amp;gt; 타입을 생성.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-29 10-56-34.png&quot; data-origin-width=&quot;113&quot; data-origin-height=&quot;258&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CHUMG/btrxJsi5r53/f9zDtGLLkjJEneaql1iCXk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CHUMG/btrxJsi5r53/f9zDtGLLkjJEneaql1iCXk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CHUMG/btrxJsi5r53/f9zDtGLLkjJEneaql1iCXk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCHUMG%2FbtrxJsi5r53%2Ff9zDtGLLkjJEneaql1iCXk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;113&quot; height=&quot;258&quot; data-filename=&quot;Screenshot from 2022-03-29 10-56-34.png&quot; data-origin-width=&quot;113&quot; data-origin-height=&quot;258&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;참고 책)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 자바다 (신용권의 Java 프로그래밍 정복)&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>java</category>
      <category>stream</category>
      <category>매핑</category>
      <category>스트림</category>
      <category>자바</category>
      <category>필터링</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/266</guid>
      <comments>https://junlab.tistory.com/266#entry266comment</comments>
      <pubDate>Tue, 29 Mar 2022 10:58:00 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] 스프링 배치로 Hello, World 실행하기 예제 (tasklet 사용)</title>
      <link>https://junlab.tistory.com/265</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;Job과 Step의 세부적인 내용을 살펴 보기 전에 스프링 배치를 활용하여 Hello, World 부터 출력을 하겠습니다. 개념도 중요하겠지만 스프링 배치는 코드로 먼저 보는 것이 조금 더 직관적이겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 프로젝트 세팅&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;start.spring.io 사이트트에서 프로젝트 기본 골격을 생성하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-30 19-38-09.png&quot; data-origin-width=&quot;1546&quot; data-origin-height=&quot;751&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/TX0Jq/btrx06fSONY/SzoiekN3MNCmh2BK0KTSNk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/TX0Jq/btrx06fSONY/SzoiekN3MNCmh2BK0KTSNk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/TX0Jq/btrx06fSONY/SzoiekN3MNCmh2BK0KTSNk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTX0Jq%2Fbtrx06fSONY%2FSzoiekN3MNCmh2BK0KTSNk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1546&quot; height=&quot;751&quot; data-filename=&quot;Screenshot from 2022-03-30 19-38-09.png&quot; data-origin-width=&quot;1546&quot; data-origin-height=&quot;751&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 데이터베이스 생성을 위한 docker-compose.yml 파일 생성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1648636823742&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: '3'

services:
  mysql:
    container_name: mysql_batch
    image: mysql/mysql-server:5.7
    environment:
      MYSQL_ROOT_HOST: '%'
      MYSQL_USER: &quot;test&quot;
      MYSQL_PASSWORD: &quot;test&quot;
      MYSQL_DATABASE: &quot;test&quot;
    ports:
      - &quot;3306:3306&quot;
    command:
      - &quot;mysqld&quot;
      - &quot;--character-set-server=utf8mb4&quot;
      - &quot;--collation-server=utf8mb4_unicode_ci&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mysql 구동을 위해서 yml 파일을 만들어주세요.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 설정 요소를 위한 application.yml파일 생성 및 작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1648636928125&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;spring:
  profiles:
    active: local
  batch:
    job:
      names: ${job.name:NONE}

---
spring:
  config:
    activate:
      on-profile: local
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/test
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: test
    password: test
  jpa:
    show-sql: true
    generate-ddl: false
    hibernate:
      ddl-auto: none
  batch:
    jdbc:
      initialize-schema: ALWAYS

---
spring:
  config:
    activate:
      on-profile: test
  jpa:
    database: h2&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;데이터베이스 생성 및 배치 구동시 파라미터 전달을 위한 application.yml파일을 작성하였습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 도커 명령어를 통해서 데이터베이스 구동&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1648637069023&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose up -d&lt;/code&gt;&lt;/pre&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. main 함수에 배치 수행을 위한 어노테이션 추가&lt;/b&gt;&lt;/h4&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-30 19-49-13.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;222&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bJfwhH/btrx0L38zuK/QKtQqHLOlGdCVFRATRyAoK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bJfwhH/btrx0L38zuK/QKtQqHLOlGdCVFRATRyAoK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bJfwhH/btrx0L38zuK/QKtQqHLOlGdCVFRATRyAoK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbJfwhH%2Fbtrx0L38zuK%2FQKtQqHLOlGdCVFRATRyAoK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;649&quot; height=&quot;222&quot; data-filename=&quot;Screenshot from 2022-03-30 19-49-13.png&quot; data-origin-width=&quot;649&quot; data-origin-height=&quot;222&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;EnableBatchProcessing 어노테이션을 추가해주세요. 이후에 구동을 하고 데이터베이스 테이블을 보게 되면 배치 관련 테이블이 자동으로 생성된 모습을 보실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-30 19-50-20.png&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;214&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/L8M2P/btrxY4QU4kh/3FEUFhQudGKx7ytgnUSdyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/L8M2P/btrxY4QU4kh/3FEUFhQudGKx7ytgnUSdyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/L8M2P/btrxY4QU4kh/3FEUFhQudGKx7ytgnUSdyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FL8M2P%2FbtrxY4QU4kh%2F3FEUFhQudGKx7ytgnUSdyK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;308&quot; height=&quot;214&quot; data-filename=&quot;Screenshot from 2022-03-30 19-50-20.png&quot; data-origin-width=&quot;308&quot; data-origin-height=&quot;214&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. job 패키지 생성 및 HelloJobConfig 파일 생성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1648637519302&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;@Configuration
@RequiredArgsConstructor
public class HelloJobConfig {

    private final JobBuilderFactory jobBuilderFactory;

    private final StepBuilderFactory stepBuilderFactory;

    @Bean
    public Job helloJob(Step helloStep) {
        return jobBuilderFactory.get(&quot;helloJob&quot;)
                .incrementer(new RunIdIncrementer())
                .start(helloStep)
                .build();
    }

    @JobScope
    @Bean
    public Step helloStep(Tasklet tasklet) {
        return stepBuilderFactory.get(&quot;helloStep&quot;)
                .tasklet(tasklet)
                .build();
    }

    @StepScope
    @Bean
    public Tasklet tasklet() {
        return (contribution, chunkContext) -&amp;gt; {
            System.out.println(&quot;Hello Spring batch&quot;);
            return RepeatStatus.FINISHED;
        };
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;helloJob이라는 하나의 잡을 생성하고, step을 하나 만들었습니다. step을 구동하기 위해서는 이번 코드에서는 tasklet을 사용하였는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;step을 구성하는 방법은 2가지 있습니다. 하나는 tasklet 방식과 다른 방식은 앞전의 설명을 드린 itemReader / itemProcessor / itemWriter 방식으로 처리하는 방식이 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;간단한 배치 작업은 tasklet 방식을 사용하고 두번째 방법은 차차 살펴 보도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;7. 수행 시 아래의 파라미터를 넘겨주세요.&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1648637633639&quot; class=&quot;bash&quot; data-ke-language=&quot;bash&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;--spring.batch.job.names=helloJob&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-30 19-54-58.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;121&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cPGYnG/btrx0tpaTpa/J78cXlWKCUXTUYzIaW715k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cPGYnG/btrx0tpaTpa/J78cXlWKCUXTUYzIaW715k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cPGYnG/btrx0tpaTpa/J78cXlWKCUXTUYzIaW715k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcPGYnG%2Fbtrx0tpaTpa%2FJ78cXlWKCUXTUYzIaW715k%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1272&quot; height=&quot;121&quot; data-filename=&quot;Screenshot from 2022-03-30 19-54-58.png&quot; data-origin-width=&quot;1272&quot; data-origin-height=&quot;121&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>Hello World</category>
      <category>java</category>
      <category>Spring Batch</category>
      <category>Tasklet</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/265</guid>
      <comments>https://junlab.tistory.com/265#entry265comment</comments>
      <pubDate>Tue, 29 Mar 2022 09:47:24 +0900</pubDate>
    </item>
    <item>
      <title>[자바] java stream(스트림) 파이프라인과 리덕션이란?</title>
      <link>https://junlab.tistory.com/264</link>
      <description>&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;b&gt;소스(컬렉션, 배열, 파일) -&amp;gt; 오리지날 스트림 -&amp;gt; 필터링처리(중간처리) -&amp;gt; 매핑 처리(중간처리)&amp;nbsp; -&amp;gt; 집계처리(최종처리) -&amp;gt; 결과 &lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;순서로 처리가 됩니다. 이런 순서로처리가 되고 난 이후에 &lt;b&gt;대량의 데이터를 가공해서 축소 하는것을 리덕션&lt;/b&gt;이라고 불리겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;샘플)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648449238255&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Member&amp;gt; list = Arrays.asList(
    new Member(&quot;홍길동&quot;, Member.MALE, 30),
    new Member(&quot;김나리&quot;, Member.FEMALE, 20),
    new Member(&quot;신용권&quot;, Member.MALE, 45),
    new Member(&quot;박수미&quot;, Member.FEMALE, 27)
);

double ageAvg = list.stream()
    .filter(m-&amp;gt;m.getSex()==Member.MALE)	// 남자요소
    .mapToInt(Member::getAge)			// 나이요소
    .average()							// 집계처리
    .getAsDouble();						// double 출력을 위한 함수 호출

System.out.println(&quot;남자 평균 나이: &quot; + ageAvg);&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;Member 변수라는 소스(회원 컬렉션, 리스트)가 있고 -&amp;gt; 오리지날 스트림(Member-남/녀) -&amp;gt; 남자요소 (Member-남)(필터링-중간처리) -&amp;gt; 나이 요소(age)(매핑-중간처리) -&amp;gt; 집계처리(average())(최종처리) -&amp;gt; 남자의 평균나이(결과)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;각각의 파이프라인 별로 데이터 처리가 되겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-28 15-35-36.png&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;72&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/oKfQN/btrxILh73EB/mscLujlSShbXs3mw4T7Sb0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/oKfQN/btrxILh73EB/mscLujlSShbXs3mw4T7Sb0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/oKfQN/btrxILh73EB/mscLujlSShbXs3mw4T7Sb0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FoKfQN%2FbtrxILh73EB%2FmscLujlSShbXs3mw4T7Sb0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;313&quot; height=&quot;72&quot; data-filename=&quot;Screenshot from 2022-03-28 15-35-36.png&quot; data-origin-width=&quot;313&quot; data-origin-height=&quot;72&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 내용)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 자바다 (신용권의 Java 프로그래밍 정복)&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>java</category>
      <category>pipline</category>
      <category>stream</category>
      <category>stream pipline</category>
      <category>스트림</category>
      <category>스트림 파이프라인</category>
      <category>자바</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/264</guid>
      <comments>https://junlab.tistory.com/264#entry264comment</comments>
      <pubDate>Mon, 28 Mar 2022 15:37:48 +0900</pubDate>
    </item>
    <item>
      <title>[자바] java  stream(스트림)이란 무엇이고 기본 활용</title>
      <link>https://junlab.tistory.com/263</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;자바 스트림이란 리스트나, 배열 같은 저장 요소를 for(이터레이터)를 사용하지 않고, 람다식이라는 함수적 스타일을 활용해서 데이터 처리를 할 수 있습니다. 이런 이야기만 듣고 보기에는 이해하기 어려우니 코드를 먼저 살펴 보겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;기본 샘플)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1648447281406&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = Arrays.asList(&quot;홍길동&quot;, &quot;신용권&quot;, &quot;감자바&quot;);

// Iterator 이용
Iterator&amp;lt;String&amp;gt; iterator = list.iterator();
while (iterator.hasNext()) {
    String name = iterator.next();
    System.out.println(name);
}

System.out.println();

// Stream 이용
Stream&amp;lt;String&amp;gt; stream = list.stream();
stream.forEach(name -&amp;gt; System.out.println(name));&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Iterator를 사용하면 반복문을 사용하여 하나씩 접근 하였습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;하지만, stream을 활용하면 반복문 없이 리스트 데이터를 처리할 수 있습니다. 위의 내용은 단순히 리스트 출력을 하였는데 아래 코드는 조금더 복작합 작업을 진행합니다.&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;b&gt;샘플2)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648447466572&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;Student&amp;gt; list = Arrays.asList(
    new Student(&quot;홍길동&quot;, 90),
    new Student(&quot;신용권&quot;, 92)
);

Stream&amp;lt;Student&amp;gt; stream = list.stream();
stream.forEach(s -&amp;gt; {
    String name = s.getName();
    int score = s.getScore();
    System.out.println(name + &quot;-&quot; + score);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;list문의 stream을 열어서 s라는 변수의 각각의 객체를 받아서 처리를 진행합니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;스트림의 장점은 병렬 처리를 통해서 더 빠른 처리를 할 수 있습니다. 병렬 처리는 하나의 코어로 처리하는 것이 아닌 다수의 코어로 작업을 나눠서 진행하기 때문에 단순 반복문 처리보다 더 빠른 속도를 낼 수 있습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;샘플3)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1648447662670&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;String&amp;gt; list = Arrays.asList(&quot;홍길동&quot;, &quot;신용권&quot;, &quot;감자바&quot;, &quot;람다식&quot;, &quot;박병렬&quot;);

// 순차 처리
Stream&amp;lt;String&amp;gt; stream = list.stream();
stream.forEach(ParallelExample :: print);

System.out.println();

// 병렬 처리
Stream&amp;lt;String&amp;gt; parallStream = list.parallelStream();
parallStream.forEach(ParallelExample :: print);&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;이점은 주의를 해주셔야 겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-28 15-08-25.png&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;260&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cK9awa/btrxHXQAXyY/bpEbdF0sOk3v6TwpH8az50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cK9awa/btrxHXQAXyY/bpEbdF0sOk3v6TwpH8az50/img.png&quot; data-alt=&quot;순서 보장을 못받음&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cK9awa/btrxHXQAXyY/bpEbdF0sOk3v6TwpH8az50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcK9awa%2FbtrxHXQAXyY%2FbpEbdF0sOk3v6TwpH8az50%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;444&quot; height=&quot;260&quot; data-filename=&quot;Screenshot from 2022-03-28 15-08-25.png&quot; data-origin-width=&quot;444&quot; data-origin-height=&quot;260&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;순서 보장을 못받음&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;코드 내용)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이것이 자바다 (신용권의 Java 프로그래밍 정복)&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>java</category>
      <category>stream</category>
      <category>스트림</category>
      <category>자바</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/263</guid>
      <comments>https://junlab.tistory.com/263#entry263comment</comments>
      <pubDate>Mon, 28 Mar 2022 15:09:09 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] 스프링 배치의 기본 구조 및 큰 그림 그리기</title>
      <link>https://junlab.tistory.com/262</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이번 시간에는 스프링 배치의 기본 구조를 살펴 보면서 큰 그림을 그려 보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;spring-batch-reference-model.png&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;294&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bamtC4/btrxmAwE6L9/HuwPU5AAPbjtuFeHLy9cEK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bamtC4/btrxmAwE6L9/HuwPU5AAPbjtuFeHLy9cEK/img.png&quot; data-alt=&quot;기본 개념&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bamtC4/btrxmAwE6L9/HuwPU5AAPbjtuFeHLy9cEK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbamtC4%2FbtrxmAwE6L9%2FHuwPU5AAPbjtuFeHLy9cEK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;738&quot; height=&quot;294&quot; data-filename=&quot;spring-batch-reference-model.png&quot; data-origin-width=&quot;738&quot; data-origin-height=&quot;294&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;기본 개념&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JobRepository&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;JobRepository는 배치 수행을 위한 데이터 (시작 시간, 종료 시간, 상태, 읽기/쓰기, 회수 등) 및 Job의 상태관리를 담당합니다. JobRepository는 스프링 배치 내의 잡런쳐, 잡, 스탭과 같이 컴포넌트들이 데이터를 공유를 하게 됩니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;JobLauncher&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;잡런처는 잡을 실행해주는 역할을 합니다. 잡이 실행이 되면 JobRepository에는 작업의 따른 데이터들이 갱신이 되겠습니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Job과 Step&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Job은 하나의 배치 작업입니다. 배치 작업을 하나 수행한다고 하면 Job을 수행 하는 개념입니다. 그리고 하나의 Job 안에는 한개의 Step 또는 여러개의 Step이 있을 수 있습니다. Step은 하나의 배치 작업 안에, 여러 단계가 있다면 이걸 나눠 놓은 개념입니다. Step은 ItemReader, ItemProcessor, ItemWriter가 있어서 무언가를 읽고 처리하고 쓰기를 진행하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배치 작업이란게 데이터베이스나 api 또는 파일을 읽는 어떤 읽는 작업을 진행하고, 필요한 내용을 처리하겠습니다. 이후에는 다시 파일이나 데이터베이스 같은 곳에 write 하는 작업을 진행하는데요. 배치 작업은 이런 방법으로 정형화가 되어 있어서 스프링 배치에서도 이런 레이어의 모습을 보이고 있습니다.&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;스프링 배치를 활용하여 개발을 한다면 우리는 Job 과 Step, Step의 있는 ItemReader, ItemProcessor, ItemWriter 항목들을 활용하여 개발을 진행하겠습니다.&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;b&gt;참고 스프링 배치 공식 사이트)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://docs.spring.io/spring-batch/docs/current/reference/html/domain.html#domainLanguageOfBatch&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://docs.spring.io/spring-batch/docs/current/reference/html/domain.html#domainLanguageOfBatch&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>Job</category>
      <category>Spring Batch</category>
      <category>STEP</category>
      <category>스프링 배치</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/262</guid>
      <comments>https://junlab.tistory.com/262#entry262comment</comments>
      <pubDate>Sun, 27 Mar 2022 18:24:02 +0900</pubDate>
    </item>
    <item>
      <title>[리액트] Functions are not valid as a React child 경고(에러)</title>
      <link>https://junlab.tistory.com/261</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;리액트 개발 중에 아래와 같은 경고가 발생 하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-27 11-00-21.png&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;352&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/UoSBT/btrxsDFBz3J/0amqE319NzoQYfIDkOPNR1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/UoSBT/btrxsDFBz3J/0amqE319NzoQYfIDkOPNR1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/UoSBT/btrxsDFBz3J/0amqE319NzoQYfIDkOPNR1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FUoSBT%2FbtrxsDFBz3J%2F0amqE319NzoQYfIDkOPNR1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;716&quot; height=&quot;352&quot; data-filename=&quot;Screenshot from 2022-03-27 11-00-21.png&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;352&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;pre id=&quot;code_1648346531959&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Warning: Functions are not valid as a React child. This may happen if you return a Component instead of &amp;lt;Component /&amp;gt; from render. Or maybe you meant to call this function rather than return it.&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;이유는 컴포넌트 개발 중에 function 컴포넌트에 {}를 사용했기 때문에 발생하였습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-03-27 11-02-55.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;175&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bnV33i/btrxoW6X4M6/4t8nakMuKoJgrmz93crvS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bnV33i/btrxoW6X4M6/4t8nakMuKoJgrmz93crvS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bnV33i/btrxoW6X4M6/4t8nakMuKoJgrmz93crvS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbnV33i%2FbtrxoW6X4M6%2F4t8nakMuKoJgrmz93crvS0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;619&quot; height=&quot;175&quot; data-filename=&quot;Screenshot from 2022-03-27 11-02-55.png&quot; data-origin-width=&quot;619&quot; data-origin-height=&quot;175&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;{}를 제거하시면 해결이 되는데요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;함수형 컴포넌트에서는 {}사용했을 때 경고를 하여 클래스형으로 변경을 해서 사용을 해주실 수도 있습니다.&lt;/p&gt;</description>
      <category>Programming/React js</category>
      <category>React</category>
      <category>리액트</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/261</guid>
      <comments>https://junlab.tistory.com/261#entry261comment</comments>
      <pubDate>Sun, 27 Mar 2022 12:43:22 +0900</pubDate>
    </item>
    <item>
      <title>[css] width와 height의 대해서 알아보자</title>
      <link>https://junlab.tistory.com/260</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;div를 사용하여 기본 샘플을 살펴보자.&lt;/p&gt;
&lt;p class=&quot;codepen&quot; style=&quot;height: 300px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;&quot; data-height=&quot;300&quot; data-default-tab=&quot;html,result&quot; data-slug-hash=&quot;YzYZvMm&quot; data-user=&quot;junngo&quot; data-ke-size=&quot;size16&quot;&gt;&lt;span&gt;See the Pen &lt;a href=&quot;https://codepen.io/junngo/pen/YzYZvMm&quot;&gt; 너비(width, height)&lt;/a&gt; by Myeongjun Go (&lt;a href=&quot;https://codepen.io/junngo&quot;&gt;@junngo&lt;/a&gt;) on &lt;a href=&quot;https://codepen.io&quot;&gt;CodePen&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;
&lt;script src=&quot;https://cpwebassets.codepen.io/assets/embed/ei.js&quot;&gt;&lt;/script&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 보면 div를 선언하고 width와 height가 각각 100px로 설정이 되어있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이 &lt;b&gt;2개의 속성의 기본값은 auto(자동)&lt;/b&gt;이다. 특별히 px같은 값으로 명시를 하지 않는다면 이 2개의 속성은 브라우저가 자동으로 계산해준다. 이 점을 인지하고 있지 못하다면&amp;nbsp; width나 height 속성을 제대로 활용할 수가 없다. 하나 지우면 갑자기 넓어지고, 다른걸 지우면 안나고 하는 현상이 발생하기 때문이다.&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;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;인라인 요소&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적인 인라인 태그인 span 태그를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;width: &lt;b&gt;콘텐츠 크기만큼&lt;/b&gt; 늘려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;height: &lt;b&gt;콘텐츠 크기만큼&lt;/b&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;* 인라인 요소는 width 와 height를 명시해도 효과가 전혀 없다. 인라인은 가로 세로 크기가 명시가 안된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;블록 요소&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;대표적 블록 태그는 div를 살펴보자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;width: 가로 요소를 &lt;b&gt;부모 크기만큼 최대한 늘려&lt;/b&gt;준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;height: 세로 요소를 &lt;b&gt;컨텐츠 크키만큼&lt;/b&gt; 늘려준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세로 요소는 지정된&amp;nbsp; 값이 없고, 콘텐츠도 없다면 하면에 아예 출력이 되지 않는다. 이점에 대해서는 주의가 필요.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추가적 속성 값&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;max-widht / max-height: 기본 값은 none&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;min-widht / min-height: 기본 값은 0&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;776&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c2XLl2/btrxkNbqC9u/TKe7wSXjiocbStUlwOFAA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c2XLl2/btrxkNbqC9u/TKe7wSXjiocbStUlwOFAA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c2XLl2/btrxkNbqC9u/TKe7wSXjiocbStUlwOFAA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc2XLl2%2FbtrxkNbqC9u%2FTKe7wSXjiocbStUlwOFAA0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;593&quot; height=&quot;362&quot; data-origin-width=&quot;1271&quot; data-origin-height=&quot;776&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>Programming/HTML, CSS</category>
      <category>css</category>
      <category>height</category>
      <category>Width</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/260</guid>
      <comments>https://junlab.tistory.com/260#entry260comment</comments>
      <pubDate>Sun, 27 Mar 2022 00:01:11 +0900</pubDate>
    </item>
    <item>
      <title>[Spring Batch] 배치 작업이 필요한 이유?</title>
      <link>https://junlab.tistory.com/258</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;배치 작업은 한국말로 일괄 작업을 뜻합니다. 고객이 송금이나 주문을 하는 작업은 실시간으로 발생이 됩니다. 고객에 입장에서는 모든 작업이 실시간 작업으로 실행될 것으로 판단이 되나, 내부적으로 특정 시간대마다 발생되는 배치 작업이 굉장히 많습니다. 고객은 주문은 하였지만 주문 이후 다음 STEP은(상품 포장, 배송 등)는 배치 작업으로 처리가 될 수도 있습니다. 송금 작업 이후에도 고객의 금액에 대한 집계 작업 또는 후 처리에 대해서는 모두 일괄 작업으로 수행이 될 것입니다.&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;배치작업이 필요한 예시&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;포장, 배송&lt;/li&gt;
&lt;li&gt;송금 작업 후 금액 집계&lt;/li&gt;
&lt;li&gt;이메일 알람&lt;/li&gt;
&lt;li&gt;일/주/월 정산&lt;/li&gt;
&lt;li&gt;주기별로 필요한 크롤링 및 데이터 호출&lt;/li&gt;
&lt;/ul&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;그 중에서 자바와 Spring Batch를 활용하여 배치 학습을 하도록 하겠습니다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;472&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/buMpTK/btrxbOVTQCU/x6bZF65ijkGq1vl3uCO721/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/buMpTK/btrxbOVTQCU/x6bZF65ijkGq1vl3uCO721/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/buMpTK/btrxbOVTQCU/x6bZF65ijkGq1vl3uCO721/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbuMpTK%2FbtrxbOVTQCU%2Fx6bZF65ijkGq1vl3uCO721%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;368&quot; height=&quot;239&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;472&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/Spring Batch</category>
      <category>Spring Batch</category>
      <category>배치작업</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/258</guid>
      <comments>https://junlab.tistory.com/258#entry258comment</comments>
      <pubDate>Fri, 25 Mar 2022 11:21:52 +0900</pubDate>
    </item>
    <item>
      <title>mysql 도커 설치, 접속 및 로그인</title>
      <link>https://junlab.tistory.com/256</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;도커를 통해서 mysql 설치 및 접속 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;1. mysql 설치&lt;/h4&gt;
&lt;pre id=&quot;code_1642173795893&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d -p 3306:3306 --name mysql-container -e MYSQL_ROOT_PASSWORD=q1w2e3r4 mysql:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-01-15 00-23-25.png&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;38&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/eUeVcb/btrqNfRIhgV/HLolhGWx7JKcrSqHIKYDVk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/eUeVcb/btrqNfRIhgV/HLolhGWx7JKcrSqHIKYDVk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/eUeVcb/btrqNfRIhgV/HLolhGWx7JKcrSqHIKYDVk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FeUeVcb%2FbtrqNfRIhgV%2FHLolhGWx7JKcrSqHIKYDVk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;723&quot; height=&quot;38&quot; data-filename=&quot;Screenshot from 2022-01-15 00-23-25.png&quot; data-origin-width=&quot;723&quot; data-origin-height=&quot;38&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-p 3306:3306 : 외부와 도커 내부 3306포트로 연결&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;--name mysql-container : 컨테이너 이름 지정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;2. 도커 접속&lt;/h4&gt;
&lt;pre id=&quot;code_1642173949166&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it mysql-container bash&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;3. 로그인&lt;/h4&gt;
&lt;pre id=&quot;code_1642174002594&quot; class=&quot;shell&quot; data-ke-language=&quot;shell&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;mysql -u root -p;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;입력 및 패스워드 입력&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;Screenshot from 2022-01-15 00-27-13.png&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;269&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NIhjQ/btrqJ6aS5RJ/8lBaA6HH5dAlH8p6KAD1h1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NIhjQ/btrqJ6aS5RJ/8lBaA6HH5dAlH8p6KAD1h1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NIhjQ/btrqJ6aS5RJ/8lBaA6HH5dAlH8p6KAD1h1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNIhjQ%2FbtrqJ6aS5RJ%2F8lBaA6HH5dAlH8p6KAD1h1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;717&quot; height=&quot;269&quot; data-filename=&quot;Screenshot from 2022-01-15 00-27-13.png&quot; data-origin-width=&quot;717&quot; data-origin-height=&quot;269&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>DB</category>
      <category>MySQL</category>
      <category>도커</category>
      <category>로그인</category>
      <category>설치</category>
      <category>접속</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/256</guid>
      <comments>https://junlab.tistory.com/256#entry256comment</comments>
      <pubDate>Sat, 15 Jan 2022 00:28:05 +0900</pubDate>
    </item>
    <item>
      <title>더 나은 코드를 작성하자 (SRP-단일 책임 원칙, OCP-개방 폐쇄 원칙, 응집도, 결합도)</title>
      <link>https://junlab.tistory.com/253</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;SRP(Single Responsibility principle)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;단일 책임 원칙 - 쉽게 유지 보수하고, 이해하기 쉬운 코드와 버그 발생 시 범위를 줄인다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 한 클래스는 한 기능만 책임진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 클래스가 바뀌어야 하는 이유는 오직 하나여야 한다.&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;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) 파싱 프로그램&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 입력 읽기&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 주어진 형식 파싱&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 결과처리&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 결과 요약 리포트&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;h3 data-ke-size=&quot;size23&quot;&gt;응집도(Cohesion)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;클래스나 메서드의 책임이 &lt;b&gt;서로 얼마나 강하게 연결&lt;/b&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;ex) CSV 데이터를 파싱하는 작업과 관련된 두 메서드를 한그룹으로 만들었다 &amp;lt;- 응집도가 높다&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;속성에 맞는 것을 모아서 클래스로 작성 하자. 계산 작업을 하는 로직을 파싱이나, 결과 전송하는 로직과 같은 곳에 작성이 되어 있다면 직접적이 관련이 없기 때문에 응집도가 떨어진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;클래스를 개발할 때는 흔히 다음과 같은 카테고리로 그룹화(클래스 분리)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 / 정보 / 유틸리티 / 논리 / 순차 / 시간&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;결합도(Coupling)&lt;/h3&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;
&lt;p data-ke-size=&quot;size16&quot;&gt;인터페이스를 이용하면 요구 사항이 바뀌더라도 유연성을 유지할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ex) csv를 파싱하는데 json 항목으로 인코딩된 거래 내역을 파싱할려면? xml으로 파싱할려면? 최초 개발시 현재 개발하는 부분이 추가적으로 개발이 필요하단걸 염두 했다면 &lt;b&gt;인터페이스를 이용&lt;/b&gt;했을 것이고, 구현한 클래스를 만들어서 호출하는 부분은 로직 변경 없이 손쉽게 기능을 추가를 할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;명심하고 또 명심)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;KISS (Kepp It Short and Simple)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;DRY (Don't repeat yourself)&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;h3 data-ke-size=&quot;size23&quot;&gt;OCP (Open / Closed Principle)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;코드를 직접 변경하지 않고 해당 메서드나 동작을 바꿀 수 있다. 코드 변경 없이(closed), 확장성은 개방(open)된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;어떻게? 인터페이스를 사용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;반복 로직&lt;/b&gt;과&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;b&gt;비즈니스 로직&lt;/b&gt;이 결합되어 있다면 인터페이스를 사용해서 결합을 제거하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제로 코드를 직접 변경하지 않는 다는 이야기는 호출하는 부분에서는 코드르 변경하지 않는다는 이야기다. 확장을 하고자 하는 코드는 당연히 확장을 하기 위해서는 코드 작성이 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;더 나은 코드와 샘플 코드를 많이 보고 생각하고 곱씹고 익히자.&lt;/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;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;소스코드)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/Iteratr-Learning/Real-World-Software-Development/tree/master/src/main/java/com/iteratrlearning/shu_book/chapter_03&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;https://github.com/Iteratr-Learning/Real-World-Software-Development/tree/master/src/main/java/com/iteratrlearning/shu_book/chapter_03&lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;책 참고)&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실전 자바 소프트웨어 개발&lt;/p&gt;</description>
      <category>Programming/소프트웨어 설계</category>
      <category>ocp</category>
      <category>SRP</category>
      <category>결합도</category>
      <category>응집도</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/253</guid>
      <comments>https://junlab.tistory.com/253#entry253comment</comments>
      <pubDate>Sat, 8 Jan 2022 01:48:05 +0900</pubDate>
    </item>
    <item>
      <title>[drone.io] gitlab - drone.io 도커 설치 (CI)</title>
      <link>https://junlab.tistory.com/252</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;우리가 작성한 코드가 깃헙이나 깃랩에 push가 되면 자동으로 빌드 및 배포가 될 수 있도록 CI 툴을 많은 사용 합니다.&lt;/p&gt;
&lt;p&gt;젠킨스나, Travis CI는 많이 들어 보셨으리라 생각이 되는데요.&lt;/p&gt;
&lt;p&gt;앞에 말씀드린 툴 이외에도 Drone.io라는 CI 툴이 있습니다.&lt;/p&gt;
&lt;p&gt;Drone.io를 사용해보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;도커 기반으로 설치를 하기 때문에 도커가 설치가 되어 있으셔야 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. 깃랩 클라이언트ID와 키를 발급&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;깃랩 프로젝트 레파짓을 사용하기 때문에 클라이언트 ID와 키를 발급 받으셔야 됩니다.&lt;/p&gt;
&lt;p&gt;깃랩 로그인 후 오른쪽 상단 프로필을 눌러주세요.&lt;/p&gt;
&lt;p&gt;preference -&amp;gt; Application(왼쪽 메뉴) -&amp;gt; 값 입력&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;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O8ouJ/btq3czM8orj/49xmE6YUkxKLMv1IUKC9o0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O8ouJ/btq3czM8orj/49xmE6YUkxKLMv1IUKC9o0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O8ouJ/btq3czM8orj/49xmE6YUkxKLMv1IUKC9o0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO8ouJ%2Fbtq3czM8orj%2F49xmE6YUkxKLMv1IUKC9o0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&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;Name: 구분 이름&lt;/p&gt;
&lt;p&gt;Redirect URI: 드론.io를 설치할 서버 URI/login&lt;/p&gt;
&lt;p&gt;ex) http://127.0.0.1:8080/login&lt;/p&gt;
&lt;p&gt;---&amp;gt; 포트번호는 설정의 따라서 달라질 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;확인을 누르고 나면 Application ID와 Secret을 확인하실 수 있습니다.&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;pre id=&quot;code_1619072516776&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;openssl rand -hex 16&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 서버에서 드론(서버) 설치 (도커로 진행)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619072586274&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker pull drone/drone:1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. 환경 변수 등록 (~/.bashrc)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619074085424&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export DRONE_GITLAB_CLIENT_ID=[...]  &amp;lt;- 깃랩에서 발급 받은 클라이언트 아이디
export DRONE_GITLAB_CLIENT_SECRET=[...]  &amp;lt;- 깃랩에서 발급 받은 시크릿 키
export DRONE_RPC_SECRET=[...] &amp;lt;- 2번 항목 서버에서 발급 받은 키
export DRONE_SERVER_HOST=127.0.0.1:8080
export DRONE_SERVER_PROTO=http&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;등록 후&amp;nbsp; &lt;b&gt;source ~/.bashrc&lt;/b&gt; 명령어를 입력해주세요&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. 드론 서버 구동&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619074244859&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run \
  --volume=/var/lib/drone:/data \
  --env=DRONE_GITLAB_SERVER=https://gitlab.com \
  --env=DRONE_GITLAB_CLIENT_ID=`echo $DRONE_GITLAB_CLIENT_ID` \
  --env=DRONE_GITLAB_CLIENT_SECRET=`echo $DRONE_GITLAB_CLIENT_SECRET` \
  --env=DRONE_RPC_SECRET=`echo $DRONE_RPC_SECRET` \
  --env=DRONE_SERVER_HOST=`echo $DRONE_SERVER_HOST` \
  --env=DRONE_SERVER_PROTO=`echo $DRONE_SERVER_PROTO` \
  --env=DRONE_LOGS_TRACE=true \
  --publish=8080:80 \
  --publish=443:443 \
  --restart=always \
  --detach=true \
  --name=drone \
  drone/drone:1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;구동할 때 8080 포트로 구동하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;6. 드론 서버 구동 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619074396919&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker ps -a
docker logs drone&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령어를 통해서 도커가 잘 구동이 되었는지 확인을 해주세요.&lt;/p&gt;
&lt;p&gt;그리고 &lt;b&gt;등록하신 서버 호스트 주소를 입력하여 drone.io 대시보드가 잘 보이는지 확인&lt;/b&gt;을 해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;지금까지는 Drone 서버를 설치를 하였습니다.&lt;/p&gt;
&lt;p&gt;이후에 개발자가 깃랩에 코드를 push 하고 드론이 자동으로 빌드를 하기 위해서는 drone runner를 설치를 해주셔야 됩니다.&lt;/p&gt;
&lt;p&gt;즉, &lt;b&gt;드론 서버는 깃랩과 통신을 하기 위한 서버 역할을&lt;/b&gt; 하고, &lt;b&gt;runner는 (빌드) 작업을 진행하는 역할&lt;/b&gt;을 합니다.&lt;/p&gt;
&lt;p&gt;러너가 없다면 코드가 push 되고 드론 서버에서 요청을 받아도 빌드 작업을 진행할 수 없습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;7. 드론 러너 설치 (도커)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619074867327&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker pull drone/drone-runner-docker:1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;8. 환경변수 등록(~/.bashrc)&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619074973530&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;export DRONE_RPC_HOST=127.0.0.1:8080
export DRONE_RPC_PROTO=http&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;9. 드론 러너 구동&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619075088282&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d \
  -v /var/run/docker.sock:/var/run/docker.sock \
  -e DRONE_RPC_PROTO=`echo $DRONE_RPC_PROTO` \
  -e DRONE_RPC_HOST=`echo $DRONE_RPC_HOST` \
  -e DRONE_RPC_SECRET=`echo $DRONE_RPC_SECRET` \
  -e DRONE_RUNNER_CAPACITY=2 \
  -e DRONE_RUNNER_NAME=`echo $HOSTNAME` \
  -p 3000:3000 \
  --restart always \
  --name runner \
  drone/drone-runner-docker:1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;10. 드론 러너 구동 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1619075134290&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs runner&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b4NeiF/btq3dQHIuZC/clbiBktKQKGnU7yIvOySTk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b4NeiF/btq3dQHIuZC/clbiBktKQKGnU7yIvOySTk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b4NeiF/btq3dQHIuZC/clbiBktKQKGnU7yIvOySTk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb4NeiF%2Fbtq3dQHIuZC%2FclbiBktKQKGnU7yIvOySTk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;러너까지 설치가 완료되셨다면, drone.io를 사용하기 위한 준비는 끝났습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;[참고 문서]&lt;/p&gt;
&lt;p&gt;드론 서버: &lt;a href=&quot;https://docs.drone.io/runner/docker/installation/linux/&quot;&gt;docs.drone.io/runner/docker/installation/linux/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;드론 runner: &lt;a href=&quot;https://docs.drone.io/runner/docker/overview/&quot;&gt;docs.drone.io/runner/docker/overview/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>drone.io</category>
      <category>gitlab</category>
      <category>install</category>
      <category>깃랩</category>
      <category>드론io</category>
      <category>설치</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/252</guid>
      <comments>https://junlab.tistory.com/252#entry252comment</comments>
      <pubDate>Thu, 22 Apr 2021 15:24:39 +0900</pubDate>
    </item>
    <item>
      <title>[docker] centos 7 도커 설치</title>
      <link>https://junlab.tistory.com/251</link>
      <description>&lt;p&gt;centos7에 도커를 설치하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. 도커 설치&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618963120712&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo yum install docker&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/s3YNJ/btq3atx6dTj/HNahcQFd3BjkbMxflkrk30/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/s3YNJ/btq3atx6dTj/HNahcQFd3BjkbMxflkrk30/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/s3YNJ/btq3atx6dTj/HNahcQFd3BjkbMxflkrk30/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fs3YNJ%2Fbtq3atx6dTj%2FHNahcQFd3BjkbMxflkrk30%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. y 입력&lt;/b&gt;&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bTLUsf/btq23uyPIVE/YA1ObyZuojgtPIzNKq8221/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bTLUsf/btq23uyPIVE/YA1ObyZuojgtPIzNKq8221/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bTLUsf/btq23uyPIVE/YA1ObyZuojgtPIzNKq8221/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbTLUsf%2Fbtq23uyPIVE%2FYA1ObyZuojgtPIzNKq8221%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 도커 실행 및 실행여부 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618963203860&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo systemctl start docker
sudo systemctl status docker&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ccz5Tu/btq284d69Kt/YhRvlWtKHvIQoqZRKSo0KK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ccz5Tu/btq284d69Kt/YhRvlWtKHvIQoqZRKSo0KK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ccz5Tu/btq284d69Kt/YhRvlWtKHvIQoqZRKSo0KK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fccz5Tu%2Fbtq284d69Kt%2FYhRvlWtKHvIQoqZRKSo0KK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. 도커 설치 테스트를 위한 테스트 컨테이너 동작 및 컨테이너 동작여부 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618963407832&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo docker run -d -p 80:80 docker/getting-started
sudo docker container ls&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;386&quot; data-filename=&quot;blob&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t7a7k/btq21NyUZLc/bhPDS3iFhgXQh6ftwLLM8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t7a7k/btq21NyUZLc/bhPDS3iFhgXQh6ftwLLM8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t7a7k/btq21NyUZLc/bhPDS3iFhgXQh6ftwLLM8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft7a7k%2Fbtq21NyUZLc%2FbhPDS3iFhgXQh6ftwLLM8K%2Fimg.png&quot; data-origin-width=&quot;1122&quot; data-origin-height=&quot;386&quot; data-filename=&quot;blob&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. 직접 페이지 열어보기&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;로컬에서 띄우셨다면 &lt;b&gt;127.0.0.1 로 접속&lt;/b&gt;을 해주세요!!&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;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b8udqH/btq26oED3M9/IXPiAT8BmlNqo9s6WZ6G50/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b8udqH/btq26oED3M9/IXPiAT8BmlNqo9s6WZ6G50/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b8udqH/btq26oED3M9/IXPiAT8BmlNqo9s6WZ6G50/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb8udqH%2Fbtq26oED3M9%2FIXPiAT8BmlNqo9s6WZ6G50%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다 :)&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>CentOS7</category>
      <category>docker</category>
      <category>docker run</category>
      <category>install</category>
      <category>도커</category>
      <category>리눅스</category>
      <category>설치</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/251</guid>
      <comments>https://junlab.tistory.com/251#entry251comment</comments>
      <pubDate>Wed, 21 Apr 2021 09:06:31 +0900</pubDate>
    </item>
    <item>
      <title>[jenkins] 젠킨스 도커 설치 (+구동이 안되는 문제)</title>
      <link>https://junlab.tistory.com/250</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;젠킨스를 도커를 활용하여 설치를 하도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;또한 도커 구동 중 권한 문제가 발생하는 문제도 해결하도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. 다음 명령어 실행 후 젠킨스 사이트 접속&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;아래 명령어를 실행시켜주시면 젠킨스가 자동으로 구동이 됩니다.&lt;/p&gt;
&lt;p&gt;그리고 해당 IP:8080 으로 가시면 젠킨스의 접속을 하실 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1618452157038&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker run -d --name jenkins -p 8080:8080 -p 50000:50000 -v /app/jenkins:/var/jenkins_home jenkins/jenkins:lts&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cntTCS/btq2zd5ygfT/6okOax7bWLuIsqbyKaWKvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cntTCS/btq2zd5ygfT/6okOax7bWLuIsqbyKaWKvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cntTCS/btq2zd5ygfT/6okOax7bWLuIsqbyKaWKvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcntTCS%2Fbtq2zd5ygfT%2F6okOax7bWLuIsqbyKaWKvk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. 구동이 완료 되어 사이트 접속을 시도&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;8080 포트로 접속을 하였는데 응답이 없는 걸 확인하였습니다.&lt;/p&gt;
&lt;p&gt;정상적으로 동작이 안되는 거 같습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 현재 구동 중인 도커 프로세스를 확인&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;구동이 됐는데 안들어가지는지 아니면 아예 구동이 안되었는지 확인을 해봅니다.&lt;/p&gt;
&lt;pre id=&quot;code_1618452320274&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker ps -a&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qvj5o/btq2GV9F0vc/G2xUNCisBUqoXz3Ue0iFEk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qvj5o/btq2GV9F0vc/G2xUNCisBUqoXz3Ue0iFEk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qvj5o/btq2GV9F0vc/G2xUNCisBUqoXz3Ue0iFEk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fqvj5o%2Fbtq2GV9F0vc%2FG2xUNCisBUqoXz3Ue0iFEk%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;구동이 되자마자 상태가 종료가 된 모습을 확인하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. 로그를 확인 &lt;/b&gt;&lt;/p&gt;
&lt;p&gt;컨테이너 아이디 또는 컨테이너 이름을 작성해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1618452481577&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker logs &amp;lt;container_id&amp;gt; or &amp;lt;container_names&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cYG0Lg/btq2DFT5v2w/mXME8sw12GpLOlTPzpo7DK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cYG0Lg/btq2DFT5v2w/mXME8sw12GpLOlTPzpo7DK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cYG0Lg/btq2DFT5v2w/mXME8sw12GpLOlTPzpo7DK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcYG0Lg%2Fbtq2DFT5v2w%2FmXME8sw12GpLOlTPzpo7DK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;데이터 저장을 위한 볼륨 부분에서 권한 문제가 발생하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;호스트 서버의 볼륨 디렉터리를 /app/jenkins를 미리 만들었습니다.&lt;/p&gt;
&lt;p&gt;검색을 해보니 이 디렉터리가 권한이 부족하여 문제가 발생한다고 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. 호스트 볼륨 디렉토리 권한 부여&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618452772171&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo chown 1000 &amp;lt;호스트 쪽 볼륨 디렉토리&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Xsl35/btq2CEOQLpx/Fxojdf4JCZmguR5UkOJ5Y1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Xsl35/btq2CEOQLpx/Fxojdf4JCZmguR5UkOJ5Y1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Xsl35/btq2CEOQLpx/Fxojdf4JCZmguR5UkOJ5Y1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXsl35%2Fbtq2CEOQLpx%2FFxojdf4JCZmguR5UkOJ5Y1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;6. 기존 컨테이너 삭제&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618452872578&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker rm &amp;lt;컨테이너 이름&amp;gt; or &amp;lt;컨테이너 id&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/t9Dtz/btq2y3IPR6A/8A6CudzB9kqcKL9u3jX0S1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/t9Dtz/btq2y3IPR6A/8A6CudzB9kqcKL9u3jX0S1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/t9Dtz/btq2y3IPR6A/8A6CudzB9kqcKL9u3jX0S1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Ft9Dtz%2Fbtq2y3IPR6A%2F8A6CudzB9kqcKL9u3jX0S1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;7. 그리고 처음의 1번 명령어를 활용하여 구동&lt;/b&gt;을 시켜주시면 되겠습니다.&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bVmyjy/btq2LkJc5b8/BeR8SyIaxc57rX19g4CGQ0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bVmyjy/btq2LkJc5b8/BeR8SyIaxc57rX19g4CGQ0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bVmyjy/btq2LkJc5b8/BeR8SyIaxc57rX19g4CGQ0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbVmyjy%2Fbtq2LkJc5b8%2FBeR8SyIaxc57rX19g4CGQ0%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/uX2jm/btq2My7L72q/v9ICZaz4VrruWuoVNfhn8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/uX2jm/btq2My7L72q/v9ICZaz4VrruWuoVNfhn8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/uX2jm/btq2My7L72q/v9ICZaz4VrruWuoVNfhn8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FuX2jm%2Fbtq2My7L72q%2Fv9ICZaz4VrruWuoVNfhn8K%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고로 위의 패스워드는 아래 스크립트로 확인해주세요 :)&lt;/p&gt;
&lt;pre id=&quot;code_1618555364144&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo docker exec -it jenkins cat /var/jenkins_home/secrets/initialAdminPassword&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;도커를 활용하여 젠킨스 구동이 정상적으로 되었습니다.&lt;/p&gt;
&lt;p&gt;감사합니다 :)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>docker</category>
      <category>docker jenkins</category>
      <category>jenkins</category>
      <category>구동 에러</category>
      <category>도커</category>
      <category>도커 젠킨스</category>
      <category>실행</category>
      <category>젠킨스</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/250</guid>
      <comments>https://junlab.tistory.com/250#entry250comment</comments>
      <pubDate>Thu, 15 Apr 2021 11:33:07 +0900</pubDate>
    </item>
    <item>
      <title>[docker] 도커 에러 /var/run/docker.sockconnect: permission denied</title>
      <link>https://junlab.tistory.com/249</link>
      <description>&lt;p&gt;&lt;b&gt;도커 명령어 수행 중&lt;/b&gt; permission denied가 발생 하였습니다.&lt;/p&gt;
&lt;p&gt;에러가 나는 이유는 1023 이하 포트는 well-known port 로써 권한이 필요하기 때문에 발생하는 에러입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1618448988207&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Got permission denied while trying to connect to the Docker daemon socket at 
unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.26/images/json
: dial unix /var/run/docker.sock: connect: permission denied&lt;/code&gt;&lt;/pre&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/brczSa/btq2BDvTN1Q/qb0OlWyQQKccmkILytPKyK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/brczSa/btq2BDvTN1Q/qb0OlWyQQKccmkILytPKyK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/brczSa/btq2BDvTN1Q/qb0OlWyQQKccmkILytPKyK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbrczSa%2Fbtq2BDvTN1Q%2Fqb0OlWyQQKccmkILytPKyK%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;해결방법&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1618449132902&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo chmod 666 /var/run/docker.sock&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;권한을 주시면 해결하실 수 있습니다 :)&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; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/C0XtX/btq2yul7TKh/exl7eLIkYHCIQH4LQHB7N1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/C0XtX/btq2yul7TKh/exl7eLIkYHCIQH4LQHB7N1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/C0XtX/btq2yul7TKh/exl7eLIkYHCIQH4LQHB7N1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FC0XtX%2Fbtq2yul7TKh%2Fexl7eLIkYHCIQH4LQHB7N1%2Fimg.png&quot; data-origin-width=&quot;0&quot; data-origin-height=&quot;0&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>Denied</category>
      <category>docker</category>
      <category>docker.sock</category>
      <category>permission</category>
      <category>도커</category>
      <category>에러</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/249</guid>
      <comments>https://junlab.tistory.com/249#entry249comment</comments>
      <pubDate>Thu, 15 Apr 2021 10:12:39 +0900</pubDate>
    </item>
    <item>
      <title>[java] Exception in thread &amp;quot;main&amp;quot; java.net.MalformedURLException: no protocol 자바 에러</title>
      <link>https://junlab.tistory.com/248</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;XML을 파싱 하는 도중 에러가 발생하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;사용한 코드:&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1616741632167&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Document doc = DocumentBuilderFactory.newInstance()
                .newDocumentBuilder()
                .parse(new InputSource(XML내용));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;에러 내용:&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1.PNG&quot; data-origin-width=&quot;1121&quot; data-origin-height=&quot;42&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bWpCMJ/btq09iMszmH/I3N9LSrm73TsOfayxttkrk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bWpCMJ/btq09iMszmH/I3N9LSrm73TsOfayxttkrk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bWpCMJ/btq09iMszmH/I3N9LSrm73TsOfayxttkrk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbWpCMJ%2Fbtq09iMszmH%2FI3N9LSrm73TsOfayxttkrk%2Fimg.png&quot; data-filename=&quot;1.PNG&quot; data-origin-width=&quot;1121&quot; data-origin-height=&quot;42&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2.PNG&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;318&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nNq7M/btq06hAKcn6/fukHBkQmlIgjpkJ7HDVPFK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nNq7M/btq06hAKcn6/fukHBkQmlIgjpkJ7HDVPFK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nNq7M/btq06hAKcn6/fukHBkQmlIgjpkJ7HDVPFK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnNq7M%2Fbtq06hAKcn6%2FfukHBkQmlIgjpkJ7HDVPFK%2Fimg.png&quot; data-filename=&quot;2.PNG&quot; data-origin-width=&quot;1134&quot; data-origin-height=&quot;318&quot; width=&quot;700&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 id=&quot;code_1616741577292&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Exception in thread &quot;main&quot; java.net.MalformedURLException: no protocol: &amp;lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&amp;gt;
	at java.net.URL.&amp;lt;init&amp;gt;(URL.java:593)
	at java.net.URL.&amp;lt;init&amp;gt;(URL.java:490)
	at java.net.URL.&amp;lt;init&amp;gt;(URL.java:439)
	at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:620)
	at com.sun.org.apache.xerces.internal.impl.XMLVersionDetector.determineDocVersion(XMLVersionDetector.java:148)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:805)
	at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770)
	at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
	at com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:243)
	at com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
	at Main3.main(Main3.java:184)

FAILURE: Build failed with an exception.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위와 같은 에러가 발생하였는데요.&lt;/p&gt;
&lt;p&gt;파싱 하실 때 StringReader를 사용하여 xml을 읽어야 문제가 발생하지 않습니다 :)&lt;/p&gt;
&lt;pre id=&quot;code_1616741786901&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Document doc = DocumentBuilderFactory.newInstance()
                .newDocumentBuilder()
                .parse(new InputSource(new StringReader(XML내용)));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다 :)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>MalformedURLException</category>
      <category>no protocol</category>
      <category>XML 파싱</category>
      <category>에러</category>
      <category>자바</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/248</guid>
      <comments>https://junlab.tistory.com/248#entry248comment</comments>
      <pubDate>Fri, 26 Mar 2021 15:57:27 +0900</pubDate>
    </item>
    <item>
      <title>[java] spring boot 실행 시 Permission denied 에러 (on linux)</title>
      <link>https://junlab.tistory.com/246</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;리눅스 환경에서 spring boot를 실행시켰을 때 Permission denied 에러가 발생하였습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1613024612087&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Caused by: java.net.SocketException: Permission denied
	at java.base/sun.nio.ch.Net.bind0(Native Method) ~[na:na]
	at java.base/sun.nio.ch.Net.bind(Net.java:455) ~[na:na]
	at java.base/sun.nio.ch.Net.bind(Net.java:447) ~[na:na]
	at java.base/sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:227) ~[na:na]
	at java.base/sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:80) ~[na:na]
	at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:228) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:211) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1141) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1227) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:592) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	at org.apache.catalina.connector.Connector.startInternal(Connector.java:1064) ~[tomcat-embed-core-9.0.39.jar:9.0.39]
	... 21 common frames omitted&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2021-02-11 15-19-21.png&quot; data-origin-width=&quot;1219&quot; data-origin-height=&quot;403&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bEeDgI/btqWVQ8pgUo/0xckoIW18k1Xi8ipa6W001/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bEeDgI/btqWVQ8pgUo/0xckoIW18k1Xi8ipa6W001/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bEeDgI/btqWVQ8pgUo/0xckoIW18k1Xi8ipa6W001/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbEeDgI%2FbtqWVQ8pgUo%2F0xckoIW18k1Xi8ipa6W001%2Fimg.png&quot; data-filename=&quot;Screenshot from 2021-02-11 15-19-21.png&quot; data-origin-width=&quot;1219&quot; data-origin-height=&quot;403&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;에러가 발생한 원인은 간단했습니다.&lt;/p&gt;
&lt;p&gt;구동할 때 포트를 80번 포트로 지정을 해놓았는데요.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;리눅스에서는 &amp;lt;= 1024 포트에 대해서는 일반 사용자가 사용을 하지 못&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;그렇기 때문에 포트를 1025 이상 포트를 지정해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>java</category>
      <category>Linux</category>
      <category>permission denied</category>
      <category>port</category>
      <category>Spring boot</category>
      <category>ubuntu</category>
      <category>에러</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/246</guid>
      <comments>https://junlab.tistory.com/246#entry246comment</comments>
      <pubDate>Thu, 11 Feb 2021 15:26:50 +0900</pubDate>
    </item>
    <item>
      <title>[git] git stash clear 복구 (stash를 지웠어요)</title>
      <link>https://junlab.tistory.com/244</link>
      <description>&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;git-logo.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;400&quot; width=&quot;400&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/F9RgE/btqWLX0D40M/ikrNsS1UKVmrOnUFtRkbN1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/F9RgE/btqWLX0D40M/ikrNsS1UKVmrOnUFtRkbN1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/F9RgE/btqWLX0D40M/ikrNsS1UKVmrOnUFtRkbN1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FF9RgE%2FbtqWLX0D40M%2FikrNsS1UKVmrOnUFtRkbN1%2Fimg.png&quot; data-filename=&quot;git-logo.png&quot; data-origin-width=&quot;800&quot; data-origin-height=&quot;400&quot; width=&quot;400&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;작업 중에 기존의 stash를 지웠습니다.&lt;/p&gt;
&lt;p&gt;기존의 작업 양이 많다면 식은땀이 나고 당황하실 수 있습니다.&lt;/p&gt;
&lt;p&gt;하지만 복구 방법이 있습니다 :)&lt;/p&gt;
&lt;p&gt;아래의 명령어를 입력해주시면 삭제했던 stash 해시를 찾을 수 있습니다.&lt;/p&gt;
&lt;p&gt;단 시간을 보고 하나씩 하나씩 찾아보셔야 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1612921458321&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git fsck --no-reflog | awk '/dangling commit/ {print $3}' | xargs -L 1 git --no-pager show -s --format=&quot;%ci %H&quot; | sort&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위에서 찾은 해시를 아래 명령어로 불러 들이면 되겠습니다 ^^&lt;/p&gt;
&lt;pre id=&quot;code_1612921495581&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git stash apply 복구할해시&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;참고)&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://stackoverflow.com/questions/89332/how-to-recover-a-dropped-stash-in-git&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;stackoverflow.com/questions/89332/how-to-recover-a-dropped-stash-in-git&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/Git, Mercurial</category>
      <category>GIT</category>
      <category>git stash</category>
      <category>stash clear 복구</category>
      <category>stash 복구</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/244</guid>
      <comments>https://junlab.tistory.com/244#entry244comment</comments>
      <pubDate>Wed, 10 Feb 2021 10:51:55 +0900</pubDate>
    </item>
    <item>
      <title>[java] 자바 HttpResponse 후 HttpEntity값 받기</title>
      <link>https://junlab.tistory.com/242</link>
      <description>&lt;p&gt;자바 Http 통신 후 response를 받게 됩니다.&lt;/p&gt;
&lt;p&gt;response의 값을 직접 확인 하는 방법에 대해서 알아봅니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. String으로 받기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1612401454875&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HttpResponse response = httpClient.execute(new HttpGet(URL));
HttpEntity entity = response.getEntity();
String responseString = EntityUtils.toString(entity, &quot;UTF-8&quot;);
System.out.println(responseString);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. Line별로 받기&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1612401552730&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;HttpResponse response = httpClient.execute(new HttpGet(URL));
HttpEntity entity = response.getEntity();
InputStream is = entity.getContent();
BufferedReader r = new BufferedReader(new InputStreamReader(is, Charset.forName(&quot;UTF-8&quot;)));
String line;

while ((line = r.readLine()) != null) {
	System.out.println(line);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;캡처.PNG&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;267&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Vcdas/btqVzRO8wZC/kK3QfpaY40Kyk7G8yoXPTK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Vcdas/btqVzRO8wZC/kK3QfpaY40Kyk7G8yoXPTK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Vcdas/btqVzRO8wZC/kK3QfpaY40Kyk7G8yoXPTK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FVcdas%2FbtqVzRO8wZC%2FkK3QfpaY40Kyk7G8yoXPTK%2Fimg.png&quot; data-filename=&quot;캡처.PNG&quot; data-origin-width=&quot;883&quot; data-origin-height=&quot;267&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>HttpEntity</category>
      <category>HttpResponse</category>
      <category>자바</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/242</guid>
      <comments>https://junlab.tistory.com/242#entry242comment</comments>
      <pubDate>Thu, 4 Feb 2021 10:22:56 +0900</pubDate>
    </item>
    <item>
      <title>[DB] PostgreSQL 기본키 - 시퀀스 생성 (insert 시 자동으로 시퀀스)</title>
      <link>https://junlab.tistory.com/241</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;데이터 INSERT를 할때 자동으로 시퀀스를 생성하고 싶었습니다.&lt;/p&gt;
&lt;p&gt;상황은 기존의 컬럼은 존재하나 INSERT 시 자동으로 시퀀스를 만들기 위해서 컬럼의 제약조건을 변경합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;테이블 이름은 tbl_board이고 컬럼 이름은 bno 입니다.&lt;/p&gt;
&lt;p&gt;아래 코드를 활용해서 시퀀스를 생성해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1609549537243&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;  --ALTER TABLE tbl_board ADD COLUMN bno INTEGER;	//키 컬럼이 없다면 입력, 기존 키 컬럼 있다면 무시
  CREATE SEQUENCE board_bno_seq OWNED BY tbl_board.bno;
  ALTER TABLE tbl_board ALTER COLUMN bno SET DEFAULT nextval('board_bno_seq');
  UPDATE tbl_board SET bno = nextval('board_bno_seq');&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;시퀀스가 생성이 되었다면 INSERT 구문은 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1609549606458&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSERT INTO public.tbl_board(
	title, content, writer, regdate, updatedate)
	VALUES ('테스트제목', '테스트내용', 'user00', now(), now());&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;INSERT 시 별도의 bno 값은 안 넣어도 자동으로 시퀀스가 생성이 되겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;포스트그레스_제약조건_시퀀스_기본키.PNG&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;400&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bAFhbT/btqSgMhW5C2/BvODHeOLc0Yw1xwCnUqVy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bAFhbT/btqSgMhW5C2/BvODHeOLc0Yw1xwCnUqVy0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bAFhbT/btqSgMhW5C2/BvODHeOLc0Yw1xwCnUqVy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbAFhbT%2FbtqSgMhW5C2%2FBvODHeOLc0Yw1xwCnUqVy0%2Fimg.png&quot; data-filename=&quot;포스트그레스_제약조건_시퀀스_기본키.PNG&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;400&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;값 확인.PNG&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;300&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dtAciP/btqR1E6Zhrq/PKSnTwq78fjkVFH9kUD9t1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dtAciP/btqR1E6Zhrq/PKSnTwq78fjkVFH9kUD9t1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dtAciP/btqR1E6Zhrq/PKSnTwq78fjkVFH9kUD9t1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdtAciP%2FbtqR1E6Zhrq%2FPKSnTwq78fjkVFH9kUD9t1%2Fimg.png&quot; data-filename=&quot;값 확인.PNG&quot; data-origin-width=&quot;837&quot; data-origin-height=&quot;300&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>DB/PostgreSQL</category>
      <category>insert</category>
      <category>PostgreSQL</category>
      <category>기본키</category>
      <category>시퀀스</category>
      <category>포스트그레스</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/241</guid>
      <comments>https://junlab.tistory.com/241#entry241comment</comments>
      <pubDate>Sat, 2 Jan 2021 10:11:15 +0900</pubDate>
    </item>
    <item>
      <title>[spring] 스프링 에러 - org.aspectj.weaver.reflect.ReflectionWorld</title>
      <link>https://junlab.tistory.com/239</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;자바 spring 학습 및 aop 세팅 중 에러가 발생하였습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;java_spring_aop.PNG&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;356&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pGV1G/btqOeCSAfiA/rYPJLaXlJm6Vn3r8j75Ik0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pGV1G/btqOeCSAfiA/rYPJLaXlJm6Vn3r8j75Ik0/img.png&quot; data-alt=&quot;세팅 내용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pGV1G/btqOeCSAfiA/rYPJLaXlJm6Vn3r8j75Ik0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpGV1G%2FbtqOeCSAfiA%2FrYPJLaXlJm6Vn3r8j75Ik0%2Fimg.png&quot; data-filename=&quot;java_spring_aop.PNG&quot; data-origin-width=&quot;922&quot; data-origin-height=&quot;356&quot; width=&quot;650&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;세팅 내용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;에러가 발생한 부분은 aop 부분에서 발생한 것으로 생각이 됩니다.&lt;/p&gt;
&lt;p&gt;에러 내용은 다음과 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1606373144153&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Exception in thread &quot;main&quot; org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'boardDAO' defined in file [C:\Users\lg\eclipse-workspace\BoardWeb\target\classes\com\junngo\biz\board\impl\BoardDAO.class]: BeanPostProcessor before instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:478)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
	at org.springframework.context.support.GenericXmlApplicationContext.&amp;lt;init&amp;gt;(GenericXmlApplicationContext.java:70)
	at com.junngo.biz.board.BoardServiceClient.main(BoardServiceClient.java:14)

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0': Initialization of bean failed; nested exception is java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
	at org.springframework.aop.framework.autoproxy.BeanFactoryAdvisorRetrievalHelper.findAdvisorBeans(BeanFactoryAdvisorRetrievalHelper.java:92)
	at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findCandidateAdvisors(AbstractAdvisorAutoProxyCreator.java:101)
	at org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator.findCandidateAdvisors(AnnotationAwareAspectJAutoProxyCreator.java:85)
	at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.shouldSkip(AspectJAwareAdvisorAutoProxyCreator.java:103)
	at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessBeforeInstantiation(AbstractAutoProxyCreator.java:248)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:988)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.resolveBeforeInstantiation(AbstractAutowireCapableBeanFactory.java:959)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:472)
	... 9 more

Caused by: java.lang.NoClassDefFoundError: org/aspectj/weaver/reflect/ReflectionWorld$ReflectionWorldException
	at java.lang.Class.getDeclaredMethods0(Native Method)
	at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
	at java.lang.Class.getDeclaredMethods(Class.java:1975)
	at org.springframework.util.ReflectionUtils.getDeclaredMethods(ReflectionUtils.java:609)
	at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:521)
	at org.springframework.util.ReflectionUtils.doWithMethods(ReflectionUtils.java:507)
	at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.determineCandidateConstructors(AutowiredAnnotationBeanPostProcessor.java:241)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineConstructorsFromBeanPostProcessors(AbstractAutowireCapableBeanFactory.java:1069)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1042)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:325)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveReference(BeanDefinitionValueResolver.java:351)
	at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:108)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1481)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1226)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
	... 22 more

Caused by: java.lang.ClassNotFoundException: org.aspectj.weaver.reflect.ReflectionWorld$ReflectionWorldException
	at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
	at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
	at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
	... 40 more&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;java_error.PNG&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;531&quot; width=&quot;800&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/9ndFD/btqOiA7nF29/QBdJf3nuGqi3tcz2AHvl11/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/9ndFD/btqOiA7nF29/QBdJf3nuGqi3tcz2AHvl11/img.png&quot; data-alt=&quot;에러 내용&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/9ndFD/btqOiA7nF29/QBdJf3nuGqi3tcz2AHvl11/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F9ndFD%2FbtqOiA7nF29%2FQBdJf3nuGqi3tcz2AHvl11%2Fimg.png&quot; data-filename=&quot;java_error.PNG&quot; data-origin-width=&quot;1335&quot; data-origin-height=&quot;531&quot; width=&quot;800&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;에러 내용&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;에러 내용 중 제일 아래를 보니(&lt;a href=&quot;http://java.lang.ClassNotFoundException&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;java.lang.ClassNotFoundException&lt;/a&gt;) aspectj.weaver 클래스를 찾을 수 없다고 합니다.&lt;/p&gt;
&lt;p&gt;aspectjweaver 라이브러리가 없어서 발생하는 에러였습니다.&lt;/p&gt;
&lt;p&gt;메이븐을 사용하신다면 pom.xml로 이동하셔서 aspectjweaver를 추가해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1606374104826&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;&amp;lt;dependency&amp;gt;
	&amp;lt;groupId&amp;gt;org.aspectj&amp;lt;/groupId&amp;gt;
	&amp;lt;artifactId&amp;gt;aspectjweaver&amp;lt;/artifactId&amp;gt;
	&amp;lt;version&amp;gt;${org.aspectj-version}&amp;lt;/version&amp;gt;
&amp;lt;/dependency&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;java 추가내용.PNG&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;478&quot; width=&quot;600&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bHrn3d/btqOnygD4tH/2ubptDkJ3FA3TKhcgEiZ70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bHrn3d/btqOnygD4tH/2ubptDkJ3FA3TKhcgEiZ70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bHrn3d/btqOnygD4tH/2ubptDkJ3FA3TKhcgEiZ70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbHrn3d%2FbtqOnygD4tH%2F2ubptDkJ3FA3TKhcgEiZ70%2Fimg.png&quot; data-filename=&quot;java 추가내용.PNG&quot; data-origin-width=&quot;705&quot; data-origin-height=&quot;478&quot; width=&quot;600&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;라이브러리를 추가하시면 이상없이 문제가 해결되겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다 :)&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>AOP</category>
      <category>AspectJ</category>
      <category>aspectj.weaver</category>
      <category>error</category>
      <category>java</category>
      <category>Spring</category>
      <category>weaver</category>
      <category>에러</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/239</guid>
      <comments>https://junlab.tistory.com/239#entry239comment</comments>
      <pubDate>Thu, 26 Nov 2020 16:04:20 +0900</pubDate>
    </item>
    <item>
      <title>[django] 파이썬애니웨어을 활용한 장고 배포 (django deploy)</title>
      <link>https://junlab.tistory.com/238</link>
      <description>&lt;p&gt;1. 파이썬애니웨어 사이트 접속 후 회원가입&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.pythonanywhere.com/&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;www.pythonanywhere.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. Console 메뉴로 이동&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;3. git clone을 통해서 소스코드 다운로드 (&lt;span style=&quot;color: #333333;&quot;&gt;Console)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4. 가상환경 생성 및 구동 (&lt;span style=&quot;color: #333333;&quot;&gt;Console)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1606205608427&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;virtualenv venv --python=python3.7
source venv/bin/activate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;5.&amp;nbsp;장고 설치 (&lt;span style=&quot;color: #333333;&quot;&gt;Console)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1606205616169&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install django&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;6. 데이터베이스 초기화 (&lt;span style=&quot;color: #333333;&quot;&gt;Console)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1606205620945&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python manage.py migrate&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;7. 관리자 계정 생성 (&lt;span style=&quot;color: #333333;&quot;&gt;Console)&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1606205626201&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python manage.py createsuperuser&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;8. 웹앱 설정 -&amp;gt; Web 메뉴로 이동&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;9. 웹앱 생성 -&amp;gt; Add a new web app&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;10. Manual configuration 선택, 파이썬 (3.7) 버전 선택&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;11. 웨앱 설정 후 Dashboard로 이동&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;12. WSGI 설정, Web 메뉴 -&amp;gt; Code -&amp;gt; WSGI configuration file 부분 이동 후 오른쪽 패스 선택&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;13. WSGI 설정을 위한 코드 입력&lt;/p&gt;
&lt;pre id=&quot;code_1606205435639&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import os
import sys
path = &quot;/home/junngo/bookmark&quot;
if path not in sys.path:
    sys.path.append(path)

# from django.contrib.staticfiles.handlers import StaticFilesHandler
from django.core.wsgi import get_wsgi_application

os.environ.setdefault(&quot;DJANGO_SETTINGS_MODULE&quot;, &quot;config.settings&quot;)
# application = StaticFilesHandler(get_wsgi_application())
application = get_wsgi_application()
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;14. SAVE&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;15. &lt;span style=&quot;color: #333333;&quot;&gt;Web 메뉴 -&amp;gt; &lt;/span&gt;Virtualenv 가상환경 패스 설정&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;16. setting 파일에 STATIC_ROOT 추가&lt;/p&gt;
&lt;pre id=&quot;code_1606205596022&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;STATIC_ROOT = os.path.join(BASE_DIR, 'static_files')&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/python</category>
      <category>deploy</category>
      <category>Django</category>
      <category>python</category>
      <category>pythonanywhere</category>
      <category>배포</category>
      <category>장고</category>
      <category>파이썬애니웨어</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/238</guid>
      <comments>https://junlab.tistory.com/238#entry238comment</comments>
      <pubDate>Tue, 24 Nov 2020 17:13:57 +0900</pubDate>
    </item>
    <item>
      <title>[git] 깃, 이미 commit 이후에 gitignore 적용이 안될 때</title>
      <link>https://junlab.tistory.com/237</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;git을 사용하면서 제외해야 되는 파일이 있습니다.&lt;/p&gt;
&lt;p&gt;그래서 gitignore 파일에 제외해야 될 파일을 작성을 했습니다.&lt;/p&gt;
&lt;p&gt;git add 그리고 git commit을 했지만 적용이 안 되는 현상이 발생했습니다.&lt;/p&gt;
&lt;p&gt;이럴 때 &amp;lt; git rm -r --cached . &amp;gt; 명령어를 통해서 캐시를 삭제하고 다시 add / commit을 해주시면 되겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1604844583333&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;git rm -r --cached .
git add .
git commit -m 'clear git cache'
git push&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-11-08 23-10-20.png&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;269&quot; width=&quot;650&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c4TYVn/btqMOxSaYKR/i4UA8T2ngX3Da73WneVWX1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c4TYVn/btqMOxSaYKR/i4UA8T2ngX3Da73WneVWX1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c4TYVn/btqMOxSaYKR/i4UA8T2ngX3Da73WneVWX1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc4TYVn%2FbtqMOxSaYKR%2Fi4UA8T2ngX3Da73WneVWX1%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-11-08 23-10-20.png&quot; data-origin-width=&quot;724&quot; data-origin-height=&quot;269&quot; width=&quot;650&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;위의 사진은 실제 위의 명령어를 통해서 gitignore 등록한 파일이 제외된 모습입니다.&lt;/p&gt;
&lt;p&gt;도움이 되셨으면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/Git, Mercurial</category>
      <category>gitignore</category>
      <category>깃</category>
      <category>적용안됨</category>
      <category>적용이 안될 때</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/237</guid>
      <comments>https://junlab.tistory.com/237#entry237comment</comments>
      <pubDate>Sun, 8 Nov 2020 23:10:46 +0900</pubDate>
    </item>
    <item>
      <title>[java] 자바 배열 / 객체 정렬 (comparable, comparator도 같이 알아보자)</title>
      <link>https://junlab.tistory.com/236</link>
      <description>&lt;p&gt;배열에 값을 넣는 방법은 알겠는데 프로그래밍을 하다 보면 배열의 정렬이 때때로 필요로 합니다.&lt;/p&gt;
&lt;p&gt;또한 타입이 객체 타입인 경우에도 원하는 기준대로 정렬을 할 수 있도록 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. 가장 기본적인 원시 타입(int형)인 경우 배열의 오름차순 정렬을 보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1601876454761&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;int[] arr1 = {11, 5, 30, 40, 35, 80, 60};
Arrays.sort(arr1);
for(int i : arr1) {
	System.out.println(i);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;간단합니다. &lt;b&gt;Arrays.sort()함수에 배열을 넘겨&lt;/b&gt;주시면 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;정렬2.PNG&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;144&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Be23D/btqKdES4BoN/0C5zbCU9X4WZ3ooGVqgvA0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Be23D/btqKdES4BoN/0C5zbCU9X4WZ3ooGVqgvA0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Be23D/btqKdES4BoN/0C5zbCU9X4WZ3ooGVqgvA0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FBe23D%2FbtqKdES4BoN%2F0C5zbCU9X4WZ3ooGVqgvA0%2Fimg.png&quot; data-filename=&quot;정렬2.PNG&quot; data-origin-width=&quot;539&quot; data-origin-height=&quot;144&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;정렬1.PNG&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;326&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/CyhBG/btqJ6ci1Stq/DVXb6Mfm6B9Yq5zEKYXywk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/CyhBG/btqJ6ci1Stq/DVXb6Mfm6B9Yq5zEKYXywk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/CyhBG/btqJ6ci1Stq/DVXb6Mfm6B9Yq5zEKYXywk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FCyhBG%2FbtqJ6ci1Stq%2FDVXb6Mfm6B9Yq5zEKYXywk%2Fimg.png&quot; data-filename=&quot;정렬1.PNG&quot; data-origin-width=&quot;716&quot; data-origin-height=&quot;326&quot; width=&quot;500&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;arr1의 배열의 요소가 오름차순으로 정렬된 모습을 보실 수 있습니다.&lt;/p&gt;
&lt;p&gt;sort는 기본 정렬 조건이 오름차순으로 되어 있기 때문에 특별한 코드 없이 오름차순으로 정렬이 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. 내림차순 정렬을 알아보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1601877804615&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;Integer[] arr2 = {11, 5, 30, 40, 35, 80, 60};
// Collections 메소드 사용
Arrays.sort(arr2, Collections.reverseOrder());

// 직접 구현도 가능
Arrays.sort(arr2, new Comparator&amp;lt;Integer&amp;gt;() {
	@Override
	public int compare(Integer i1, Integer i2) {
		return i2 - i1;
	}
});

for(int i : arr2) {
	System.out.println(i);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;내림차순 정렬방법도 오름차순과 동일하게 진행됩니다. 하지만 인자로 내림차순이 될 수 있도록 &lt;b&gt;구현된 C&lt;/b&gt;&lt;span&gt;&lt;b&gt;omparator를 넘겨 주셔야 됩니다&lt;/b&gt;. (Comparator가 무엇인지는 잠시 후에 살펴보겠습니다.) C&lt;span&gt;omparator를 구할 때는 Collections메서드를 사용하시거나 직접 구현을 해주시면 되겠습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;정렬3.PNG&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;520&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zvB84/btqKhld8YLj/ukMXHn8hUEGqckzf0hF51k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zvB84/btqKhld8YLj/ukMXHn8hUEGqckzf0hF51k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zvB84/btqKhld8YLj/ukMXHn8hUEGqckzf0hF51k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzvB84%2FbtqKhld8YLj%2FukMXHn8hUEGqckzf0hF51k%2Fimg.png&quot; data-filename=&quot;정렬3.PNG&quot; data-origin-width=&quot;704&quot; data-origin-height=&quot;520&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. Comparable 와 Comparator는 무엇일까?&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위의 내용으로 배열의 정렬은 하실 수 있습니다. 이제는 정렬을 조금 더 잘 사용할 수 있도록 Comparable과 Comparator를 알아보도록 하겠습니다. 이 둘을 배우고 나면 객체도 정렬을 하실 수 있겠습니다.&lt;/p&gt;
&lt;p&gt;Comparable과 Comparator는 정렬을 위한 인터페이스입니다. 각각의 인터페이스를 구현해서 &quot;구현한 로직대로 정렬을 하겠다&quot;입니다. 위에서 Arrays.sort() 함수를 통해서 정렬을 할 수 있었던 이유는 이미 Comparator가 내부적으로 구현이 되어 있기 때문입니다. 이렇게만 보면 이해가 잘 안 갑니다. 아래의 내용을 살펴보겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. &lt;span style=&quot;color: #333333;&quot;&gt;Comparable&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;Comparable 인터페이스에는 compareTo() 추상 메소드 하나만 존재&lt;/b&gt;합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;정렬4.PNG&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;215&quot; width=&quot;600&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HYPzs/btqJ4H4OPXP/SJpoXkdkuy9OsgItNsS4P1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HYPzs/btqJ4H4OPXP/SJpoXkdkuy9OsgItNsS4P1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HYPzs/btqJ4H4OPXP/SJpoXkdkuy9OsgItNsS4P1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHYPzs%2FbtqJ4H4OPXP%2FSJpoXkdkuy9OsgItNsS4P1%2Fimg.png&quot; data-filename=&quot;정렬4.PNG&quot; data-origin-width=&quot;904&quot; data-origin-height=&quot;215&quot; width=&quot;600&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;주어진 객체(T o) 보다 작으면 음수, 같으면 0, 크면 양수를 리턴&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;이게 무슨말인지 소스 코드를 보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601888014789&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class NameCard implements Comparable&amp;lt;NameCard&amp;gt; {
	public String name;
	public int age;
	
	public NameCard(String name, int age) {
		this.name = name;
		this.age = age;
	}

	@Override
	public int compareTo(NameCard o) {
		if(this.age &amp;lt; o.age) {
			return -1;
		} else if(this.age == o.age) {
			return 0;
		} else {
			return 1;
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NameCard라는 클래스에 Comparable를 구현하였습니다. NameCard를 컬랙션에 줄줄이 넣고 정렬을 한다면 어떻게 하시겠습니까? 정렬의 기준은 어떻게 될까요? &lt;span style=&quot;color: #333333;&quot;&gt;정렬의 기준을 이름으로 할까요? 아니면 나이가 될까요? &lt;/span&gt;정렬의 기준이 없습니다. 그렇기 때문에 정렬의 기준을 정하기 위해서 &lt;span style=&quot;color: #333333;&quot;&gt;Comparable를 구현하는겁니다. 위의 코드를 볼 때 정렬의 기준은 나이(age)가 되겠습니다. 테스트를 하도록 하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1601888343230&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;NameCard&amp;gt; nc = new ArrayList&amp;lt;&amp;gt;();
nc.add(new NameCard(&quot;자바&quot;, 8));
nc.add(new NameCard(&quot;파이썬&quot;, 7));
nc.add(new NameCard(&quot;장고&quot;, 15));
nc.add(new NameCard(&quot;스프링&quot;, 10));

Collections.sort(nc);
for (NameCard obj : nc) {
	System.out.println(obj.name +&quot; &quot;+obj.age);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;NameCard 객체를 리스트에 담아주세요. 그리고 &lt;b&gt;Collections.sort() 함수를 통해서 정렬&lt;/b&gt;을 해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;정렬5.PNG&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;465&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/QIipa/btqKdGDAc9B/OS5w3zHbeibPHMyBQHocS0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/QIipa/btqKdGDAc9B/OS5w3zHbeibPHMyBQHocS0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/QIipa/btqKdGDAc9B/OS5w3zHbeibPHMyBQHocS0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQIipa%2FbtqKdGDAc9B%2FOS5w3zHbeibPHMyBQHocS0%2Fimg.png&quot; data-filename=&quot;정렬5.PNG&quot; data-origin-width=&quot;682&quot; data-origin-height=&quot;465&quot; width=&quot;500&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;오름차순으로 이상 없이 정렬이 된 모습을 보실 수 있습니다. 만약 내림차순을 원하시다면 compareTo 로직을 반대로 변경해주시면 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;5. &lt;b&gt;Comparator&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;comparable 정렬이 일반적이고 객체에 이미 정해진 정렬이라면, &lt;span style=&quot;color: #333333;&quot;&gt;Comparator는 조금 더 복잡하게 정렬도 가능하고 필요할 때마다 구현해서 사용할 수 있는 인터페이스입니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Comparator 인터페이스는 int compare(T t1, T t2)를 구현해주셔야 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;compareTo와 마찮가지로 t1과 t2가 같다면 0, t1이 t2 보다 앞에 오게 하려면 음수, t1이 뒤쪽으로 오게 하려면 양수를 반환하시면 됩니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601889384726&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;List&amp;lt;NameCard&amp;gt; nc = new ArrayList&amp;lt;&amp;gt;();
nc.add(new NameCard(&quot;자바&quot;, 8));
nc.add(new NameCard(&quot;파이썬&quot;, 7));
nc.add(new NameCard(&quot;장고&quot;, 15));
nc.add(new NameCard(&quot;스프링&quot;, 10));

Comparator&amp;lt;NameCard&amp;gt; cp = new Comparator&amp;lt;&amp;gt;() {
	@Override
	public int compare(NameCard n1, NameCard n2) {
		return n2.age - n1.age;
	}
};

Collections.sort(nc, cp);
for (NameCard obj : nc) {
	System.out.println(obj.name +&quot; &quot;+obj.age);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;코드가 조금 다른 점은 Comparator를 구현하고 sort()함수에 인자로 같이 넘겨줬습니다.&lt;/p&gt;
&lt;p&gt;익명 객체라 하여 이름 있는 객체를 만드는 것이 아닌, 객체를 바로 생성하였습니다. 그리고 sort() 함수에 전달을 했는데요. 기존에 NameCard에 comparable이 구현이 되어 있음에도 불구하고 Comparator이 적용된 모습을 보실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;정렬6.PNG&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;616&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zUhep/btqJ6cwRV0N/LIS2zTHOAK7bPfY8C1Pxzk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zUhep/btqJ6cwRV0N/LIS2zTHOAK7bPfY8C1Pxzk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zUhep/btqJ6cwRV0N/LIS2zTHOAK7bPfY8C1Pxzk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzUhep%2FbtqJ6cwRV0N%2FLIS2zTHOAK7bPfY8C1Pxzk%2Fimg.png&quot; data-filename=&quot;정렬6.PNG&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;616&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;Comparator 인터페이스는 코드 작성 중 정렬이 필요할 때마다 위와 같이 익명 객체로 구현해서 적용을 해주시면 더 편리하게 정렬이 가능하겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;감사합니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>Arrays</category>
      <category>comparable</category>
      <category>Comparator</category>
      <category>내림차순</category>
      <category>배열</category>
      <category>오름차순</category>
      <category>자바</category>
      <category>정렬</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/236</guid>
      <comments>https://junlab.tistory.com/236#entry236comment</comments>
      <pubDate>Mon, 5 Oct 2020 14:51:39 +0900</pubDate>
    </item>
    <item>
      <title>[java] 자바 iterator란? 및 예제</title>
      <link>https://junlab.tistory.com/235</link>
      <description>&lt;p&gt;List와 같은 컬랙션에서 요소들을 순차적으로 처리하기 위해서 iterator 반복자가 존재합니다.&lt;/p&gt;
&lt;p&gt;예제를 보고 간단히 살펴보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601807015423&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class IteratorExample {
	public static void main(String[] args) {
		List&amp;lt;String&amp;gt; list = Arrays.asList(&quot;자바&quot;, &quot;파이썬&quot;, &quot;스프링&quot;, &quot;장고&quot;);
		Iterator&amp;lt;String&amp;gt; iterator = list.iterator();
		while(iterator.hasNext()) {
			String name = iterator.next();
			System.out.println(name);
		}
		
		for (String s : list) {
			System.out.println(s);
		}
	}
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;자바 / 파이썬 / 스프링 / 장고 4개의 리스트 요소를 포함하고 있는 리스트를 생성했습니다.&lt;/p&gt;
&lt;p&gt;그리고 iterator() 함수를 통해서 Iterator 반복자를 갖고 옵니다.&lt;/p&gt;
&lt;p&gt;hasnext() 함수를 통해서 항목이 있는지 확인을 하고 next() 함수를 통해서 요소를 하나씩 하나씩 갖고 오면 되겠습니다.&lt;/p&gt;
&lt;p&gt;아래의 for문은 iterator를 사용하지 않고도 for문을 통해서 요소들을 전체 출력을 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;캡처6.PNG&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;578&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0vMU0/btqJ6dVJSOC/yNqT9IDVoOhlwqSKnbrcHK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0vMU0/btqJ6dVJSOC/yNqT9IDVoOhlwqSKnbrcHK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0vMU0/btqJ6dVJSOC/yNqT9IDVoOhlwqSKnbrcHK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0vMU0%2FbtqJ6dVJSOC%2FyNqT9IDVoOhlwqSKnbrcHK%2Fimg.png&quot; data-filename=&quot;캡처6.PNG&quot; data-origin-width=&quot;684&quot; data-origin-height=&quot;578&quot; width=&quot;500&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음으로는 iterator를 활용한 예제를 보도록 하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601807542960&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class Iterators {

    public static class ListIterator&amp;lt;T&amp;gt; implements Iterator&amp;lt;T&amp;gt; {

        private final Iterator&amp;lt;Iterator&amp;lt;T&amp;gt;&amp;gt; listIterator;
        private Iterator&amp;lt;T&amp;gt; currentIterator;

        public ListIterator(List&amp;lt;Iterator&amp;lt;T&amp;gt;&amp;gt; iterators) {
            this.listIterator = iterators.iterator();
            this.currentIterator = listIterator.next();
        }

        @Override
        public boolean hasNext() {
            if(!currentIterator.hasNext()) {
                if (!listIterator.hasNext()) {
                    return false;
                }

                currentIterator = listIterator.next();
                hasNext();
            }

            return true;
        }

        @Override
        public T next() {
            hasNext();
            return currentIterator.next();
        }

        @Override
        public void remove() {
            hasNext();
            currentIterator.remove();
        }
    }

    public static &amp;lt;T&amp;gt; Iterator&amp;lt;T&amp;gt; singleIterator(final List&amp;lt;Iterator&amp;lt;T&amp;gt;&amp;gt; iteratorList) {
        return new ListIterator&amp;lt;&amp;gt;(iteratorList);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;1. singleIterator부터 살펴보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;singleIterator는 정적 메서드이며 Iterator&amp;lt;T&amp;gt; 타입을 리턴합니다.&lt;/p&gt;
&lt;p&gt;위의 ListIterator 클래스는 Iterator를 구현하였으니 &lt;span style=&quot;color: #333333;&quot;&gt;Iterator 타입이겠죠?&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;singleIterator를 호출하면 &lt;span style=&quot;color: #333333;&quot;&gt;ListIterator 객체가 리턴됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;파라미터로는 Iterator&amp;lt;T&amp;gt;으로 구성된 리스트를 인자로 받습니다. 즉, 여러 &lt;span style=&quot;color: #333333;&quot;&gt;(리스트로 만들어지고 난 후에) &lt;/span&gt;Iterator형의 요소들이 존재합니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. ListIterator 클래스를 살펴보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;ListIterator 생성자를 보면 &lt;span style=&quot;color: #333333;&quot;&gt;singleIterator 메서드로부터 받은 &lt;span style=&quot;color: #333333;&quot;&gt;Iterator요소가 담겨 있는 &lt;/span&gt;리스트를 넘겨받아서, &lt;b&gt;리스트의 Iterator를 저장합니다&lt;/b&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;아하, 그러니까 리스트 안에는 Iterator타입의 요소들이 담겨줘 있고, 요소가 아닌 이 리스트의 Iterator를 다시 저장하는 것입니다.&lt;/p&gt;
&lt;p&gt;currentIterator에는 첫 번째 요소를 저장합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. hasNext()를 살펴보겠습니다.&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;currentIterator(현재 이터레이터)의 다음 데이터가 없다면 listIterator.next()를 통해서 다음 요소를 갖고 옵니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;listIterator.hasNext()를 호출할 때 리스트의 다음 요소가 없다면, 더 이상 요소가 존재하지 않습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;span style=&quot;color: #333333;&quot;&gt;currentIterator 다음 데이터가 존재한다면 True가 리턴됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;테스트 코드를 살펴보겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601808411053&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class IteratorsTest {

    @Test
    public void multipleIterators() {
        final Iterator&amp;lt;Integer&amp;gt; a = Arrays.asList(1, 2, 3, 4, 5).iterator();
        final Iterator&amp;lt;Integer&amp;gt; b = Arrays.asList(6).iterator();
        final Iterator&amp;lt;Integer&amp;gt; c = new ArrayList&amp;lt;Integer&amp;gt;().iterator();
        final Iterator&amp;lt;Integer&amp;gt; d = new ArrayList&amp;lt;Integer&amp;gt;().iterator();
        final Iterator&amp;lt;Integer&amp;gt; e = Arrays.asList(7, 8, 9).iterator();

        final Iterator&amp;lt;Integer&amp;gt; singleIterator = Iterators.singleIterator(Arrays.asList(a, b, c, d, e));

        assertTrue(singleIterator.hasNext());
        for (Integer i = 1; i &amp;lt; 10; i++) {
            assertEquals(i, singleIterator.next());
        }
        assertFalse(singleIterator.hasNext());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;a, b, c, d, e 각각의 Iterator 타입의 변수를 만들었습니다. 그리고 이 각각의 변수들을 List 요소에 넣고 singleIterator 메서드를 호출했습니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;singleIterator 변수에 &lt;/span&gt;Iterator가 리턴이 되고, 이를 활용하여 각각의 요소들 별로 데이터를 추출하는 예제입니다.&lt;/p&gt;
&lt;p&gt;즉, &lt;b&gt;하나의 Iterator 인터페이스로 여러 개의 Iterator를 다루는 예제&lt;/b&gt;입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; width=&quot;700&quot; data-filename=&quot;캡처7.PNG&quot; data-origin-width=&quot;1310&quot; data-origin-height=&quot;455&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cNtaNE/btqJ92e6lhM/F46AaRjuXgNf3ZLZ0caSKk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cNtaNE/btqJ92e6lhM/F46AaRjuXgNf3ZLZ0caSKk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cNtaNE/btqJ92e6lhM/F46AaRjuXgNf3ZLZ0caSKk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcNtaNE%2FbtqJ92e6lhM%2FF46AaRjuXgNf3ZLZ0caSKk%2Fimg.png&quot; width=&quot;700&quot; data-filename=&quot;캡처7.PNG&quot; data-origin-width=&quot;1310&quot; data-origin-height=&quot;455&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;도움이 되셨으면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다 :)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;참고)&lt;/p&gt;
&lt;p&gt;[예제] - JAVA 프로그래밍 면접 이렇게 준비한다&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>Iterator</category>
      <category>java</category>
      <category>반복자</category>
      <category>예제</category>
      <category>이터레이터</category>
      <category>자바</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/235</guid>
      <comments>https://junlab.tistory.com/235#entry235comment</comments>
      <pubDate>Sun, 4 Oct 2020 20:01:38 +0900</pubDate>
    </item>
    <item>
      <title>[java] 자바, 간략하게 알아보는 WeakReference</title>
      <link>https://junlab.tistory.com/234</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;WeakReference에 대해서 간략하게 알아보고 예제를 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;WeakReference는 클래스입니다 :) &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;그리고 GC(Garbage Collector)와 밀접한 연관성이 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;GC는 개발자의 영역이 아닌데 &lt;span style=&quot;color: #333333;&quot;&gt;WeakReference을 사용함으로써 GC에게 어느정도 개입을 할 수가 있습니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;GC는 불필요한 객체(참조하고 있지 않는)들을 힙 메모리에서 제거를 해줍니다. 특정 객체가 &lt;span style=&quot;color: #333333;&quot;&gt;Weak Reference(약한 참조) 상태가 되면 GC는 이 객체를 제거를 합니다. 빠르게 객체를 제거함으로써 잠깐 사용하고 제거를 할 수 있는 것이죠.&lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;new를 사용하여 객체를 만들때는 강한 Reference가 적용이 되는데, &lt;span style=&quot;color: #333333;&quot;&gt;WeakReference를 사용하여 객체를 만들 때는 약한 Reference가 적용이 됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;예제를 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1601799645396&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;    @Test
    public void weakReferenceStackManipulation() {
        final WeakReferenceStack&amp;lt;ValueContainer&amp;gt; stack = new WeakReferenceStack&amp;lt;&amp;gt;();

        final ValueContainer expected = new ValueContainer(&quot;Value for the stack&quot;);
        stack.push(new ValueContainer(&quot;Value for the stack&quot;));

        ValueContainer peekedValue = stack.peek();
        assertEquals(expected, peekedValue);
        assertEquals(expected, stack.peek());
        peekedValue = null;
        System.gc();
        assertNull(&quot;Fail&quot;, stack.peek());
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 예제는 stack을 &lt;span style=&quot;color: #333333;&quot;&gt;WeakReference형으로 선언하였습니다. &lt;span style=&quot;color: #333333;&quot;&gt;WeakReference은 ValueContainer을 &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;래퍼해줍니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;ValueContainer 객체를 생성하고, 이 객체를 stack에 집어넣었습니다.&lt;/p&gt;
&lt;p&gt;그리고 두 값을 비교하면 같은 값이 됩니다.&lt;/p&gt;
&lt;p&gt;이때 peekedValue는&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;&lt;b&gt;WeakReference 형으로 선언된 값을 참조하기 때문에&lt;/b&gt;, peekedValue 값에 null을 대입하면 &lt;span style=&quot;color: #333333;&quot;&gt;WeakReference&lt;span&gt; 형으로 선언된 객체는 GC가 동작될 때 제거됩니다. 그렇기 때문에 stack 값을 갖고 오면 stack에 값이 있을 것으로 생각이 되지만 GC에 의해서 이미 제거되어 null이 됩니다.&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;GC가 동작하지 않았더라면(System.gc() 주석 처리), GC가 동작하기 전까지는 null값이 아니기 때문에 마지막 테스트는 실패하게 됩니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;캡처5.PNG&quot; data-origin-width=&quot;819&quot; data-origin-height=&quot;232&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ACHj1/btqJ1KUjHKu/F7BLOTI1IK20Ka7exSk780/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ACHj1/btqJ1KUjHKu/F7BLOTI1IK20Ka7exSk780/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ACHj1/btqJ1KUjHKu/F7BLOTI1IK20Ka7exSk780/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FACHj1%2FbtqJ1KUjHKu%2FF7BLOTI1IK20Ka7exSk780%2Fimg.png&quot; data-filename=&quot;캡처5.PNG&quot; data-origin-width=&quot;819&quot; data-origin-height=&quot;232&quot; width=&quot;750&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;span style=&quot;color: #333333;&quot;&gt;LRU 캐시처럼 &lt;/span&gt;객체를 짧게 사용하는 곳에서는 WeakReference가 유용할 수 있겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>gc</category>
      <category>java</category>
      <category>WeakReference</category>
      <category>자바</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/234</guid>
      <comments>https://junlab.tistory.com/234#entry234comment</comments>
      <pubDate>Sun, 4 Oct 2020 17:25:09 +0900</pubDate>
    </item>
    <item>
      <title>[java] 자바 JUnit 테스트 순서 및 핵심 메서드 (단계, 생명주기)</title>
      <link>https://junlab.tistory.com/233</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;JUnit의 생명주기, 즉 테스트가 수행되는 순서를 알아보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;테스트 코드.PNG&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;611&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cn0uh1/btqJWRkOPsN/0t6yqWu8cwSVP7IbLW3FI0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cn0uh1/btqJWRkOPsN/0t6yqWu8cwSVP7IbLW3FI0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cn0uh1/btqJWRkOPsN/0t6yqWu8cwSVP7IbLW3FI0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcn0uh1%2FbtqJWRkOPsN%2F0t6yqWu8cwSVP7IbLW3FI0%2Fimg.png&quot; data-filename=&quot;테스트 코드.PNG&quot; data-origin-width=&quot;1099&quot; data-origin-height=&quot;611&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;JUnit 순서&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;테스트가 수행될 때는 @Test 만 수행되는 것이 아닌 @BeforeClass, 생성자, @Before, @AfterClass 가 존재합니다.&lt;/p&gt;
&lt;p&gt;생명주기를 이해하기 쉬운 방법 중 하나는 카운터를 세는 코드를 작성하시면 조금도 쉽게 이해할 수 있습니다.&lt;/p&gt;
&lt;p&gt;일단 코드를 먼저 작성하겠습니다. (테스트 코드 기준은 JUnit4 입니다.)&lt;/p&gt;
&lt;pre id=&quot;code_1601472464154&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;public class JUnitLifecycle {
    private static int counter = 0;

    @BeforeClass
    public static void suiteSetup() {
        assertEquals(0, counter);
        counter++;
    }

    public JUnitLifecycle() {
        assertTrue(Arrays.asList(1, 5).contains(counter));
        counter++;
    }

    @Before
    public void prepareTest() {
        assertTrue(Arrays.asList(2, 6).contains(counter));
        counter++;
    }

    @Test
    public void peformFirstTest() {
        assertTrue(Arrays.asList(3, 7).contains(counter));
        counter++;
    }

    @Test
    public void performSecondTest() {
        assertTrue(Arrays.asList(3, 7).contains(counter));
        counter++;
    }

    @After
    public void cleanupTest() {
        assertTrue(Arrays.asList(4, 8).contains(counter));
        counter++;
    }

    @AfterClass
    public static void suiteFinished() {
        assertEquals(9, counter);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;1. @BeforeClass&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;테스트 &lt;b&gt;클래스&lt;/b&gt; 시작 시 &lt;b&gt;한번만&lt;/b&gt; 수행&lt;/p&gt;
&lt;p&gt;-------------------------------------------------&lt;/p&gt;
&lt;p&gt;&lt;b&gt;2. 생성자&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;- 테스트 &lt;b&gt;케이스&lt;/b&gt; 시작 전 호출&lt;/p&gt;
&lt;p&gt;- (@Before/@After 이외에도 생성자도 호출이 되는 걸 인지해주세요)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. @Before&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- 테스트 &lt;b&gt;케이스&lt;/b&gt; 시작 전 호출&lt;/span&gt;&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;&lt;b&gt;4. @Test&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- 테스트 케이스&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;- public이고 void 타입 값으로 반환&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;5. @After&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;테스트 케이스 &lt;b&gt;종료 후&lt;/b&gt; 호출&lt;/p&gt;
&lt;p&gt;- 테스트 후 정리&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;-------------------------------------------------&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;6. @AfterClass&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;모든 테스트 케이스 완료 후, 테스트 클래스 종료 전 수행&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;마지막 AfterClass 종료 시 카운터는 9인걸 보실 수 있습니다. 이유는 @Test(테스트 케이스)가 2번 호출이 되어 생성자와 @Before/@After 가 다시 한번 호출이 되었기 때문입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;핵심 메소드&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1601473612939&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;assertEquals 			// 두개의 객체가 같은지 확인
assertTrue / asertFalse	// Boolean 결과값 확인
assertNotNull			// 객체가 Null이 아닌지 확인
assertArrayEquals		// 두 배열의 값이 같은지 확인&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;테스트 코드를 작성하기 위해서는 생각보다 많은 지식이 필요한 것은 아닙니다.&lt;/p&gt;
&lt;p&gt;테스트 코드를 작성하기 어려운 프로젝트는 이미 개발이 많이 되어 있으며 모듈(함수/클래스) 단위가 커서 테스트 코드를 작성하기 어려운 소스코드가 존재할 때가 오히려 테스트 작성이 어렵습니다.&lt;/p&gt;
&lt;p&gt;그렇기에 시작부터 프로그래밍을 하실 때는 항상 테스트코드를 생활화 하셔야겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;학습을 통해서 생명주기와, 핵심 메소드를 익혔습니다. 이제는 직접 테스트 코드를 작성하실 수 있겠습니다 :)&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>java</category>
      <category>junit</category>
      <category>test 순서</category>
      <category>생명주기</category>
      <category>자바</category>
      <category>테스</category>
      <category>테스트</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/233</guid>
      <comments>https://junlab.tistory.com/233#entry233comment</comments>
      <pubDate>Wed, 30 Sep 2020 22:51:11 +0900</pubDate>
    </item>
    <item>
      <title>[java] 자바 JUnit 에러 java.lang.NoClassDefFoundError</title>
      <link>https://junlab.tistory.com/232</link>
      <description>&lt;p&gt;라이브러리에 JUnit을 추가 이후에 테스트를 실행했더니 다음과 같은 에러가 발생했습니다.&lt;/p&gt;
&lt;p&gt;가장 기본적인 테스트 코드인데도 불구하고... 에러가 발생을 했네요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;캡처1.PNG&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;65&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/YUEYQ/btqJWq8HZNN/K5qmEPkLfd6PG9OeqSRjO0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/YUEYQ/btqJWq8HZNN/K5qmEPkLfd6PG9OeqSRjO0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/YUEYQ/btqJWq8HZNN/K5qmEPkLfd6PG9OeqSRjO0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FYUEYQ%2FbtqJWq8HZNN%2FK5qmEPkLfd6PG9OeqSRjO0%2Fimg.png&quot; data-filename=&quot;캡처1.PNG&quot; data-origin-width=&quot;743&quot; data-origin-height=&quot;65&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;java.lang.NoClassDefFoundError: org/junit/runner/manipulation/Filter&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;에러가 발생한 이유는 환경설정에 문제가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;JUnit을 추가하실 때 Modulepath에 추가하셨기 때문에 문제가 발생&lt;/b&gt;합니다.&lt;/p&gt;
&lt;p&gt;환경설정 들어가는 방법은 프로젝트 우클릭 -&amp;gt; Properties -&amp;gt; Java Build Path -&amp;gt; Libraries 입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;캡처2.PNG&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;496&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/0JciJ/btqJUObTapp/Uvq2ktay3Ais8Bz3vKkKuK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/0JciJ/btqJUObTapp/Uvq2ktay3Ais8Bz3vKkKuK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/0JciJ/btqJUObTapp/Uvq2ktay3Ais8Bz3vKkKuK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F0JciJ%2FbtqJUObTapp%2FUvq2ktay3Ais8Bz3vKkKuK%2Fimg.png&quot; data-filename=&quot;캡처2.PNG&quot; data-origin-width=&quot;1044&quot; data-origin-height=&quot;496&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Modulepath가 아닌 &lt;b&gt;Classpath에 JUnit을 추가&lt;/b&gt;해주세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;캡처3.PNG&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;616&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/lBDyN/btqJV7axSrb/MqFKPDqIvK8LQaO89bcu4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/lBDyN/btqJV7axSrb/MqFKPDqIvK8LQaO89bcu4K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/lBDyN/btqJV7axSrb/MqFKPDqIvK8LQaO89bcu4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FlBDyN%2FbtqJV7axSrb%2FMqFKPDqIvK8LQaO89bcu4K%2Fimg.png&quot; data-filename=&quot;캡처3.PNG&quot; data-origin-width=&quot;1050&quot; data-origin-height=&quot;616&quot; width=&quot;750&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위 사진 처럼 Classpath에 추가를 해주시면 문제가 해결되겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>java</category>
      <category>junit</category>
      <category>NoClassDefFoundError</category>
      <category>세팅</category>
      <category>에러</category>
      <category>이클립스</category>
      <category>자바</category>
      <category>환경설정</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/232</guid>
      <comments>https://junlab.tistory.com/232#entry232comment</comments>
      <pubDate>Wed, 30 Sep 2020 18:12:22 +0900</pubDate>
    </item>
    <item>
      <title>[docker] 도커 실행 중인 전체 컨테이너 중지, 일괄 삭제 (prune)</title>
      <link>https://junlab.tistory.com/229</link>
      <description>&lt;p&gt;&lt;b&gt;실행 중인 컨테이너 중지&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596465300508&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo docker stop $(sudo docker ps -aq)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-02 00-22-19.png&quot; data-origin-width=&quot;425&quot; data-origin-height=&quot;145&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bog9dm/btqGbrqTKvm/4KGtOYFpi0aWt6P2ml6vkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bog9dm/btqGbrqTKvm/4KGtOYFpi0aWt6P2ml6vkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bog9dm/btqGbrqTKvm/4KGtOYFpi0aWt6P2ml6vkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbog9dm%2FbtqGbrqTKvm%2F4KGtOYFpi0aWt6P2ml6vkK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-02 00-22-19.png&quot; data-origin-width=&quot;425&quot; data-origin-height=&quot;145&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;실행 중인 컨테이너를 제외한 모든 컨테이너 삭제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596465315132&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker container prune&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;모든 이미지 삭제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596465325540&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image prune&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;도커 이미지, 컨테이너, 볼륨, 네트워크 등 모든 도커 리소스 일괄 삭제&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596465338090&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker system prune&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-02 00-19-46.png&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;124&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bMzs1Y/btqGd1qPk2A/ADc68ZfRC5LpNWZXTaZhSK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bMzs1Y/btqGd1qPk2A/ADc68ZfRC5LpNWZXTaZhSK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bMzs1Y/btqGd1qPk2A/ADc68ZfRC5LpNWZXTaZhSK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbMzs1Y%2FbtqGd1qPk2A%2FADc68ZfRC5LpNWZXTaZhSK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-02 00-19-46.png&quot; data-origin-width=&quot;468&quot; data-origin-height=&quot;124&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>도커</category>
      <category>삭제</category>
      <category>이미지</category>
      <category>중지</category>
      <category>컨테이너</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/229</guid>
      <comments>https://junlab.tistory.com/229#entry229comment</comments>
      <pubDate>Sun, 2 Aug 2020 00:23:45 +0900</pubDate>
    </item>
    <item>
      <title>[java] 리눅스 우분투 버전별로 자바 6, 7, 9 설치 및 관리(버전 확인)</title>
      <link>https://junlab.tistory.com/225</link>
      <description>&lt;p&gt;현재 우분투에 자바 8 버전이 설치가 되어 있습니다.&lt;/p&gt;
&lt;p&gt;자바 6 ,7, 9 버전도 필요로 하여 각각 설치를 하고 자바 버전을 어떻게 변경하는지 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바 6 버전 (bin 파일)&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;1. 바이너리 파일 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase-java-archive-javase6-downloads.html#jdk-6u45-oth-JPR&quot;&gt;https://www.oracle.com/java/technologies/javase-java-archive-javase6-downloads.html#jdk-6u45-oth-JPR&lt;/a&gt;&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;현재 실행권이 없어 권한 변경&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-01 09-27-24.png&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;58&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNAUp8/btqF9lYXies/lgEwSNckiNhKhrbiDa4jbK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNAUp8/btqF9lYXies/lgEwSNckiNhKhrbiDa4jbK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNAUp8/btqF9lYXies/lgEwSNckiNhKhrbiDa4jbK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNAUp8%2FbtqF9lYXies%2FlgEwSNckiNhKhrbiDa4jbK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-01 09-27-24.png&quot; data-origin-width=&quot;586&quot; data-origin-height=&quot;58&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596335099075&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo chmod +x jdk-6u45-linux-x64.bin(파일이름)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-01 09-28-29.png&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;18&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bgrRQU/btqGdDp75Do/AvUE4oxvH3NZpgZ71iEte0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bgrRQU/btqGdDp75Do/AvUE4oxvH3NZpgZ71iEte0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bgrRQU/btqGdDp75Do/AvUE4oxvH3NZpgZ71iEte0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbgrRQU%2FbtqGdDp75Do%2FAvUE4oxvH3NZpgZ71iEte0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-01 09-28-29.png&quot; data-origin-width=&quot;457&quot; data-origin-height=&quot;18&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;권한 변경 후 확인을 하면 실행권이 주어진 걸 보실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-01 09-28-46.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;56&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IOG3A/btqGbOlzVwR/k2xPlVKcW2iyRcJlPODmzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IOG3A/btqGbOlzVwR/k2xPlVKcW2iyRcJlPODmzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IOG3A/btqGbOlzVwR/k2xPlVKcW2iyRcJlPODmzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIOG3A%2FbtqGbOlzVwR%2Fk2xPlVKcW2iyRcJlPODmzK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-01 09-28-46.png&quot; data-origin-width=&quot;582&quot; data-origin-height=&quot;56&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;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-01 09-29-16.png&quot; data-origin-width=&quot;347&quot; data-origin-height=&quot;18&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IwAAl/btqF9baze6x/2Yz4ayqJDSSDMojKxkwAu0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IwAAl/btqF9baze6x/2Yz4ayqJDSSDMojKxkwAu0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IwAAl/btqF9baze6x/2Yz4ayqJDSSDMojKxkwAu0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIwAAl%2FbtqF9baze6x%2F2Yz4ayqJDSSDMojKxkwAu0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-01 09-29-16.png&quot; data-origin-width=&quot;347&quot; data-origin-height=&quot;18&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1596335141735&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./jdk-6u45-linux-x64.bin&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바 7 버전(tar 파일)&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;1. tar 파일 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html#jdk-7u80-oth-JPR&quot;&gt;https://www.oracle.com/java/technologies/javase/javase7-archive-downloads.html#jdk-7u80-oth-JPR&lt;/a&gt;&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;pre id=&quot;code_1596335174829&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo tar xvf jdk-7u80-linux-x64.tar.gz&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위의 5, 6 버전을 실행하고 나면 각각의 디렉터리가 만들어집니다. (아래 9 버전까지 압축을 풀어주면 9 버전까지 존재합니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-01 09-48-05.png&quot; data-origin-width=&quot;224&quot; data-origin-height=&quot;37&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dxZgcs/btqGdsI5rKG/t7OiGxg0j8e1ZGXp2SlzI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dxZgcs/btqGdsI5rKG/t7OiGxg0j8e1ZGXp2SlzI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dxZgcs/btqGdsI5rKG/t7OiGxg0j8e1ZGXp2SlzI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdxZgcs%2FbtqGdsI5rKG%2Ft7OiGxg0j8e1ZGXp2SlzI1%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-01 09-48-05.png&quot; data-origin-width=&quot;224&quot; data-origin-height=&quot;37&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;자바 9 버전(tar 파일)&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;1. tar 파일 다운로드&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://jdk.java.net/archive/&quot;&gt;http://jdk.java.net/archive/&lt;/a&gt;&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;sudo tar xvf&amp;nbsp;&lt;a href=&quot;http://openjdk-9.0.4_linux-x64_bin.tar.gz&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt;openjdk-9.0.4_linux-x64_bin.tar.gz&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;각각의 자바 버전 세팅&lt;/h3&gt;
&lt;p&gt;&lt;b&gt;1. 각각의 디렉터리를 우분투 jvm관리를 해주는 디렉터리로 복사를 해줍니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596335472638&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo cp -r jdk1.6.0_45/ /usr/lib/jvm/java-6-amd64
sudo cp -r jdk1.7.0_80/ /usr/lib/jvm/java-7-amd64
sudo cp -r jdk-9.0.4/ /usr/lib/jvm/java-9-openjdk-amd64&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;2. 이제는 아래 명령어를 통해서 설치를 진행해주세요&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596335285833&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-6-amd64/bin/java 6
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-6-amd64/bin/javac 6
sudo update-alternatives --install /usr/bin/javaws javaws /usr/lib/jvm/java-6-amd64/bin/javaws 6

sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-7-amd64/bin/java 7
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-7-amd64/bin/javac 7
sudo update-alternatives --install /usr/bin/javaws javaws /usr/lib/jvm/java-7-amd64/bin/javaws 7

sudo update-alternatives --install /usr/bin/java java /usr/lib/jvm/java-9-openjdk-amd64/bin/java 9
sudo update-alternatives --install /usr/bin/javac javac /usr/lib/jvm/java-9-openjdk-amd64/bin/javac 9
sudo update-alternatives --install /usr/bin/javaws javaws /usr/lib/jvm/java-9-openjdk-amd64/bin/javaws 9&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;끝에 숫자는 겹치지 않는 임의 숫자를 입력해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3. 아래 명령어를 통해서 자바 버전을 변경해주실 수 있습니다.&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596335324388&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo update-alternatives --config javac
sudo update-alternatives --config java
sudo update-alternatives --config javws&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-01 10-16-30.png&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;271&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qptPm/btqGbN1hPhW/6LgCUP97MwQ9m5XwLDiGe1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qptPm/btqGbN1hPhW/6LgCUP97MwQ9m5XwLDiGe1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qptPm/btqGbN1hPhW/6LgCUP97MwQ9m5XwLDiGe1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqptPm%2FbtqGbN1hPhW%2F6LgCUP97MwQ9m5XwLDiGe1%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-01 10-16-30.png&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;271&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;4. 마지막으로 자바 버전 확인&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1596335341306&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;java -version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;명령어를 통해서 버전을 확인해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-08-01 10-18-12.png&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;73&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b6CDBq/btqF9ClS0Q4/DkxKZoimK0gR4eCPHGwakk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b6CDBq/btqF9ClS0Q4/DkxKZoimK0gR4eCPHGwakk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b6CDBq/btqF9ClS0Q4/DkxKZoimK0gR4eCPHGwakk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb6CDBq%2FbtqF9ClS0Q4%2FDkxKZoimK0gR4eCPHGwakk%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-08-01 10-18-12.png&quot; data-origin-width=&quot;607&quot; data-origin-height=&quot;73&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;</description>
      <category>Programming/JAVA</category>
      <category>java</category>
      <category>리눅스</category>
      <category>설치</category>
      <category>우분투</category>
      <category>자바</category>
      <category>자바 6</category>
      <category>자바 7</category>
      <category>자바 9</category>
      <category>자바 버전 관리</category>
      <category>자바 버전 확인</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/225</guid>
      <comments>https://junlab.tistory.com/225#entry225comment</comments>
      <pubDate>Sat, 1 Aug 2020 09:47:42 +0900</pubDate>
    </item>
    <item>
      <title>[java] error variable name not initialized in the default constructor (자바 그레이들 에러)</title>
      <link>https://junlab.tistory.com/224</link>
      <description>&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;테스트 코드 실행 중 다음과 같은 에러가 발생했습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;error:&amp;nbsp;variable&amp;nbsp;name&amp;nbsp;not&amp;nbsp;initialized&amp;nbsp;in&amp;nbsp;the&amp;nbsp;default&amp;nbsp;constructor&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-07-11 00-57-15.png&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;262&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/ysBG2/btqFz3iNWU2/cnjyGoxLbkbl796ZhdB4n1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/ysBG2/btqFz3iNWU2/cnjyGoxLbkbl796ZhdB4n1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/ysBG2/btqFz3iNWU2/cnjyGoxLbkbl796ZhdB4n1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FysBG2%2FbtqFz3iNWU2%2FcnjyGoxLbkbl796ZhdB4n1%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-07-11 00-57-15.png&quot; data-origin-width=&quot;1356&quot; data-origin-height=&quot;262&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;그레이들 버전이 맞지 않아 발생하는 에러였습니다.&lt;/p&gt;
&lt;p&gt;그레이들 버전을 4.x으로 낮춰주면서 이상 없이 문제를 해결 했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-07-11 01-03-40.png&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;28&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/O4fXd/btqFArjbOv3/FWlQmEOMrVAO2kt3p9Spuk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/O4fXd/btqFArjbOv3/FWlQmEOMrVAO2kt3p9Spuk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/O4fXd/btqFArjbOv3/FWlQmEOMrVAO2kt3p9Spuk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FO4fXd%2FbtqFArjbOv3%2FFWlQmEOMrVAO2kt3p9Spuk%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-07-11 01-03-40.png&quot; data-origin-width=&quot;552&quot; data-origin-height=&quot;28&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 id=&quot;code_1596334709387&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;./gradlew wrapper --gradle-version 4.10.2&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>Programming/JAVA</category>
      <category>error</category>
      <category>gradle</category>
      <category>java</category>
      <category>variable name not initialized</category>
      <category>그레이들</category>
      <category>버전</category>
      <category>에러</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/224</guid>
      <comments>https://junlab.tistory.com/224#entry224comment</comments>
      <pubDate>Sat, 11 Jul 2020 01:05:02 +0900</pubDate>
    </item>
    <item>
      <title>[it/개발] 책 리뷰 - 모두의 알고리즘 with 파이썬 (알고리즘 공부법)</title>
      <link>https://junlab.tistory.com/223</link>
      <description>&lt;p&gt;알고리즘 공부를 시작하기 위해서 읽은 책입니다.&lt;/p&gt;
&lt;p&gt;책 이름은 &lt;b&gt;모두의 알고리즘 with 파이썬&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;모두의알고리즘_수정.jpg&quot; data-origin-width=&quot;5472&quot; data-origin-height=&quot;3832&quot; width=&quot;600&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bak0GO/btqFjFvhe1w/4UyoHkTWQSfow3nOLofGZ1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bak0GO/btqFjFvhe1w/4UyoHkTWQSfow3nOLofGZ1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bak0GO/btqFjFvhe1w/4UyoHkTWQSfow3nOLofGZ1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbak0GO%2FbtqFjFvhe1w%2F4UyoHkTWQSfow3nOLofGZ1%2Fimg.jpg&quot; data-filename=&quot;모두의알고리즘_수정.jpg&quot; data-origin-width=&quot;5472&quot; data-origin-height=&quot;3832&quot; width=&quot;600&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;총 18문제를 풀어봅니다. 내용은 알고리즘 문제를 풀기 위한 필수 내용들로 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;기초내용 / 재귀 함수 / 탐색과 정렬 / 자료구조(스택, 큐, 딕셔너리, 그래프)로 구성되어 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;각각의 내용들을 학습하고 학습한 내용을 기반으로 문제들을 풀어봅니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;책 내용은 다른 알고리즘 책들에 비해서 어렵지 않습니다. 처음 알고리즘 시작을 하시는 분이라면 물론 어려우실 수도 있습니다. 하지만 &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;위의 책 내용은 &lt;/span&gt;알고리즘 문제를 풀기 위한 필수적인 내용들입니다. 내용들을 숙지하고 반복하고 또 반복하셔야 됩니다. 그렇게 될 때 책 이외의 다른 문제들도 풀어 나갈 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;* 알고리즘 공부 시작법&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;알고리즘 공부를 시작하겠다고 마음먹고 많은 이들이 범하는 오류가 있습니다.&lt;/p&gt;
&lt;p&gt;알고리즘을 공부한다면서 정말 두꺼운 책부터 보고 있는 것입니다. 또 그런 책들은 처음 공부할 때 내용이 쉽지도 않습니다. 두꺼운 책을 펴고 50 페이지, 70 페이지 보고 나서 더 이상 안 열어 봅니다. 그렇게 알고리즘을 공부하겠다는 마음가짐이 사라집니다.&lt;/p&gt;
&lt;p&gt;그렇기에 처음 알고리즘 공부를 하신다면 위의 책처럼 내용이 조금 쉽고(다른 책에 비해서입니다) 끝까지 보고 정리를 할 수 있는 책을 추천드립니다.&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;이런 책의 내용들을 모르고 다른 사이트의 알고리즘 문제들을 풀어 나간다면 접근조차도 못하는 경우가 생깁니다. 각각의 파트를 숙지하고 나면 이 지식기반으로 문제들을 접근할 수 있는 힘이 생깁니다. 그리고 고민하고 코드를 작성하시면서 문제를 풀어 나가시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;이런 힘을 키우기 위해서는 책 한 권 끝까지 보는건 정말 필수입니다. 알고리즘 기본서적을 한권 골라서 문제해결 지식 기반을 쌓고 알고리즘 문제들을 풀어 나가시면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;* 정리&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;1. 쉬운 알고리즘 책을 한권 선택&lt;/p&gt;
&lt;p&gt;2. 책 내용을 끝가지 보고 충분히 숙지한다 (개념 / 코드)&lt;/p&gt;
&lt;p&gt;3. 적절한 알고리즘 사이트를 찾는다&lt;/p&gt;
&lt;p&gt;4. 쉬운 문제부터 알고리즘 문제를 풀어 본다&lt;/p&gt;
&lt;p&gt;5. 문제를 접근할 때는 우리가 학습한 내용을 기반으로 접근을 하며 풀어 나가자&lt;br /&gt;ex) 아, 이문제는 해시 테이블로 문제를 풀어보면 되겠구나!!&lt;/p&gt;</description>
      <category>Book</category>
      <category>공부법</category>
      <category>모두의</category>
      <category>알고리즘</category>
      <category>알고리즘 공부</category>
      <category>알고리즘 책</category>
      <category>책</category>
      <category>책 추천</category>
      <category>책리뷰</category>
      <category>파이썬</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/223</guid>
      <comments>https://junlab.tistory.com/223#entry223comment</comments>
      <pubDate>Thu, 2 Jul 2020 12:00:45 +0900</pubDate>
    </item>
    <item>
      <title>[it/개발] 책 리뷰 - 알고리즘 도감(그림으로 배우는 알고리즘 26)</title>
      <link>https://junlab.tistory.com/222</link>
      <description>&lt;p&gt;알고리즘 공부를 위해서 읽은 책입니다.&lt;/p&gt;
&lt;p&gt;알고리즘 도감 (그림으로 배우는 알고리즘 26)이라는 책입니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-origin-width=&quot;5436&quot; data-origin-height=&quot;3820&quot; data-filename=&quot;알고리즘 도감_수정.jpg&quot; width=&quot;600&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pwHWS/btqFedenZUh/ITtsUWWhb8WIJChd6ZXkk1/img.jpg&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pwHWS/btqFedenZUh/ITtsUWWhb8WIJChd6ZXkk1/img.jpg&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pwHWS/btqFedenZUh/ITtsUWWhb8WIJChd6ZXkk1/img.jpg&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpwHWS%2FbtqFedenZUh%2FITtsUWWhb8WIJChd6ZXkk1%2Fimg.jpg&quot; data-origin-width=&quot;5436&quot; data-origin-height=&quot;3820&quot; data-filename=&quot;알고리즘 도감_수정.jpg&quot; width=&quot;600&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;다른 파트들도 괜찮은데, 개인적으로 정말 괜찮다 싶은 파트는 보안 파트였습니다. 개발 시작 당시 공개키-개인키 관련 지식들에 대해서&amp;nbsp;&lt;span style=&quot;color: #333333;&quot;&gt;인터넷에 글로 된 지식들을 배우며 미심쩍은 부분이 많았었습니다. 그 당시 지금의 책을 봤으면 조금 더 쉽게 이해를 했겠구나 라는 생각이 듭니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;책 내용을 보시게 되면 코드 내용은 한 줄도 없습니다. 하지만 알고리즘 코드를 보기 전에 알고리즘에 대한 이해는 필수입니다. 이런 이해를 돕기 위해서 알고리즘 학습을 또는 개발을 처음 시작하신다면 추천하는 책입니다. &lt;/span&gt;&lt;span style=&quot;color: #333333;&quot;&gt;알고리즘을 정말 이해하기 쉽게 설명이 되어 있습니다 :)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;지금의 책으로 기반 지식을 쌓고 알고리즘 책들과 문제들을 하나 둘 배우신다면 효과적으로 알고리즘 학습을 이해하실 수 있으리라 생각이 됩니다. 처음부터 너무 어려운 책을 보거나 두꺼운 책을 보시게 된다면 끝까지 책을 못 볼 경우가 발생합니다. 그렇기에 쉬운 책부터 하나 둘 끝까지 학습하셨으면 하는데요. 책을 3권 4권 읽었는데 앞에 30장 50장만 읽었다면 리스트, 큐 파트만 학습을 하시게 된 겁니다. 끝까지 읽음으로써 모든 개념들을 한 바퀴 학습하시면 더 큰 의미가 있겠습니다.&lt;/span&gt;&lt;/p&gt;</description>
      <category>Book</category>
      <category>개발</category>
      <category>그림으로</category>
      <category>배우는</category>
      <category>알고리즘</category>
      <category>알고리즘 도감</category>
      <category>알고리즘 책</category>
      <category>책</category>
      <category>책 리뷰</category>
      <category>책 추천</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/222</guid>
      <comments>https://junlab.tistory.com/222#entry222comment</comments>
      <pubDate>Mon, 29 Jun 2020 11:25:20 +0900</pubDate>
    </item>
    <item>
      <title>[docker] 도커 컴포즈 사용법 및 젠킨스 설치&amp;amp;실습(여러 컨테이너 활용)</title>
      <link>https://junlab.tistory.com/220</link>
      <description>&lt;p&gt;앞 포스트에서는 도커 컴포즈가 무엇이고 어떻게 스크립트를 작성하는지 알아봤습니다. 도커 컴포즈에 대해서 잘 모르겠다 싶으시면 앞의 포스트를 확인해주세요. &lt;a href=&quot;https://junlab.tistory.com/219&quot;&gt;https://junlab.tistory.com/219&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1591936876798&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[docker] 도커 컴포즈란? 예제 및 기본 사용법 (docker-compose)&quot; data-og-description=&quot;도커 컴포즈를 알아보기 위해서는 기본적인 도커의 사용 이유와 예제 및 구동 방법을 알고 있으셔야 됩니다. 기본 내용은 앞의 게시물을 확인해주세요 :) - https://junlab.tistory.com/216 [docker] 도커 사&quot; data-og-host=&quot;junlab.tistory.com&quot; data-og-source-url=&quot;https://junlab.tistory.com/219&quot; data-og-url=&quot;https://junlab.tistory.com/219&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bSyHkE/hyGnTePmWZ/HF5yW2WJZdZS6Pw7WuWKpk/img.png?width=467&amp;amp;height=76&amp;amp;face=0_0_467_76,https://scrap.kakaocdn.net/dn/iOED0/hyGnJpKYbA/7Exhkf7fk5TaOw6HHvh3Ek/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/htHU0/hyGnVqaC7O/K1jDU0SiDumsggyIo9XJk1/img.png?width=467&amp;amp;height=76&amp;amp;face=0_0_467_76&quot;&gt;&lt;a href=&quot;https://junlab.tistory.com/219&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junlab.tistory.com/219&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bSyHkE/hyGnTePmWZ/HF5yW2WJZdZS6Pw7WuWKpk/img.png?width=467&amp;amp;height=76&amp;amp;face=0_0_467_76,https://scrap.kakaocdn.net/dn/iOED0/hyGnJpKYbA/7Exhkf7fk5TaOw6HHvh3Ek/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/htHU0/hyGnVqaC7O/K1jDU0SiDumsggyIo9XJk1/img.png?width=467&amp;amp;height=76&amp;amp;face=0_0_467_76');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[docker] 도커 컴포즈란? 예제 및 기본 사용법 (docker-compose)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;도커 컴포즈를 알아보기 위해서는 기본적인 도커의 사용 이유와 예제 및 구동 방법을 알고 있으셔야 됩니다. 기본 내용은 앞의 게시물을 확인해주세요 :) - https://junlab.tistory.com/216 [docker] 도커 사&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;junlab.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;이번 포스트에서는 도커 컴포즈를 활용하여 젠킨스를 구동하도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;젠킨스 구동을 위해서 스크립트를 하나 만들어주세요.&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;1. &lt;b&gt;docker-compose.yml&lt;/b&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1591937199819&quot; class=&quot;java&quot; data-ke-language=&quot;java&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3&quot;
services:
  master:
    container_name: master
    image: jenkinsci/jenkins:2.150.1-slim
    ports:
      - 8080:8080
    volumes:
      - ./jenkins_home:/var/jenkinse_home&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;앞전의 기본 스크립트에서 못 본 volumes가 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;volumes&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;호스트의 jenkine_home 디렉터리를 젠킨스 컨테이너의 /var/jenkinse_home에 공유할 수 있는 구문입니다.&lt;/p&gt;
&lt;p&gt;Dockerfile의 COPY 명령어는 복사기능이지만, docker-compose volumes는 공유를 합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;명령어를 통해서 컨테이너를 구동하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1591937489408&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose pull
docker-compose up&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-12 13-45-35.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;106&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bKxxMp/btqEOProuNT/shpLOYqY1OiDhJ06okT1dK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bKxxMp/btqEOProuNT/shpLOYqY1OiDhJ06okT1dK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bKxxMp/btqEOProuNT/shpLOYqY1OiDhJ06okT1dK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbKxxMp%2FbtqEOProuNT%2FshpLOYqY1OiDhJ06okT1dK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-12 13-45-35.png&quot; data-origin-width=&quot;532&quot; data-origin-height=&quot;106&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;h3 data-ke-size=&quot;size23&quot;&gt;2. &lt;b&gt;localhost:8080 접속&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-12 13-54-35.png&quot; data-origin-width=&quot;1433&quot; data-origin-height=&quot;481&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/RdgZW/btqEL54cGu6/NIaHo3u88kw5YDdxTSenkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/RdgZW/btqEL54cGu6/NIaHo3u88kw5YDdxTSenkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/RdgZW/btqEL54cGu6/NIaHo3u88kw5YDdxTSenkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FRdgZW%2FbtqEL54cGu6%2FNIaHo3u88kw5YDdxTSenkK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-12 13-54-35.png&quot; data-origin-width=&quot;1433&quot; data-origin-height=&quot;481&quot; width=&quot;700&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;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-12 13-55-59.png&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;295&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bjHs9T/btqEL5iQ978/aYC5rzGgKpvA0Nxxne2DmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bjHs9T/btqEL5iQ978/aYC5rzGgKpvA0Nxxne2DmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bjHs9T/btqEL5iQ978/aYC5rzGgKpvA0Nxxne2DmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbjHs9T%2FbtqEL5iQ978%2FaYC5rzGgKpvA0Nxxne2DmK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-12 13-55-59.png&quot; data-origin-width=&quot;729&quot; data-origin-height=&quot;295&quot; width=&quot;700&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;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음으로 Install suggested plugins를 클릭하여 젠킨스 설치를 진행해주세요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-12 13-58-18.png&quot; data-origin-width=&quot;1367&quot; data-origin-height=&quot;597&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/7MwfT/btqEMxTBJkL/c8OqNsd9umhU3j7G9gs0fK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/7MwfT/btqEMxTBJkL/c8OqNsd9umhU3j7G9gs0fK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/7MwfT/btqEMxTBJkL/c8OqNsd9umhU3j7G9gs0fK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F7MwfT%2FbtqEMxTBJkL%2Fc8OqNsd9umhU3j7G9gs0fK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-12 13-58-18.png&quot; data-origin-width=&quot;1367&quot; data-origin-height=&quot;597&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-12 14-57-27.png&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;670&quot; width=&quot;700&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/IlkV0/btqENaD1NxY/7vaR0lIRQ8WsjeG9a0FrR0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/IlkV0/btqENaD1NxY/7vaR0lIRQ8WsjeG9a0FrR0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/IlkV0/btqENaD1NxY/7vaR0lIRQ8WsjeG9a0FrR0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FIlkV0%2FbtqENaD1NxY%2F7vaR0lIRQ8WsjeG9a0FrR0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-12 14-57-27.png&quot; data-origin-width=&quot;1376&quot; data-origin-height=&quot;670&quot; width=&quot;700&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;그럼 Retry를 누르지 않고 그냥 설치를 진행해주시면 아래의 완료된 모습을 보실 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-12 14-12-15.png&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;356&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bSgmE0/btqEODx3xfw/iCMbVryLw9esspWjSK5FW0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bSgmE0/btqEODx3xfw/iCMbVryLw9esspWjSK5FW0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bSgmE0/btqEODx3xfw/iCMbVryLw9esspWjSK5FW0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbSgmE0%2FbtqEODx3xfw%2FiCMbVryLw9esspWjSK5FW0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-12 14-12-15.png&quot; data-origin-width=&quot;828&quot; data-origin-height=&quot;356&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3. &lt;b&gt;슬레이브 젠킨스 컨테이너 생성&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;젠킨스를 사용할 때는 흔히, 2개의 서버로 운영을 합니다.&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;p&gt;마스터가 슬레이브와 데이터를 주고받을 수 있도록 ssh 키를 생성하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;컨테이너가 실행 중인 상태에서 아래 명령어를 입력해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1592802573328&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker container exec -it master ssh-keygen -t rsa -C &quot;&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-22 14-09-44.png&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;162&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dfEAWa/btqE4p0ng1M/xMrqHzeGIcq8dlv1Q4YEHk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dfEAWa/btqE4p0ng1M/xMrqHzeGIcq8dlv1Q4YEHk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dfEAWa/btqE4p0ng1M/xMrqHzeGIcq8dlv1Q4YEHk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdfEAWa%2FbtqE4p0ng1M%2FxMrqHzeGIcq8dlv1Q4YEHk%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-22 14-09-44.png&quot; data-origin-width=&quot;713&quot; data-origin-height=&quot;162&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;docker exec -it master bash 명령어를 통해서 /var/jenkins_home/.ssh/ 경로로 이동 후 id_rsa.pub를 확인해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1592803995555&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker exec -it master bash
cd /var/jenkins_home/.ssh/ 
cat id_rsa.pub
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;위의 명령어를 통해서 공개키 값을 확인 후에 yml파일에 slave를 만들겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1592804104965&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3&quot;
services:
  master:
    container_name: master
    image: jenkinsci/jenkins:2.150.1-slim
    ports:
      - 8080:8080
    volumes:
      - ./jenkins_home:/var/jenkinse_home
    links:
      - slave01

  slave01:
    container_name: slave01
    image: jenkinsci/ssh-slave
    environment:
      - JENKINS_SLAVE_SSH_PUBKEY= ssh-rsa AA...
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;links: master에 slave01에 대한&amp;nbsp; 링크를 설정&lt;/b&gt;했습니다. master에서 slave01이라는 이름으로 슬레이브를 찾아갈 수 있습니다.&lt;/p&gt;
&lt;p&gt;다시 정리를 하자면&lt;/p&gt;
&lt;p&gt;1. ssh 공개키 생성&lt;/p&gt;
&lt;p&gt;2. 젠킨스 환경변수인 &lt;span&gt;JENKINS_SLAVE_SSH_PUBKEY 추가&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;3. links 추가&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;slave컨테이너를 추가했으니 compose 명령어를 통해서 컨테이너를 구동하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1592804450608&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose up -d
docker-compose ps&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-22 14-40-54.png&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;115&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dNiDBP/btqE1DsfAf5/VCNukMClQ1bYkNFfbS5Zg0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dNiDBP/btqE1DsfAf5/VCNukMClQ1bYkNFfbS5Zg0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dNiDBP/btqE1DsfAf5/VCNukMClQ1bYkNFfbS5Zg0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdNiDBP%2FbtqE1DsfAf5%2FVCNukMClQ1bYkNFfbS5Zg0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-22 14-40-54.png&quot; data-origin-width=&quot;726&quot; data-origin-height=&quot;115&quot; data-ke-mobilestyle=&quot;widthContent&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이상으로 master와 slave 컨테이너 2개가 정상적으로 생성된 모습을 보실 수 있습니다.&lt;/p&gt;
&lt;p&gt;도커 컴 포즈 및 젠킨스 세팅 방법을 학습했으니 필요에 따라서 젠킨스 학습을 더욱 진행을 했으면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>docker</category>
      <category>docker composer</category>
      <category>도커</category>
      <category>도커컴포즈</category>
      <category>설치</category>
      <category>실습</category>
      <category>젠킨스</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/220</guid>
      <comments>https://junlab.tistory.com/220#entry220comment</comments>
      <pubDate>Fri, 12 Jun 2020 14:04:45 +0900</pubDate>
    </item>
    <item>
      <title>[docker] 도커 컴포즈란? 예제 및 기본 사용법 (docker-compose)</title>
      <link>https://junlab.tistory.com/219</link>
      <description>&lt;p&gt;도커 컴포즈를 알아보기 위해서는 기본적인 도커의 사용 이유와 예제 및 구동 방법을 알고 있으셔야 됩니다.&lt;/p&gt;
&lt;p&gt;기본 내용은 앞의 게시물을 확인해주세요 :) - &lt;a href=&quot;https://junlab.tistory.com/216&quot;&gt;https://junlab.tistory.com/216&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1591852592891&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[docker] 도커 사용 이유, 심플 예제 및 구동 (기본 사용법)&quot; data-og-description=&quot;프로젝트 빌드를 위해서 도커를 굉장히 많이 사용합니다. 대략적인 명령어를 활용하여 구동만 시킬 줄 알지 도커 관련하여 기본기가 너무 부족한 걸 느꼈습니다. 이제는 도커에 대해서 조금은 �&quot; data-og-host=&quot;junlab.tistory.com&quot; data-og-source-url=&quot;https://junlab.tistory.com/216&quot; data-og-url=&quot;https://junlab.tistory.com/216&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/LUKEp/hyGmQJGe3B/C1wxTezPQcQ0AyVLpmlzYK/img.png?width=698&amp;amp;height=271&amp;amp;face=0_0_698_271,https://scrap.kakaocdn.net/dn/dgPd9z/hyGnPCo7cv/VXnpGWdlBcByVeKU38KS11/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/GxX5w/hyGnXUJGFc/DBOjtu41gy8qNQdPhKof21/img.png?width=698&amp;amp;height=271&amp;amp;face=0_0_698_271&quot;&gt;&lt;a href=&quot;https://junlab.tistory.com/216&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://junlab.tistory.com/216&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/LUKEp/hyGmQJGe3B/C1wxTezPQcQ0AyVLpmlzYK/img.png?width=698&amp;amp;height=271&amp;amp;face=0_0_698_271,https://scrap.kakaocdn.net/dn/dgPd9z/hyGnPCo7cv/VXnpGWdlBcByVeKU38KS11/img.jpg?width=400&amp;amp;height=400&amp;amp;face=0_0_400_400,https://scrap.kakaocdn.net/dn/GxX5w/hyGnXUJGFc/DBOjtu41gy8qNQdPhKof21/img.png?width=698&amp;amp;height=271&amp;amp;face=0_0_698_271');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot;&gt;[docker] 도커 사용 이유, 심플 예제 및 구동 (기본 사용법)&lt;/p&gt;
&lt;p class=&quot;og-desc&quot;&gt;프로젝트 빌드를 위해서 도커를 굉장히 많이 사용합니다. 대략적인 명령어를 활용하여 구동만 시킬 줄 알지 도커 관련하여 기본기가 너무 부족한 걸 느꼈습니다. 이제는 도커에 대해서 조금은 �&lt;/p&gt;
&lt;p class=&quot;og-host&quot;&gt;junlab.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;일반적인 시스템은 단일 애플리케이션으로 구동이 되지 않습니다. 여러 개의 애플리케이션이 서로 의존성 있게 구성되어 시스템이 이뤄져 있습니다. 그렇다면 흔히 하나의 컨테이너가 하나의 애플리케이션을 담당한다고 하면 여러 개의 컨테이너가 필요로 합니다. 이때 필요한 기술이 도커 컴포즈(Docker Compose)입니다. 도커 컴포즈는 yaml 포맷으로 작성되며 여러 개의 컨테이너의 실행을 한 번에 관리를 할 수 있게 해 줍니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;앞의 게시물 예제 기반으로 root 위치에 도커 컴포즈를 위한 파일을 하나 만들겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1. docker-compose.yml&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1591853371289&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;version: &quot;3&quot;
services:
  echo:
    image: example/echo:latest
    ports:
      - 9000:8080&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;version&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;docker-compose.yml 내용을 해석하기 위한 문법 버전 - 3 버전은 안전 버전입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;echo&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;services 아래의 echo는 컨테이너 이름입니다. 즉, echo는 하나의 컨테이너입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;image&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;도커 이미지&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ports&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;포트 포워딩&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;도커 컴포즈 실행을 위해 아래 명령어를 실행시켜주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1591853632765&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose up&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-11 14-34-14.png&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;76&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/NX74r/btqENrxsGQm/2qBym81zILT7EH2lmbzTL0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/NX74r/btqENrxsGQm/2qBym81zILT7EH2lmbzTL0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/NX74r/btqENrxsGQm/2qBym81zILT7EH2lmbzTL0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FNX74r%2FbtqENrxsGQm%2F2qBym81zILT7EH2lmbzTL0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-11 14-34-14.png&quot; data-origin-width=&quot;467&quot; data-origin-height=&quot;76&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;docker container run 명령어로 실행시킨 것과 같이 동일하게 실행이 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;-d 옵션을 주고 백그라운드에서 실행을 시킬 수도 있고 다음으로 컨테이너를 종료시키겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1591853845013&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker-compose up -d
docker-compose ls
docker-compose down&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-06-11 14-35-55.png&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;206&quot; data-ke-mobilestyle=&quot;widthContent&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nSn9I/btqENaCJE4I/08nSrW1UPrIMYK1k3D2Kk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nSn9I/btqENaCJE4I/08nSrW1UPrIMYK1k3D2Kk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nSn9I/btqENaCJE4I/08nSrW1UPrIMYK1k3D2Kk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnSn9I%2FbtqENaCJE4I%2F08nSrW1UPrIMYK1k3D2Kk1%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-06-11 14-35-55.png&quot; data-origin-width=&quot;725&quot; data-origin-height=&quot;206&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;yml파일에 명시된 컨테이너들은 down 명령어를 통해서 한 번에 종료시킬 수 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;도커 컴포즈에 대해서 간략하게 알아봤습니다.&lt;/p&gt;
&lt;p&gt;다음은 젠킨스를 예제를 통해서 여러 컨테이너를 만들어보고 학습을 하도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;p.s)&lt;/p&gt;
&lt;p&gt;학습은 &lt;b&gt;도커/쿠버네티스를 활용한 컨테이너 개발 실전 입문&lt;/b&gt;을 보고 학습했습니다 :)&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>docker</category>
      <category>Docker Compose</category>
      <category>docker-compose</category>
      <category>도커</category>
      <category>도커 컴포즈란</category>
      <category>도커컴포즈</category>
      <category>사용법</category>
      <category>예제</category>
      <category>컨테이너</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/219</guid>
      <comments>https://junlab.tistory.com/219#entry219comment</comments>
      <pubDate>Thu, 11 Jun 2020 14:44:41 +0900</pubDate>
    </item>
    <item>
      <title>[docker] 도커 사용 이유, 심플 예제 및 구동 (기본 사용법)</title>
      <link>https://junlab.tistory.com/216</link>
      <description>&lt;p&gt;프로젝트 빌드를 위해서 도커를 굉장히 많이 사용합니다.&lt;/p&gt;
&lt;p&gt;대략적인 명령어를 활용하여 구동만 시킬 줄 알지 도커 관련하여 기본기가 너무 부족한 걸 느꼈습니다.&lt;/p&gt;
&lt;p&gt;이제는 도커에 대해서 조금은 더 알아야 될 때까 왔습니다.&lt;/p&gt;
&lt;p&gt;책을 보고 공부를 하며 정리를 하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;책은 도커/쿠버네티스를 활용한 컨테이너 실전 입문 책을 보고 공부했습니다 :)&lt;/p&gt;
&lt;p&gt;도커 공부가 필요하신 분은 한 권 구입을 하시는 것도 추천드립니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;도커를 사용하는 이유&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;- 변화하지 않는 실행 환경 확보를 위해서&lt;/p&gt;
&lt;p&gt;- 코드를 통한 실행 환경 구축 및 애플리케이션 구성&lt;/p&gt;
&lt;p&gt;- 실행 환경과 애플리케이션의 일체화로 이식성 향상&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;즉, 애플리케이션을 개발하면서 변화 없는 동일한 환경 구성을 할 수 있다!!&lt;/p&gt;
&lt;p&gt;똑같은 애플리케이션을 구동하더라도 사용자마다 서버마다 환경이 다르다. 이 문제를 도커로 같은 실행환경으로 만들 수 있다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;도커 이미지 및 도커 컨테이너&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;- 도커 이미지: 컨테이너를 구성하는 파일 시스템과 실행할 애플리케이션 설정을 하나로 합친 것을 뜻함. 컨테이너를 생성하기 위한 템플릿.&lt;/p&gt;
&lt;p&gt;- 도커 컨테이너: 도커 이미지를 기반으로 애플리케이션이 실행되는 상태.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2개의 용어를 숙지해주세요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;도커 실행 예제&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;1. main.go&lt;/p&gt;
&lt;pre id=&quot;code_1590396902615&quot; class=&quot;go&quot; data-ke-language=&quot;go&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;package main

import (
	&quot;fmt&quot;
	&quot;log&quot;
	&quot;net/http&quot;
)

func main() {
	http.HandleFunc(&quot;/&quot;, func(w http.ResponseWriter, r *http.Request) {
		log.Println(&quot;received request&quot;)
		fmt.Fprintf(w, &quot;Hello Docker!!&quot;)
	})

	log.Println(&quot;start server&quot;)
	server := &amp;amp;http.Server{Addr: &quot;:8080&quot;}
	if err := server.ListenAndServe(); err != nil {
		log.Println(err)
	}
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;go언어로 작성이 되었지만 어려운 내용은 없습니다. 8080으로 요청을 받는 서버입니다. 요청을 받게 되면 received request와 Hello Docker!! 문구가 출력됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;2. Dockerfile&lt;/p&gt;
&lt;pre id=&quot;code_1590397106848&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;FROM golang:1.9

RUN mkdir /echo
COPY main.go /echo

CMD [&quot;go&quot;, &quot;run&quot;, &quot;/echo/main.go&quot;]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;도커 이미지를 만들어 봤습니다. main.go파일과 같은 위치에 만들어 주세요.&lt;/p&gt;
&lt;p&gt;각각의 명령들을 살펴보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;FROM&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;도커 이미지의 베이스입니다. 우리는 go 언어를 사용하기 때문에 golang을 명시해줍니다.&lt;/p&gt;
&lt;p&gt;FROM에 명시된 이미지는 도커 허브(Docker Hub)에 등록되어 있는 이미지입니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;RUN&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;도커 이미지가 실행될 때 컨테이너 안에서 실행할 명령입니다.&lt;/p&gt;
&lt;p&gt;스크립트의 명령에 따라 컨테이너 안에서는 /echo 디렉터리가 만들어집니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;COPY&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;호스트의 파일이나 디렉터리를 도커 컨테이너로 복사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;CMD&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;컨테이너 안에서 실행할 프로세스를 지정합니다.&lt;/p&gt;
&lt;p&gt;RUN명령어는 애플리케이션의 업데이트 및 배치를 위해서 이미지를 빌드할 때 실행됩니다.&lt;/p&gt;
&lt;p&gt;CMD는 애플리케이션 자체를 실행하는 명령어로 컨테이너가 시작될 때 한 번만 실행됩니다.&lt;/p&gt;
&lt;p&gt;즉, 위의 CMD 명령어를 통해서 &quot; go run /echo/main.go &quot; 명령이 실행됩니다.&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;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;위의 내용을 기반으로 도커 구동&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;1. 다음으로 &lt;b&gt;도커 이미지를 빌드&lt;/b&gt;하겠습니다.&lt;/p&gt;
&lt;p&gt;docker image build -t example/echo:latest&lt;/p&gt;
&lt;pre id=&quot;code_1590400369064&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image build -t example/echo:latest .&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;-t 옵션을 통해서 example/echo:latest라는 이미지명을 지정합니다. 이미지명을 지정하지 않으면 이미지명이 해시값만 만들어져 구분이 어렵습니다. :latest도 생략이 가능하며 생략 시 latest가 붙습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-25 18-56-25.png&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;271&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/l2zxY/btqEpZn4KfN/kkcntGrjzmPmInyP45mcc1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/l2zxY/btqEpZn4KfN/kkcntGrjzmPmInyP45mcc1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/l2zxY/btqEpZn4KfN/kkcntGrjzmPmInyP45mcc1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fl2zxY%2FbtqEpZn4KfN%2FkkcntGrjzmPmInyP45mcc1%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-25 18-56-25.png&quot; data-origin-width=&quot;698&quot; data-origin-height=&quot;271&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;실행 명령어를 수행하면 dockerfile에 명시된 명려들이 순차적으로 실행됩니다.&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;pre id=&quot;code_1590400744170&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker image ls&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;위의 명령을 실행하면 현재 자신의 컴퓨터에 생성된 도커 이미지를 확인할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-25 18-59-55.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;88&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/kNYqd/btqEnhYcxP1/EjgP9WIxf9mr1H2xnk67N0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/kNYqd/btqEnhYcxP1/EjgP9WIxf9mr1H2xnk67N0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/kNYqd/btqEnhYcxP1/EjgP9WIxf9mr1H2xnk67N0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FkNYqd%2FbtqEnhYcxP1%2FEjgP9WIxf9mr1H2xnk67N0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-25 18-59-55.png&quot; data-origin-width=&quot;643&quot; data-origin-height=&quot;88&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;3. 빌드까지 정상적으로 되었으니 &lt;b&gt;도커 컨테이너를 실행&lt;/b&gt;하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1590400917215&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker container run example/echo:latest
or
# -d 옵션: 백그라운드 실행
docker container run -d example/echo:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-25 19-04-51.png&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;40&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/yCGaD/btqEpZO7VTT/v2hCcXDTrCKGSjzJYue6pK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/yCGaD/btqEpZO7VTT/v2hCcXDTrCKGSjzJYue6pK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/yCGaD/btqEpZO7VTT/v2hCcXDTrCKGSjzJYue6pK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FyCGaD%2FbtqEpZO7VTT%2Fv2hCcXDTrCKGSjzJYue6pK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-25 19-04-51.png&quot; data-origin-width=&quot;667&quot; data-origin-height=&quot;40&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;4. 다음 명령어를 통해서 실행 중인 도커 컨테이너를 확인할 수 있습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1590406771974&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;docker container ls&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-25 20-38-53.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;96&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dnG2Tf/btqEoBBNjzX/H9TLzVZg5PgsxkBpd03f0k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dnG2Tf/btqEoBBNjzX/H9TLzVZg5PgsxkBpd03f0k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dnG2Tf/btqEoBBNjzX/H9TLzVZg5PgsxkBpd03f0k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdnG2Tf%2FbtqEoBBNjzX%2FH9TLzVZg5PgsxkBpd03f0k%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-25 20-38-53.png&quot; data-origin-width=&quot;728&quot; data-origin-height=&quot;96&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;5. 서버가 동작하니 8080으로 요청을 해보겠습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-25 20-40-37.png&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;47&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/HbNIH/btqEnhcPsRE/K44KW59SAkIPR7s4dV24CK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/HbNIH/btqEnhcPsRE/K44KW59SAkIPR7s4dV24CK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/HbNIH/btqEnhcPsRE/K44KW59SAkIPR7s4dV24CK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FHbNIH%2FbtqEnhcPsRE%2FK44KW59SAkIPR7s4dV24CK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-25 20-40-37.png&quot; data-origin-width=&quot;636&quot; data-origin-height=&quot;47&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;8080으로 요청을 했더니 연결이 거절됐습니다.&lt;/p&gt;
&lt;p&gt;컨테이너 밖에서는 컨테이너 포트를 바로 사용할 수 없습니다.&lt;/p&gt;
&lt;p&gt;밖에서 온 요청을 컨테이너 안에 있는 애플리케이션으로 전달을 해줘야 합니다. 즉, &lt;b&gt;포트 포워딩을 해주셔야&lt;/b&gt; 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;6. 도커 실행을 중지하고 &lt;b&gt;호스트 포트 9000을 컨테이너 포트 8080으로 연결&lt;/b&gt;하겠습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1590407321998&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;# container_id는 ls 명령어를 통해서 확인
docker container stop [container_id]

# -p옵션: 포트 포워딩 지정
docker container run -d -p 9000:8080 example/echo:latest&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-25 20-46-56.png&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;237&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bs9Mr0/btqEpZ9wxHl/zWomdEhoq0YzCCqBQQ7Zk1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bs9Mr0/btqEpZ9wxHl/zWomdEhoq0YzCCqBQQ7Zk1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bs9Mr0/btqEpZ9wxHl/zWomdEhoq0YzCCqBQQ7Zk1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fbs9Mr0%2FbtqEpZ9wxHl%2FzWomdEhoq0YzCCqBQQ7Zk1%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-25 20-46-56.png&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;237&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;7. 포트 포워딩이 되었으니 9000 포트로 접속을 다시 하겠습니다 :)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-25 20-49-57.png&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;133&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/qhOig/btqEng6aSrq/PL8ef0UIvT9ZiV1OYimrD0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/qhOig/btqEng6aSrq/PL8ef0UIvT9ZiV1OYimrD0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/qhOig/btqEng6aSrq/PL8ef0UIvT9ZiV1OYimrD0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FqhOig%2FbtqEng6aSrq%2FPL8ef0UIvT9ZiV1OYimrD0%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-25 20-49-57.png&quot; data-origin-width=&quot;366&quot; data-origin-height=&quot;133&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;9000 포트로 접속을 했더니 서버로부터 이상 없이 응답을 받았습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;이상 도커의 기본 스크립트와 구동방법을 알아봤습니다.&lt;/p&gt;
&lt;p&gt;도움이 되셨으면 좋겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>docker</category>
      <category>dockerfile</category>
      <category>도커</category>
      <category>사용법</category>
      <category>예제</category>
      <category>이미지</category>
      <category>컨테이너</category>
      <category>포워딩</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/216</guid>
      <comments>https://junlab.tistory.com/216#entry216comment</comments>
      <pubDate>Mon, 25 May 2020 18:08:55 +0900</pubDate>
    </item>
    <item>
      <title>django 토큰 인증 기반 회원가입 및 로그인 구현(rest api, jwt)</title>
      <link>https://junlab.tistory.com/214</link>
      <description>&lt;p&gt;&lt;span&gt;안녕하세요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;장고에서 jwt 인증 방법을 활용하여 회원가입 및 로그인 구현을 해보겠습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;기존에는 쿠키-세션에 유저 정보가 있는데요. &lt;span style=&quot;color: #333333;&quot;&gt;쿠키를 사용해서 유저를 식별합니다.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;이를 통해서 로그인 여부를 알 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;기존의 방법은 rest api에 적합하지 않고 리액트에서는 쿠키를 관리하지 않아 인증 메커니즘을 변경시켜주셔야 됩니다.&lt;/p&gt;
&lt;p&gt;우리는 jwt 인증 방식으로 사용자 인증을 진행하겠습니다.&lt;/p&gt;
&lt;p&gt;jwt는 javascript web token의 약자입니다.&lt;/p&gt;
&lt;p&gt;즉, 사용자에게 토큰을 발행해서 인증이 된 사용자인지 판별 하는 것입니다.&lt;/p&gt;
&lt;p&gt;어렵지 않으니 하나씩 하나씩 변경을 해주시면 되겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;장고에서는 jwt 사용을 위해서 패키지를 제공해줍니다. 아래와 같이 설치해주세요.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;1) &lt;span style=&quot;color: #333333;&quot;&gt;djangorestframework-jwt 설치&lt;/span&gt;&lt;/b&gt;&lt;span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589472329210&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install djangorestframework-jwt&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;&lt;span&gt;2) 세팅 파일에 다음과 같은 인증을(코드를) 추가&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589472415608&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이 2가지만 해주시면 jwt 사용은 가능합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;다음으로 로그인과 회원가입을 위한 rest api를 만들어 보겠습니다.&lt;/p&gt;
&lt;p&gt;이 내용도 패키지가 제공이 되어 정말 심플하게 구현이 가능합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;3) &lt;span style=&quot;color: #333333;&quot;&gt;django-rest-auth 설치&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589472570362&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install django-rest-auth&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;4) 세팅 파일에 INSTALLED_APPS에 필요로 하는 app 추가&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589472715818&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;INSTALLED_APPS = (
    ...,
    'allauth',
    'allauth.account',
    'rest_auth.registration',
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;5) jwt 인증 사용을 위한 sesstion 및 기본 인증 주석 처리&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589472761366&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        #'rest_framework.authentication.SessionAuthentication',
        #'rest_framework.authentication.BasicAuthentication',
    ),
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;b&gt;6) 기본 설정&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589472836454&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;#ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_REQUIRED = False

#ACCOUNT_EMAIL_VERIFICATION = &quot;mandatory&quot;
ACCOUNT_EMAIL_VERIFICATION = &quot;none&quot;

REST_USE_JWT = True
ACCOUNT_LOGOUT_ON_GET = True
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;7) URL 추가&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1589472955529&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;path(&quot;rest-auth/&quot;, include('rest_auth.urls')),
path(&quot;rest-auth/registration/&quot;, include('rest_auth.registration.urls')),&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;마지막으로 URL을 설정해주시면 됩니다.&lt;/p&gt;
&lt;p&gt;우리는 JWT 세팅과 회원가입과 로그인을 위한 rest&amp;nbsp; api도 만들었습니다.&lt;/p&gt;
&lt;p&gt;테스트를 진행하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;* 회원가입&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-14 15-21-35.png&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;526&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/c0eCbR/btqEamRr595/PVcFwQwK59AE22ZSBS5kLk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/c0eCbR/btqEamRr595/PVcFwQwK59AE22ZSBS5kLk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/c0eCbR/btqEamRr595/PVcFwQwK59AE22ZSBS5kLk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fc0eCbR%2FbtqEamRr595%2FPVcFwQwK59AE22ZSBS5kLk%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-14 15-21-35.png&quot; data-origin-width=&quot;1242&quot; data-origin-height=&quot;526&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;&amp;nbsp;&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; data-filename=&quot;Screenshot from 2020-05-14 15-21-58.png&quot; data-origin-width=&quot;1333&quot; data-origin-height=&quot;466&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dagynM/btqEa0UTFWq/cfEg1K8gxRV5uF8zL1dkmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dagynM/btqEa0UTFWq/cfEg1K8gxRV5uF8zL1dkmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dagynM/btqEa0UTFWq/cfEg1K8gxRV5uF8zL1dkmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdagynM%2FbtqEa0UTFWq%2FcfEg1K8gxRV5uF8zL1dkmK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-14 15-21-58.png&quot; data-origin-width=&quot;1333&quot; data-origin-height=&quot;466&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;로그인이 성공되고 token이 만들어집니다.&lt;/p&gt;
&lt;p&gt;사용자는 이후에 우리의 서버에 접속하기 위해서는 아래처럼 헤더에 token을 갖고 시도를 해야 접속을 할 수 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-15 01-19-10.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;167&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/chQdn3/btqEamxFgWJ/XB7FLhQGbVU3EcELmFwRdk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/chQdn3/btqEamxFgWJ/XB7FLhQGbVU3EcELmFwRdk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/chQdn3/btqEamxFgWJ/XB7FLhQGbVU3EcELmFwRdk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FchQdn3%2FbtqEamxFgWJ%2FXB7FLhQGbVU3EcELmFwRdk%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-15 01-19-10.png&quot; data-origin-width=&quot;798&quot; data-origin-height=&quot;167&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;* 참고 사이트&lt;/p&gt;
&lt;p&gt;&lt;b&gt;&lt;span style=&quot;color: #333333;&quot;&gt;- djangorestframework-jwt&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://jpadilla.github.io/django-rest-framework-jwt/&quot;&gt;https://jpadilla.github.io/django-rest-framework-jwt/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;- django rest auth&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://django-rest-auth.readthedocs.io/en/latest/index.html&quot;&gt;https://django-rest-auth.readthedocs.io/en/latest/index.html&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/python</category>
      <category>Django</category>
      <category>djangorestframework</category>
      <category>JWT</category>
      <category>REST API</category>
      <category>로그인</category>
      <category>인증</category>
      <category>장고</category>
      <category>토큰</category>
      <category>회원가입</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/214</guid>
      <comments>https://junlab.tistory.com/214#entry214comment</comments>
      <pubDate>Thu, 14 May 2020 15:24:18 +0900</pubDate>
    </item>
    <item>
      <title>[django] 장고 모델 null 과 blank 차이</title>
      <link>https://junlab.tistory.com/213</link>
      <description>&lt;p&gt;장고 프레임워크를 활용하여 DB 모델을 만들고 있었습니다.&lt;/p&gt;
&lt;p&gt;일반적인 DB를 활용하여 테이블을 만들때는 제약조건에 null만 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;null 이라 함은 값이 없음을 의미하는 값&lt;/b&gt; 입니다.&lt;/p&gt;
&lt;p&gt;하지만 장고 모델을 작성하다 보니 blank라는 제약조건이 있었는데요.&lt;/p&gt;
&lt;p&gt;이 둘의 차이점을 알아보도록 하겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;1. 공식문서&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;django null.PNG&quot; data-origin-width=&quot;1103&quot; data-origin-height=&quot;348&quot; width=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/swtUQ/btqEo6PJAeU/BgQiSjBi5KKPh4dKvxlEb1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/swtUQ/btqEo6PJAeU/BgQiSjBi5KKPh4dKvxlEb1/img.png&quot; data-alt=&quot;&amp;amp;amp;nbsp;django null&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/swtUQ/btqEo6PJAeU/BgQiSjBi5KKPh4dKvxlEb1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FswtUQ%2FbtqEo6PJAeU%2FBgQiSjBi5KKPh4dKvxlEb1%2Fimg.png&quot; data-filename=&quot;django null.PNG&quot; data-origin-width=&quot;1103&quot; data-origin-height=&quot;348&quot; width=&quot;700&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;&amp;nbsp;django null&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;django 공식문서에 null 설명입니다. True라고 설정이 된다면 데이터베이스 내 빈 값을 저장할 수 있다고 합니다. 마지막줄을 보시게 되면 장고에서 사용되는 forms 관련해서는 blank 파트를 보라고 설명이 되어 있습니다.&lt;/p&gt;
&lt;p&gt;다음 blank를 보겠습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;장고공식문서.PNG&quot; data-origin-width=&quot;1094&quot; data-origin-height=&quot;227&quot; width=&quot;700&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cUjf1m/btqEqr6JN5u/D7zKIziKrSdTVIgTWgr140/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cUjf1m/btqEqr6JN5u/D7zKIziKrSdTVIgTWgr140/img.png&quot; data-alt=&quot;django blank&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cUjf1m/btqEqr6JN5u/D7zKIziKrSdTVIgTWgr140/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcUjf1m%2FbtqEqr6JN5u%2FD7zKIziKrSdTVIgTWgr140%2Fimg.png&quot; data-filename=&quot;장고공식문서.PNG&quot; data-origin-width=&quot;1094&quot; data-origin-height=&quot;227&quot; width=&quot;700&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;django blank&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;blank가 True인 경우에는 blank라고 설명이 되어 있는데요. 여기까지 보면 null과 별 차이가 없습니다.&lt;/p&gt;
&lt;p&gt;다음 라인을 보시게 되면 차이점이 있습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;null은 물리적인 데이터베이스와 관련이 있고, blank는 유효성과 관련&lt;/b&gt;이 있습니다.&lt;/p&gt;
&lt;p&gt;즉, null은 데이터베이스의 직접적인 연관이 있고 null 옵션을 통해서 데이터베이스의 null이라는 제약조건을 주고 blank옵션은 물리적으로 데이터베이스에는 연관이 없으며 django forms을 사용한 유효성 검사와 관련이 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;2. 코드와 테이블 설계도&lt;/b&gt;&lt;/h3&gt;
&lt;p&gt;실제코드는 아래와 같습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1590554452736&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class TestNullBlank(models.Model):
    null_true   = models.CharField(max_length=10, null=True)
    null_false  = models.CharField(max_length=10, null=False)
    blank_true  = models.CharField(max_length=10, blank=True)
    blank_flase = models.CharField(max_length=10, blank=False)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-05-27 13-58-26.png&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;107&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dha4ru/btqEsXcCCkE/JcXmG5SKw6HtaCbkKx7AaK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dha4ru/btqEsXcCCkE/JcXmG5SKw6HtaCbkKx7AaK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dha4ru/btqEsXcCCkE/JcXmG5SKw6HtaCbkKx7AaK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fdha4ru%2FbtqEsXcCCkE%2FJcXmG5SKw6HtaCbkKx7AaK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-05-27 13-58-26.png&quot; data-origin-width=&quot;546&quot; data-origin-height=&quot;107&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;테이블이 만들어지는 데이터베이스 설계도&lt;/p&gt;
&lt;p&gt;PostgreSql 데이터베이스 기준입니다.&lt;/p&gt;
&lt;pre id=&quot;code_1590554860136&quot; class=&quot;sql&quot; data-ke-language=&quot;sql&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;CREATE TABLE TestNullBlank (
  id              serial			NOT NULL,
  &quot;null_True&quot;     character varying(10),
  &quot;null_False&quot;    character varying(10)		NOT NULL,
  &quot;blank_True&quot;    character varying(10)		NOT NULL,
  &quot;blank_False&quot;   character varying(10)		NOT NULL,
  CONSTRAINT TestNullBlank PRIMARY KEY (id)
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;null이 허용되는(null=True) 첫번째 컬럼&lt;/b&gt; null_True를 제외하고는, 모두 &lt;b&gt;null 값이 허용이 안됩&lt;/b&gt;니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;데이터베이스 설계는 정말 중요합니다.&lt;/p&gt;
&lt;p&gt;스키마를 만드는데 있어 빈틈없이 꼼꼼하게 설계를 만들어야겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;* 장고 공식문서 참고&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.djangoproject.com/en/3.0/ref/models/fields/#null&quot;&gt;https://docs.djangoproject.com/en/3.0/ref/models/fields/#null&lt;/a&gt;&lt;/p&gt;</description>
      <category>Programming/python</category>
      <category>blank</category>
      <category>model</category>
      <category>null field</category>
      <category>값이 없음</category>
      <category>널</category>
      <category>데이터베이스</category>
      <category>모델</category>
      <category>스키마</category>
      <category>장고</category>
      <category>테이블</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/213</guid>
      <comments>https://junlab.tistory.com/213#entry213comment</comments>
      <pubDate>Thu, 14 May 2020 14:58:12 +0900</pubDate>
    </item>
    <item>
      <title>git 에러 - Permission denied (publickey) (gitlab)(키에러)</title>
      <link>https://junlab.tistory.com/212</link>
      <description>&lt;p&gt;gitlab으로 push를 진행 중에 Permission denied (publickey) 에러가 발생했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;1_error.PNG&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;143&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b2V8LF/btqDBzxTGPH/KugSQDk627o0kNsg6wtK3k/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b2V8LF/btqDBzxTGPH/KugSQDk627o0kNsg6wtK3k/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b2V8LF/btqDBzxTGPH/KugSQDk627o0kNsg6wtK3k/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb2V8LF%2FbtqDBzxTGPH%2FKugSQDk627o0kNsg6wtK3k%2Fimg.png&quot; data-filename=&quot;1_error.PNG&quot; data-origin-width=&quot;478&quot; data-origin-height=&quot;143&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 id=&quot;code_1587540061348&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;lg@DESKTOP-E80J3HQ MINGW64 ~/work/lotto (master)
$ git push -u origin master
git@gitlab.com: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;ssh키가 등록이 안되어 발생하는 에러입니다.&lt;/p&gt;
&lt;p&gt;깃랩 사이트에 우리의 공개키를 등록을 해주시면 됩니다.&lt;/p&gt;
&lt;p&gt;아래의 방법을 참고해주세요 ^^&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;1. 다음 명령어 입력 후 엔터를 쳐주세요.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;ssh-keygen&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;2_error.PNG&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;112&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/xE91A/btqDACPx8hT/bQc2gKEsn97I152OSxhZzK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/xE91A/btqDACPx8hT/bQc2gKEsn97I152OSxhZzK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/xE91A/btqDACPx8hT/bQc2gKEsn97I152OSxhZzK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FxE91A%2FbtqDACPx8hT%2FbQc2gKEsn97I152OSxhZzK%2Fimg.png&quot; data-filename=&quot;2_error.PNG&quot; data-origin-width=&quot;585&quot; data-origin-height=&quot;112&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;2. 방금 key가 만들어진. ssh&amp;nbsp; 경로로 이동해주세요. (경로는 위의 사진이며 사용자 컴퓨터 만다 다릅니다.)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;3_error.PNG&quot; data-origin-width=&quot;323&quot; data-origin-height=&quot;66&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dM5ch3/btqDzEtdpDp/mV6xTTXcl4ybxwvxrmsBq0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dM5ch3/btqDzEtdpDp/mV6xTTXcl4ybxwvxrmsBq0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dM5ch3/btqDzEtdpDp/mV6xTTXcl4ybxwvxrmsBq0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdM5ch3%2FbtqDzEtdpDp%2FmV6xTTXcl4ybxwvxrmsBq0%2Fimg.png&quot; data-filename=&quot;3_error.PNG&quot; data-origin-width=&quot;323&quot; data-origin-height=&quot;66&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;3. id_ksa.pub 파일을 열어서 &lt;b&gt;키를 복사&lt;/b&gt;해주세요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;4. 깃랩 키 관리 사이트로 이동해주세요. (&lt;a href=&quot;https://gitlab.com/profile/keys&quot;&gt;https://gitlab.com/profile/keys&lt;/a&gt;)&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;4_error.PNG&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;496&quot; width=&quot;650&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cwatjp/btqDA5jujdF/xa5ocRyt4JFFlUsb31J3D0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cwatjp/btqDA5jujdF/xa5ocRyt4JFFlUsb31J3D0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cwatjp/btqDA5jujdF/xa5ocRyt4JFFlUsb31J3D0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fcwatjp%2FbtqDA5jujdF%2Fxa5ocRyt4JFFlUsb31J3D0%2Fimg.png&quot; data-filename=&quot;4_error.PNG&quot; data-origin-width=&quot;1236&quot; data-origin-height=&quot;496&quot; width=&quot;650&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;5. &lt;span style=&quot;color: #333333;&quot;&gt;id_ksa.pub&lt;span&gt;에서 &lt;/span&gt;&lt;/span&gt;복사하신 키를 사이트 key 부분에 복사해주세요.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;6. Add Key를 눌러 키를 등록해주시면 됩니다 ^^&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;키 등록 이후에 이상 없이 push가 되었습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;complete.PNG&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;174&quot; width=&quot;600&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b3Djg5/btqDA6v2tbH/XbXkxokIw1KNy1FKuxOyw0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b3Djg5/btqDA6v2tbH/XbXkxokIw1KNy1FKuxOyw0/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b3Djg5/btqDA6v2tbH/XbXkxokIw1KNy1FKuxOyw0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb3Djg5%2FbtqDA6v2tbH%2FXbXkxokIw1KNy1FKuxOyw0%2Fimg.png&quot; data-filename=&quot;complete.PNG&quot; data-origin-width=&quot;638&quot; data-origin-height=&quot;174&quot; width=&quot;600&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/Git, Mercurial</category>
      <category>Denied</category>
      <category>GIT</category>
      <category>gitlab</category>
      <category>Key</category>
      <category>permission</category>
      <category>publickey</category>
      <category>SSH</category>
      <category>깃</category>
      <category>깃랩</category>
      <category>에러</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/212</guid>
      <comments>https://junlab.tistory.com/212#entry212comment</comments>
      <pubDate>Wed, 22 Apr 2020 16:38:04 +0900</pubDate>
    </item>
    <item>
      <title>system에러 - Unable to fetch some archives, maybe run apt-get update...</title>
      <link>https://junlab.tistory.com/210</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;도커 커맨드 실행중에 다음과 같은 에러가 발생했습니다.&lt;/p&gt;
&lt;pre id=&quot;code_1587129304401&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;E: Failed to fetch http://deb.debian.org/debian/pool/main/g/glibc/libc6-dev_2.28-10_amd64.deb  Connection failed [IP: 151.101.228.204 80]
E: Unable to fetch some archives, maybe run apt-get update or try with --fix-missing?
ERROR: Service 'django' failed to build: The command '/bin/sh -c apt-get update   &amp;amp;&amp;amp; apt-get install -y build-essential   &amp;amp;&amp;amp; apt-get install -y libpq-dev   &amp;amp;&amp;amp; apt-get install -y gettext   &amp;amp;&amp;amp; apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false   &amp;amp;&amp;amp; rm -rf /var/lib/apt/lists/*' returned a non-zero code: 1002&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-04-17 22-11-23.png&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;166&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/btsFvQ/btqDw3FfxQW/b8AMTpQCFbozojlUMyUKkK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/btsFvQ/btqDw3FfxQW/b8AMTpQCFbozojlUMyUKkK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/btsFvQ/btqDw3FfxQW/b8AMTpQCFbozojlUMyUKkK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbtsFvQ%2FbtqDw3FfxQW%2Fb8AMTpQCFbozojlUMyUKkK%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-04-17 22-11-23.png&quot; data-origin-width=&quot;727&quot; data-origin-height=&quot;166&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;해결하는 방법은 간단합니다.&lt;/p&gt;
&lt;p&gt;다음 명령어를 입력해주세요.&lt;/p&gt;
&lt;pre id=&quot;code_1587129360180&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get update&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;이후에 문제 없이 동작이 되었습니다 ^^&lt;/p&gt;
&lt;p&gt;참고해주세요.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/System</category>
      <category>apt-get</category>
      <category>Archives</category>
      <category>fetch</category>
      <category>Maybe</category>
      <category>run</category>
      <category>some</category>
      <category>unable</category>
      <category>update</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/210</guid>
      <comments>https://junlab.tistory.com/210#entry210comment</comments>
      <pubDate>Fri, 17 Apr 2020 22:12:19 +0900</pubDate>
    </item>
    <item>
      <title>JS에러 - redux-persist failed to create sync storage. falling back to noop storage</title>
      <link>https://junlab.tistory.com/209</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;리덕스 세팅 중에 다음과 같은 에러가 발생했습니다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;Screenshot from 2020-04-16 17-59-59.png&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;150&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b02Sgt/btqDw3FfHnD/OBbiskxMwiZM99D8EUFk70/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b02Sgt/btqDw3FfHnD/OBbiskxMwiZM99D8EUFk70/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b02Sgt/btqDw3FfHnD/OBbiskxMwiZM99D8EUFk70/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb02Sgt%2FbtqDw3FfHnD%2FOBbiskxMwiZM99D8EUFk70%2Fimg.png&quot; data-filename=&quot;Screenshot from 2020-04-16 17-59-59.png&quot; data-origin-width=&quot;731&quot; data-origin-height=&quot;150&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 id=&quot;code_1587129659853&quot; class=&quot;python&quot; data-ke-language=&quot;python&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;redux-persist failed to create sync storage. falling back to noop storage.&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;redux-persist 세팅 중에 발생한 에러입니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;원인은 버전이 맞지 않아 최근 버전의 방법처럼 세팅을 해주셔야 합니다&lt;/b&gt;.&lt;/p&gt;
&lt;p&gt;sync 스토리지 생성을 실패했는데요. 실패한 코드는 다음과 같습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;기존 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1587129940831&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { applyMiddleware, createStore } from &quot;redux&quot;;
import { persistStore, persistCombineReducers } from &quot;redux-persist&quot;;
import storage from &quot;redux-persist/lib/storage&quot;;
import thunk from &quot;redux-thunk&quot;;

const middlewares = [thunk];

const persistConfig = {
	key: &quot;root&quot;,
	storage
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;기존 코드인 실패한 코드는 storage를 redux-persist 라이브러리에서 갖고 온 storage를 설정 값에 넣어 줍니다.&lt;/p&gt;
&lt;p&gt;하지만 최근 버전에서는 react-native에서 갖고 오셔야 됩니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;b&gt;변경 코드&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1587129989778&quot; class=&quot;javascript&quot; data-ke-language=&quot;javascript&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import { AsyncStorage } from 'react-native';
import { applyMiddleware, createStore } from &quot;redux&quot;;
import { persistStore, persistCombineReducers } from &quot;redux-persist&quot;;
import thunk from &quot;redux-thunk&quot;;

const middlewares = [thunk];

const persistConfig = {
	key: &quot;root&quot;,
	storage: AsyncStorage
};&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;letter-spacing: 0px;&quot;&gt;&lt;/span&gt;storage 방식을 위와 같이 저장해주시면 해결이 되겠습니다.&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;</description>
      <category>Programming/JavaScript</category>
      <category>Failed</category>
      <category>JS</category>
      <category>React</category>
      <category>React Native</category>
      <category>redux-persist</category>
      <category>storage</category>
      <category>Sync</category>
      <category>에러</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/209</guid>
      <comments>https://junlab.tistory.com/209#entry209comment</comments>
      <pubDate>Thu, 16 Apr 2020 18:08:14 +0900</pubDate>
    </item>
    <item>
      <title>탈잉 VOD 강의 후기 (소액으로 시작하는 부동산 투자)</title>
      <link>https://junlab.tistory.com/208</link>
      <description>&lt;p&gt;안녕하세요.&lt;/p&gt;
&lt;p&gt;탈잉 VOD 후기를 남겨 보려고 해요. 탈잉이라는 플랫폼은 다른 사람의 가르침을 받을 수 있는 플랫폼입니다. 어떤 걸 배울 수 있을까요? 영어회화, 영상편집, 개발, 요리, 투잡 관련 등등 정말 많은 걸 배울 수 있어요. 내가 다른 사람들보다 조금 잘할 수 있는 게 있다면 가르칠 수도 있고 필요로 한 걸 배울 수도 있어요!!&lt;/p&gt;
&lt;p&gt;원래는 오프라인으로 많이 진행을 하는데 최근에는 온라인 강좌도 많이 올라고 있습니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;제가 본 강좌는 &lt;b&gt;소액으로 시작하는 부동산 투자 강의를 수강&lt;/b&gt;했어요. &lt;b&gt;이광석 튜터님&lt;/b&gt;께서 진행을 하시고요.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-filename=&quot;부동산 투자.PNG&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;362&quot; width=&quot;750&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/DgOp3/btqDdIWWMir/5DBmWaiJkb1qaR8J4SyEQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/DgOp3/btqDdIWWMir/5DBmWaiJkb1qaR8J4SyEQ1/img.png&quot; data-alt=&quot;지금은 강의 시청 중 :)&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/DgOp3/btqDdIWWMir/5DBmWaiJkb1qaR8J4SyEQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FDgOp3%2FbtqDdIWWMir%2F5DBmWaiJkb1qaR8J4SyEQ1%2Fimg.png&quot; data-filename=&quot;부동산 투자.PNG&quot; data-origin-width=&quot;1352&quot; data-origin-height=&quot;362&quot; width=&quot;750&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;지금은 강의 시청 중 :)&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p&gt;결론부터 말씀드리면 부동산 공부를 처음 시작하신다면 정말 추천드립니다.&lt;/p&gt;
&lt;p&gt;최근 들어 부동산의 대한 관심이 커지고 앞으로 집을 한 채 사야 겠다는 생각이 들었습니다.&lt;/p&gt;
&lt;p&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;p&gt;13만원 가격이 비싸면 비싸고 저렴하면 저렴한 가격인데 제 기준으로는 비싼 가격이 아니었습니다. &lt;span style=&quot;color: #333333;&quot;&gt;부동산 용어, 투자 방법, 분석 방법 이런 믿을만한 정보들을 한 번에 떠먹기는 쉽지 않습니다.&lt;/span&gt; &lt;b&gt;지금까지 못 했던 부동산 공부들의 대해서 정말 빠르게 기본을 다질 수&lt;/b&gt; 있었거든요.&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;강의를 보고 공부를 하면서 나름의 기준도 생겼고 부동산을 분석하는 방법들도 배웠습니다.&lt;/p&gt;
&lt;p&gt;&lt;b&gt;정말 스스로가 분석도 하실 수&lt;/b&gt; 있습니다. (제가 해보니 강의만 보고 그치면 안 됩니다..)&lt;/p&gt;
&lt;p&gt;지금 생각해보니 유튜브에서 부동산을 분석하는 내용들도 지금 강의 듣고 스스로도 할 수 있을 것 같아요.. 왜냐면 강의에서 중요한 부동산 기준들을 딱 잡아주니까요.&lt;/p&gt;
&lt;p&gt;지금의 기반으로 책도 보고 스스로 분석하면서 부동산 능력을 쌓아 올리면 되겠다는 생각이 듭니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;강의를 듣고 하루아침에 부동산 몇 채를 갖는 건 아니지만 강의를 보고 공부를 함으로써 집을 한 채 가질 수 있겠다는 생각이 듭니다.&lt;b&gt; 새집을 분양받아야 될지 마음과 같아선 지금 투자를 하고 싶다는 생각도 듭니다&lt;/b&gt;. &lt;span style=&quot;color: #333333;&quot;&gt;강의 이후에는 새집 아파트에는 분양신청을 꾸준히 넣기 시작했답니다.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;강의를 듣지 않았더라면 부동산에 대한 관심은 벌써 사라지고 집 마련도 점점 멀어졌을 겁니다. 청약이든 부동산 투자든 전혀 생각을 하지 않고 있었겠죠 ㅠ.ㅠ&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;부동산을 공부해본 적 없었던 저로서는 강의를 듣게 되어 다행입니다.&lt;/p&gt;
&lt;p&gt;어차피 살아가기 위해서는 집이 필요로 하고 집을 사는 김에 괜찮은 집을 사는 게 좋겠지요.&lt;/p&gt;
&lt;p&gt;부동산을 막 시작하신 분들에게는 정말 추천드리는 강의입니다.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;color: #333333;&quot;&gt;기회가 된다면 이광석 튜터님과 차를 한잔 마시고 싶네요.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;감사합니다.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;p.s)&lt;/p&gt;
&lt;p&gt;부동산 공부를 꽤 하셨거나 평소에도 부동산에 관심이 많으셨 던 분은 알고 있는 내용들이 많을 수도 있습니다 ^^&lt;/p&gt;</description>
      <category>Lecture/Life</category>
      <category>VOD</category>
      <category>강의</category>
      <category>부동산</category>
      <category>소액으로</category>
      <category>시작하는</category>
      <category>이광석 튜터님</category>
      <category>탈잉</category>
      <category>투자</category>
      <category>후기</category>
      <author>junngo</author>
      <guid isPermaLink="true">https://junlab.tistory.com/208</guid>
      <comments>https://junlab.tistory.com/208#entry208comment</comments>
      <pubDate>Tue, 7 Apr 2020 18:24:35 +0900</pubDate>
    </item>
  </channel>
</rss>