반응형

1. 시험환경

    ˙ Ubuntu(우분투) Linux(리눅스)

    ˙ ssh-keygen

 

2. 목적

    ˙ ssh-keygen 명령어를 통하여 public 및 private key 생성하는 방법을 알아보자.

 

3. 적용

    ① 우분투 환경에서 아래 명령어를 실행하여 private 및 public key를 생성한다.

        - $ ssh-keygen -q -t rsa -N '' -m PEM -t rsa -b 4096 -C test -f ./id_rsa <<<y >/dev/null 2>&1

 

4. 결과

    ˙ 공개키(.pub)는 github 등 접속을 위한 서버에 등록하여 사용한다.

    ˙ 비밀키(private)는 접속 클라이언트에 등록하여 사용한다.

 

반응형
반응형

1. 시험환경

    ˙ 윈도우

    ˙ Visual Studio Code

    ˙JDK 17

    ˙Spring Boot

 

2. 목적

    ˙ Visual Studio Code에서 Spring Boot 프로젝트를 생성하기 위한 플러그인(plugin)을 설치한다.

    ˙ Visual Studio Code에서 Spring Boot 프로젝트를 생성한다.

    ˙ Spring Boot에 테스트 코드를 입력하고 동작 여부를 확인한다.

 

3. 적용

    ① Visual Studio Code에서 Spring Boot 프로젝트를 지원하기 위한 플러그인들을 설치한다.

        - Extension Pack for Java
        - Spring Boot Extension Pack
        - Lombok Annotations Support for VS Code
        - Spring Initializr Java Support

 

    ② Command Palette에서 "Spring Initializer: [빌드 프로젝트]"를 선택한다.

        - 메뉴 : [View] → [Command Palette]

        - 단축키 : <Ctrl> + <Shift> + <P>

 

    ③ Spring Boot Framework 버전을 선택한다.

 

    ④ 개발 언어, 패키지, 프로젝트명, 빌드파일 형식(jar, war), 자바 버전을 설정한다.

 

    ⑤ 프로젝트에서 사용할 의존성 패캐지를 추가한다.

 

    ⑥ 프로젝트를 구성할 루트 디렉토리를 선택한다.

 

    ⑦ Controller 생성 및 테스트 코드를 작성하고, 프로젝트를 실행한다.

        - 프로젝트 실행 단축키 : <Ctrl> + <F5>

 

4. 결과

    ˙ 프로젝트 실행 여부를 확인한다.

 

    ˙ 프로젝트 파일 다운로드

template-springboot.zip
0.08MB

 

반응형
반응형

1. 시험환경

    ˙ JAVA 17

    ˙ 스프링프레임워크

 

2. 목적

    ˙ JAVA에서 of를 사용하는 이유에 대하여 알아보자.

    ˙ JAVA에서 from을 사용하는 이유에 대하여 알아보자.

 

3. 적용

    ① JAVA의 of와 from 사용 목적

        - 가독성과 유연성을 높이기 위해 도입된 JAVA의 문법적인 요소이다.

        - 주로 컬렉션과 배열을 다룰 때 사용되는 메소드 또는 생성자에 사용된다.

 

    ② of 사용방법

        - of는 주로 불변 컬렉션을 생성하기 위해 사용된다.

        - 이 메소드는 주어진 인수로부터 요소를 생성하고 해당 요소를 포함하는 불변 컬렉션을 반환한다.

        - 아래 코드는 1, 2, 3 세 개의 요소를 포함하는 불변 리스트를 생성한다.

        - 이는 배열 초기화와 유사한 효과를 가지며, 가독성이 높아지고 코드를 간결하게 작성할 수 있게 해준다.

1
List<Integer> numbers = List.of(123);
cs

 

    ③ from 사용방법

    - from은 주로 컬렉션 또는 배열로부터 다른 형태의 컬렉션을 생성할 때 사용된다.

    - 이와 같은 사용법은 기존 컬렉션을 이용하여 새로운 컬렉션을 생성할 때 유용하다.

    - 아래 코드는 existingList라는 기존 컬렉션을 이용하여 새로운 리스트를 생성한다.

1
2
List<Integer> existingList = Arrays.asList(123);
List<Integer> numbers = List.from(existingList);
cs

 

4. 결과

    ˙ 즉, 코드 간결화 및 가독성 향상을 위한 JAVA 문법으로써, 아래와 같이 Spring Framework에서 활용하자.

        - parameter로부터 DTO 또는 Entity를 생성할 때 of

        - Entity와 DTO 간 변환할 때 from

반응형
반응형

1. 시험환경

    ˙ Python

    ˙ JSON

 

2. 목적

    ˙ python을 이용하여 JSON 파일 Parsing 하는 코드를 작성한다.

    ˙ JSON 파일로부터 읽어들인 내용을 출력하는 코드를 작성한다.

 

3. 적용

    ① json 샘플파일은 공공 데이터 포털에서 획득한 아파트 실거래가 정보이다.

sample.json
0.03MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
{
    "response":{
       "header":{
          "resultCode":"00",
          "resultMsg":"NORMAL SERVICE."
       },
       "body":{
          "items":{
             "item":[
                {
                   "거래금액":"250,000",
                   "거래유형":"중개거래",
                   "건축년도":"2010",
                   "년":"2022",
                   "도로명":"소공로",
                   "도로명건물본번호코드":"00046",
                   "도로명건물부번호코드":"00000",
                   "도로명시군구코드":"11140",
                   "도로명일련번호코드":"05",
                   "도로명지상지하코드":"0",
                   "도로명코드":"3101004",
                   "법정동":"회현동2가",
                   "법정동본번코드":"0087",
                   "법정동부번코드":"0000",
                   "법정동시군구코드":"11140",
                   "법정동읍면동코드":"12200",
                   "법정동지번코드":"1",
                   "아파트":"쌍용남산플래티넘",
                   "월":"1",
                   "일":"31",
                   "일련번호":"11140-1123",
                   "전용면적":"177",
                   "중개사소재지":"서울 중구",
                   "지번":"87",
                   "지역코드":"11140",
                   "층":"23",
                   "해제사유발생일":"None",
                   "해제여부":"None"
                },
                {
                   "거래금액":"59,500",
                   "거래유형":"직거래",
                   "건축년도":"1982",
                   "년":"2022",
                   "도로명":"퇴계로50길",
                   "도로명건물본번호코드":"00042",
                   "도로명건물부번호코드":"00000",
                   "도로명시군구코드":"11140",
                   "도로명일련번호코드":"01",
                   "도로명지상지하코드":"0",
                   "도로명코드":"4103357",
                   "법정동":"묵정동",
                   "법정동본번코드":"0011",
                   "법정동부번코드":"0002",
                   "법정동시군구코드":"11140",
                   "법정동읍면동코드":"13600",
                   "법정동지번코드":"1",
                   "아파트":" 충무",
                   "월":"1",
                   "일":"27",
                   "일련번호":"11140-16",
                   "전용면적":"54.18",
                   "중개사소재지":"None",
                   "지번":"11-2",
                   "지역코드":"11140",
                   "층":"1",
                   "해제사유발생일":"None",
                   "해제여부":"None"
                },
                {
                   "거래금액":"25,000",
                   "거래유형":"직거래",
                   "건축년도":"2020",
                   "년":"2022",
                   "도로명":"동호로33길",
                   "도로명건물본번호코드":"00015",
                   "도로명건물부번호코드":"00000",
                   "도로명시군구코드":"11140",
                   "도로명일련번호코드":"00",
                   "도로명지상지하코드":"0",
                   "도로명코드":"4103109",
                   "법정동":"오장동",
                   "법정동본번코드":"0145",
                   "법정동부번코드":"0001",
                   "법정동시군구코드":"11140",
                   "법정동읍면동코드":"15400",
                   "법 정동지번코드":"1",
                   "아파트":"오렌지카운티을지로",
                   "월":"1",
                   "일":"1",
                   "일련번호":"11140-1355",
                   "전용면적":"14.37",
                   "중개사소재지":"None",
                   "지번":"145-1",
                   "지역코드":"11140",
                   "층":"14",
                   "해제사유발생일":"22.01.21",
                   "해제여부":"O"
                },
                {
                   "거래금액":"25,000",
                   "거래유형":"직거래",
                   "건축년도":"2020",
                   "년":"2022",
                   "도로명":"동호로33길",
                   "도로명건물본번호코드":"00015",
                   "도로명건물부번호코드":"00000",
                   "도로명시군구코드":"11140",
                   "도로명일련번호코드":"00",
                   "도로명지상지하코드":"0",
                   "도로명코드":"4103109",
                   "법정동":"오장동",
                   "법정동본번코드":"0145",
                   "법정동부번코드":"0001",
                   "법정동시군구코드":"11140",
                   "법정동읍면동코드":"15400",
                   "법정동지번코드":"1",
                   "아파트":"오렌지카운티을지로",
                   "월":"1",
                   "일":"1",
                   "일련번호":"11140-1355",
                   "전용면적":"14.37",
                   "중개사소재지":"None",
                   "지번":"145-1",
                   "지역코드":"11140",
                   "층":"15",
                   "해제사유발생일":"22.02.03",
                   "해제여부":"O"
                }
             ]
          },
          "numOfRows":"1000",
          "pageNo":"1",
          "totalCount":"19"
       }
    }
 }
cs

 

    ② 동일 폴더에 있는 sample.json 파일 Parsing 및 출력 코드를 작성한다.

main.py
0.00MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import json
 
 
if __name__ == '__main__':
 
    jsonFile = './sample.json'
    with open(jsonFile, encoding='UTF-8'as f:
        data = json.load(f)
 
    aptDealList = list()
    if data['response']['header']['resultCode'== '00':
        aptDealList = data['response']['body']['items']['item']
 
    for item in aptDealList:
        print(item)
    
cs

 

4. 결과

    ˙ 코드 실행 결과 json 파일을 Parsing하여 출력한다.

반응형
반응형

1. 시험환경

    ˙ Ubuntu

    ˙ Docker

 

2. 목적

    ˙ 일반 사용자에게 Docker 실행권한을 부여한다.

 

3. 적용

    ① docker 실행 후 build 명령어를 실행을 시도하면, 일반 계정은 권한이 막혀있는 것을 확인할 수 있다.

        - 명령어 : $ docker build .

1
2
3
4
Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock:
Post "http://%2Fvar%2Frun%2Fdocker.sock/v1.24/build?buildargs=%7B%7D&cachefrom=%5B%5D&cgroupparent=&cpuperiod=0&cpuquota=0&cpusetcpus=&cpusetmems=&cpushares=
0&dockerfile=Dockerfile&labels=%7B%7D&memory=0&memswap=0&networkmode=default&rm=1&shmsize=0&target=&ulimits=null&version=1":
dial unix /var/run/docker.sock: connect: permission denied
cs

 

    ② 현재 로그인한 계정($USER)을 docker group에 포함시킨다.

        - 명령어 : $ sudo usermod -a -G docker $USER

 

    ③ 시스템 재기동 후 해당 ID에 docker group 권한이 부여되었음을 확인한다.

        - 명령어 : $ id

 

4. 결과

    ˙ 접속 계정으로 docker build 명령어가 동작됨을 확인한다.

        - 명령어 : $ docker build .

반응형
반응형

1. 시험환경

    ˙ SpringBoot

    ˙ Spring Data JPA

    ˙ MariaDB

 

2. 목적

    ˙ Pageable 기능을 이용하여 데이터 가져오는 방법을 알아보자.

 

3. 적용

    ① Spring Data JPA를 이용하여 DB 테이블 및 테스트 데이터를 생성하였다.

        - URL : https://languagestory.tistory.com/244

 

Spring Data JPA 설정 및 초기 데이터 생성

1. 시험환경 ˙ Spring Boot ˙ Spring-Data-JPA ˙ MariaDB 2. 목적 ˙ Spring Data JPA 설정하는 방법을 알아보자. ˙ Entity와 Repository만 작성하여 DB 테이블을 생성한다. ˙ Spring 프로젝트 실행 시 data.sql 초기 데이터

languagestory.tistory.com

 

    ② PagingAndSortingRepository를 상속 받는 Repository 인터페이스를 생성한다.

        - DB 데이터 조회 함수의 Paging 파라미터 및 Return Type을 선언한다.

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.pageable.repository;
 
import com.example.pageable.domain.Nation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.repository.PagingAndSortingRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
 
@RepositoryRestResource
public interface NationsRepository extends PagingAndSortingRepository<Nation, String> {
  Page<Nation> findAll(Pageable pageable);
}
cs

 

    ③ Controller에서 데이터를 읽어올 부분 PageRequest(page, size)를 정의하고 Pageable 변수를 전달한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.example.pageable.controller;
 
import com.example.pageable.domain.Nation;
import com.example.pageable.repository.NationsRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
 
@RestController
@RequiredArgsConstructor
public class NationController {
  private final NationsRepository nationsRepository;
 
  @GetMapping("/")
  public Page<Nation> pageableTest() {
 
    Pageable firstPageWithTwoElements = PageRequest.of(12);
    return nationsRepository.findAll(firstPageWithTwoElements);
  }
}
cs

 

4. 결과

    ˙ 페이지 당 건수 및 원하는 쪽수에 해당하는 데이터를 불러온다.

 

    ˙ 프로젝트 다운로드

pageable-jpa-example.zip
0.12MB

 

반응형
반응형

1. 시험환경

    ˙ Spring Boot

    ˙ MariaDB

 

2. 목적

    ˙ Spring-Rest-Data 패키지 설정하는 방법을 알아보자.

    ˙ Domain과 Repository만을 가지고 빠르게 REST API 서버를 구축하는 방법을 알아보자.

 

3. 적용

    ① Spring Data JPA를 이용하여 DB 테이블 및 테스트 데이터를 생성하였다.

        - URL : https://languagestory.tistory.com/244

 

Spring Data JPA 설정 및 초기 데이터 생성

1. 시험환경 ˙ Spring Boot ˙ Spring-Data-JPA ˙ MariaDB 2. 목적 ˙ Spring Data JPA 설정하는 방법을 알아보자. ˙ Entity와 Repository만 작성하여 DB 테이블을 생성한다. ˙ Spring 프로젝트 실행 시 data.sql 초기 데이터

languagestory.tistory.com

 

    ② Spring-Data-Rest 의존성 패키지를 설치한다.

        - src/build.gradle

1
2
implementation 'org.springdoc:springdoc-openapi-data-rest:1.6.15'
implementation 'org.springframework.boot:spring-boot-starter-data-rest'
cs

 

    ③ Spring-Data-Rest 설정하여, "/api"로 시작하는 URL은 Open API 로 제공한다.

        - src/main/resource/application.yaml

1
2
3
4
  data.rest:
    base-path: /api
    default-page-size: 10
    max-page-size: 10
cs

 

    ④ Entity 클래스를 정의한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.example.datarest.domain;
 
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
 
 
@Entity
@Getter
@ToString
public class Nation {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
 
  @Setter
  private String nation;
 
  @Setter
  private int population;
 
  @Setter
  private String lang;
 
  @Setter
  private String currency;
 
}
cs

 

     Repository 인터페이스에 @RepositoryRestResource를 추가한다.

        -  Controller 및 Service 없이 미 정의된 로직에 따라 처리되어 Rest API 서버 개발이 가능하다.

1
2
3
4
5
6
7
8
9
10
package com.example.datarest.repository;
 
import com.example.datarest.domain.Nation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
 
@RepositoryRestResource
public interface NationsRepository extends JpaRepository<Nation, String> {
}
 
cs

 

    ⑥ endpoint를 호출하는 방법은 각 엔티티 클래스에 s를 붙인 형태로하거나 Repository에서 지정할 수 있다.

        - @RepositoryRestResource(path = "endpoint명")

 

4. 결과

    ˙ 여기서는 endpoint를 지정하지 않았으므로 Entity 클래스 이름에 s를 추가하여 호출한다.

        - http://localhost:8080/api/nations

 

    ˙ 프로젝트 다운로드

data-rest-example.zip
0.12MB

반응형
반응형

1. 시험환경

    ˙ Spring Boot

    ˙ Spring-Data-JPA

    ˙ MariaDB

 

2. 목적

    ˙ Spring Data JPA 설정하는 방법을 알아보자.

    ˙ Entity와 Repository만 작성하여 DB 테이블을 생성한다.

    ˙ Spring 프로젝트 실행 시 data.sql 초기 데이터를 Insert 한다.

 

3. 적용

    의존성 패키지를 설치한다.

        - src/build.gradle

1
2
3
4
5
6
7
8
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    compileOnly 'org.projectlombok:lombok'
    runtimeOnly 'org.mariadb.jdbc:mariadb-java-client'
    annotationProcessor 'org.projectlombok:lombok'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
cs

 

    MariaDB 연결 및 JPA 설정 부분을 작성한다.

        - src/main/resources/application.yaml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring:
  datasource:
    url: jdbc:mariadb://[IP:PORT]/[DB]?characterEncoding=UTF-8
   username: [ID]
   password: [PASSWORD]
  jpa:
    defer-datasource-initialization: true
    hibernate:
      ddl-auto: create
      show-sql: true
    properties:
      hibernate.format_sql: true
      hibernate.default_batch_fetch_size: 100
  sql:
    init:
      mode: always
cs

 

    ② DB 테이블과 매치된 클래스인 Entity를 작성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package com.example.datarest.domain;
 
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
 
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
 
 
@Entity
@Getter
@ToString
public class Nation {
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
 
  @Setter
  private String nation;
 
  @Setter
  private int population;
 
  @Setter
  private String lang;
 
  @Setter
  private String currency;
 
}
cs

 

    ③ CRUD를 위한 Repository 인터페이스를 생성한다.

1
2
3
4
5
6
7
8
9
package com.example.datarest.repository;
 
import com.example.datarest.domain.Nation;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;
 
@RepositoryRestResource
public interface NationsRepository extends JpaRepository<Nation, String> {
}
cs

 

    ④ Entity 매핑 테이블에서 사용할 데이터를 작성한다.

        - src/main/resources/data.sql

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
insert into nation (nation, population, lang, currency) values
('America'50000'English''Dollar')
;
 
insert into nation (nation, population, lang, currency) values
('Swizerland'2000'Swiss''Frank')
;
 
insert into nation (nation, population, lang, currency) values
('England'60000'English''Found')
;
 
insert into nation (nation, population, lang, currency) values
('Italiy'4000'Italian''Euro')
;
cs

 

4. 결과

    ˙ Spring Boot 프로젝트를 실행 후 DB에서 Entity 매핑 테이블과 데이터가 초기화 되었는지 확인한다.

 

    ˙ 프로젝트 파일 다운로드

data-jpa-example.zip
0.12MB

반응형

+ Recent posts