MSA구성매뉴얼

1.    문서 개요

 

1.1       문서의 목적

본 문서는 MSA 기반의 API 샘플 서버, 게이트웨이 서버, 유레카 서버 등에 대한 구축 관련 절차에 대하여 기술하고 있다.

1.2       시스템 구성도

본 프로젝트에서 구현되고자 하는 시스템 구성도이다.

 

 

2.    관련 어플리케이션 설치

2.1       JDK 설치

JDK 1.8이상으로 본 문서에서는 64비트용 JDK15를 기준으로 한다.

2.2       Eclipse 설치

2.2.1        이클립스 설치

– https://www.eclipse.org/downloads/packages/ 에서 64 비트용 Eclipse IDE for Enterprise Java Developers 을 선택

 

2.2.2        Spring Boot STS(Spring Tool Suite) 설치

Help > Eclipse Marketplace 를 선택한후에 STS 를 입력하여 검색한후에, Spring Tools 4 (aka Spring Tool Suite 4) 를 선택하여 설치한다.

2.2.3        롬복(Lombok) 설치

Getter와 Setter를 자동으로 생성해주는 라이브러리로 Visual Studio Code에서는 별다른 설치 없어 개발 IDE의 인텔리전트가 잘 나왔지만, 이클립스는 별도로 설치해주어야 동작한다.

  • 탐색기로 해당 계정의 maven repository에 들어가서 버전을 확인

C:\Users\계정\.m2\repository\org\projectlombok\lombok\버전

 

  • 롬복 설치 관리자 실행

아래 명령을 통해 실행

Java -jar lombok-버전.jar

  • 이클립스 위치지정

“Specify location…” 버튼을 클릭하여 이클립스가 설치되어 있는 위치 지정하고

“Install/Update” 버튼을 클릭하여 설치완료

 

 

 

2.3       Postman 설치

API 서버를 호출하여 결과를 확인하기가 용이하므로 테스트할 때 많이 사용되는 툴이다.

https://www.postman.com/downloads/ 에서 64비트용을 다운받아 설치한다.

설치 후 Signin을 클릭하여 로그인하면 되고, 계정이 없으면 가입하면 된다.

 

사용방법은 탭 옆에 “+” 버튼을 클릭하여 새로운 Request를 생성하여 실행하면 된다.

 

일례로 Method를 GET으로 하고, url을 입력하고 Send 버튼을 클릭하면 하단에 결과가 출력된다.

 

 

3.    메이븐(Maven) 기반의 Spring Boot 프로젝트 생성

이클립스를 띄워 아래와 같이 워크스페이스를 만든다.

  • D:\Projects\45.ValfacSolutions\02.Solutions\MsaSolution

3.1       최상단 부모 프로젝트 생성

  • File > New > Other 를 클릭한후 Spring Boot를 선택한후 Spring Starter Project를 선택

 

  • 프로젝트 정보 입력

본 샘플에서는 store라는 이름으로 프로젝트를 구성하였다.

– Name : store

– Group :store

– Artifact : store

– Description : Store Project

– Package : store

 

  • 스프링 부트 버전 및 프로젝트 종속성 입력

아래와 같이 Spring Boot Version을 현재 최신인 2.3.4를 선택하고, 3가지 종속성을 체크하여 추가한후에 “Finish” 버튼을 클릭하여 프로젝트를 생성한다.

– Developer Tools > Spring Boot DevTools

– Developer Tools > Lombok

– Web > Spring Web

 

  • xml 파일 수정

아래와 같이 <packaging>pom</packaging>를 추가한다.

 

3.2       하위 자식 모듈 생성

최상단 부모 메이븐 프로젝트 밑에 딸린 자식 모듈은 다음과 같다.

 

명칭 모듈명 포트 비고
유레카 서버 store-eureka-server 8761
게이트웨이서버 store-gateway-server 5001
회사 API(샘플) store-corp-api 5002
사용자 API(샘플) store-user-api 5003
백엔드 웹 store-backend-web 8080 Feign Client 포함

 

3.2.1        게이트웨이 서버

아래와 같이 Maven Module을 생성한다.

  • File > New > Other에서 Maven > Maven Module을 선택하고 “Next” 버튼 클릭

 

 

  • 모듈명 입력

“create a simple project” 를 체크 하고, Module Name에 “store-gateway-server”를 입력하고 “Next” 버튼을 클릭한다.

  • 기타 모듈정보를 입력하고 “Finish” 버튼 클릭

– Group Id : store.gateway.server

– Version : 0.0.1-SNAPSHOT

– Packaging: jar

– Name : Store Gateway Server

– Description : Store Gateway Server Project

  • 최상단 부모 프로젝트의 xml 파일 확인 및 수정

– 위에서 생성한 store-gateway-server 메이븐 모듈이 자동적으로 추가된 것을 확인할 수 있다.

– 또한 넷플릭스의 Zuul을 사용하기 위해 부모 pom.xml에도 종속성을 추가해야 한다.

 

(중         략)

 

<modules>

<module>store-gateway-server</module>

</modules>

 

<repositories>

<repository>

<id>spring-snapshots</id>

<name>Spring Snapshots</name>

<url>https://repo.spring.io/snapshot</url>

<snapshots>

<enabled>true</enabled>

</snapshots>

</repository>

<repository>

<id>spring-milestones</id>

<name>Spring Milestones</name>

<url>https://repo.spring.io/milestone</url>

<snapshots>

<enabled>false</enabled>

</snapshots>

</repository>

</repositories>

 

<properties>

<java.version>11</java.version>

       <spring-cloud.version>Hoxton.SR5</spring-cloud.version>

</properties>

 

<dependencies>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-devtools</artifactId>

<scope>runtime</scope>

<optional>true</optional>

</dependency>

<dependency>

<groupId>org.projectlombok</groupId>

<artifactId>lombok</artifactId>

<optional>true</optional>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-test</artifactId>

<scope>test</scope>

<exclusions>

<exclusion>

<groupId>org.junit.vintage</groupId>

<artifactId>junit-vintage-engine</artifactId>

</exclusion>

</exclusions>

</dependency>

</dependencies>

 

<dependencyManagement>

<dependencies>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-dependencies</artifactId>

<version>${spring-cloud.version}</version>

<type>pom</type>

<scope>import</scope>

</dependency>

</dependencies>

</dependencyManagement>

 

<build>

<plugins>

<plugin>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-maven-plugin</artifactId>

</plugin>

</plugins>

</build>

 

 

 

 

  • 해당 자식 모듈(store-gateway-server)의 xml에도 스프링 부트 관련 종속성 명기
<project xmlns=“http://maven.apache.org/POM/4.0.0” xmlns:xsi=“http://www.w3.org/2001/XMLSchema-instance” xsi:schemaLocation=“http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd”>

<modelVersion>4.0.0</modelVersion>

<parent>

<groupId>store</groupId>

<artifactId>store</artifactId>

<version>0.0.1-SNAPSHOT</version>

</parent>

 

<groupId>store.gateway.server</groupId>

<artifactId>store-gateway-server</artifactId>

<version>0.0.1-SNAPSHOT</version>

<name>Store Gateway Server</name>

<description>Store Gateway Server Project</description>

 

<dependencies>

<!– 주울(Zuul) –>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-zuul</artifactId>

</dependency>

</dependencies>

</project>

 

  • 패키지 생성

소스를 생성하기위해 먼저 패키지를 만든다.

– 패키지명 : store.gateway.server

  • Application.java 파일생성

– New > Class로 main이 있는 Application 파일생성

  • Application.java 파일수정

Annotation에 @EnableZuulProxy 등을 입력

@EnableZuulProxy

@SpringBootApplication

public class Application

{

public static void main(String[] args)

{

SpringApplication.run(Application.class, args);

}

}

 

  • 환경설정파일 추가

어플리케이션 설정에 필요한 환경설정 파일로 resources 폴더에 application.yml 이라는 이름으로 만들고 아래와 같이 작성한다.

spring:

application:

name: store-gateway-server

 

server:

port: 5001

 

 

# 주울

zuul:

routes:

store-corp-api:

path: /corpsvc/**

url: http://localhost:5002

stripPrefix: true

 

store-user-api:

path: /usersvc/**

url: http://localhost:5003

stripPrefix: true

 

 

Zuul 설정은 게이트웨이를 통해 다음절에서 다오는 회사API와 사용자API에게 라우팅해주는 기능이다.

가령 http://localhost:5001/corpsvc/api/corp/findAll  과 같이 게이트웨이(5001포트)를 통해 패스가 /corpsvc/** 형태로 들어오는 경우는 URL을

http://localhost:5002/api/corp/findAll 로 요청하여 반환하게 된다.

 

  • 실행

위에서 작성한 소스를 실행하려면 Run AS > Spring Boot App 를 선택하여 실행하면 된다.

 

 

3.2.2        회사 API(샘플)

아래와 같이 Maven Module을 생성한다.

  • File > New > Other에서 Maven > Maven Module을 선택하고 “Next” 버튼 클릭

  • 모듈명 입력

“create a simple project” 를 체크 하고, Module Name에 “store-corp-api”를 입력하고 “Next” 버튼을 클릭한다.

 

  • 기타 모듈정보를 입력하고 “Finish” 버튼 클릭

– Group Id : store.corp.api

– Version : 0.0.1-SNAPSHOT

– Packaging: jar

– Name : Store Corp API

– Description : Store Corp API Project

  • 패키지 생성

소스를 생성하기위해 먼저 패키지를 만든다.

– 패키지명 : store.corp.api

  • Applicaiton.java 파일생성

– New > Class로 main이 있는 Application 파일생성

 

  • Applicaiton.java 파일수정
@SpringBootApplication

@EnableAutoConfiguration

public class Application

{

public static void main(String[] args)

{

SpringApplication.run(Application.class, args);

}

}

 

 

 

 

  • 환경설정파일 추가

어플리케이션 설정에 필요한 환경설정 파일로 resources 폴더에 application.yml 이라는 이름으로 만들고 아래와 같이 작성한다.

spring:

application:

name: store-corp-api

 

server:

port: 5002

 

 

 

 

  • 컨트롤러 패키지 작성

– store.corp.api.controllers

  • 컨트롤러 작성 : CorpController.java

  • 실행

위에서 작성한 소스를 실행하려면 Run AS > Spring Boot App 를 선택하여 실행하면 된다.

 

 

3.2.3        사용자 API(샘플)

회사 API[샘플]과 동일하게 Maven Module을 생성한다.

  • 모듈명 : store- user -api

 

  • 모듈정보

– Group Id : store.user.api

– Version : 0.0.1-SNAPSHOT

– Packaging: jar

– Name : Store User API

– Description : Store User API Project

 

  • 패키지 생성

– 패키지명 : store.user.api

 

  • java 파일생성 및 수정
@SpringBootApplication

@EnableAutoConfiguration

public class Application

{

public static void main(String[] args)

{

SpringApplication.run(Application.class, args);

}

}

 

  • 환경설정파일 추가

– resources\application.yml

spring:

application:

name: store-user-api

 

server:

port: 5003

 

 

 

  • 컨트롤러 패키지 작성

– store.user.api.controllers

 

  • 컨트롤러 작성 : UserController.java

 

  • 실행

위에서 작성한 소스를 실행하려면 Run AS > Spring Boot App 를 선택하여 실행하면 된다.

3.2.4        유레카 서버

유레카는 MSA를 동적 등록 및 탐색, 부하분산처리 기능을 한다.

유레카는 위와 동일하게 Maven Module로 생성한다.

  • File > New > Other에서 Maven > Maven Module을 선택하고 “Next” 버튼 클릭

 

  • 모듈명 입력

“create a simple project” 를 체크 하고, Module Name에 “store-eureka-server”를 입력하고 “Next” 버튼을 클릭한다.

  • 기타 모듈정보를 입력하고 “Finish” 버튼 클릭

– Group Id : store.eureka.server

– Version : 0.0.1-SNAPSHOT

– Packaging: jar

– Name : Store Eureka Server

– Description : Store Eureka Server Project

  • xml 파일 확인 및 수정
<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>

</dependency>

 

  • 패키지 생성

소스를 생성하기위해 먼저 패키지를 만든다.

– 패키지명 : store.eureka.server

 

  • Application.java 파일생성

– New > Class로 main이 있는 Application 파일생성

 

  • Application.java 파일수정

유레카 서버로 사용할 수 있게, @EnableEurekaServer Annotation을 입력

 

@EnableEurekaServer

@SpringBootApplication

public class Application

{

public static void main(String[] args)

{

SpringApplication.run(Application.class, args);

}

}

 

 

 

 

 

  • 환경설정파일 추가

어플리케이션 설정에 필요한 환경설정 파일로 resources 폴더에 application.yml 이라는 이름으로 만들고 아래와 같이 작성한다.

spring:

application:

name: store-eureka-server

 

server:

port: 8761

 

eureka:

client:

register-with-eureka: false

fetch-registry: false

 

 

  • 실행 및 유레카 서버 접속

위에서 작성한 소스를 실행하려면 Run AS > Spring Boot App 를 선택하여 실행하면 된다.

그후에 웹 브라우져에서  http://localhost:8761/ 로 접속하면 유레카에서 제공하는 페이지를 볼수 있다.

 

 

  • MSA 클라이언트 등록

위 화면에서는 등록된 MSA 클라이언트의 정보를 볼 수 있는데 현재 등록된 MSA 클라이언트가 없으므로 아래와 같이 등록 해야 한다.

 

– 각 MSA클라이언트별 종속성 추가

store-gateway-server, store-corp-api, store-user-api 모듈을 유레카 클라이언트로

설정한다. 따라서 각 모듈에 종속성을 추가한다.

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

</dependency>

 

– 각 모듈의 Application.java 에 @EnableDiscoveryClient 아노테이션을 추가

 

@EnableDiscoveryClient

@SpringBootApplication

public class Application

{

public static void main(String[] args)

{

SpringApplication.run(Application.class, args);

}

}

 

– 각 모듈의 application.yml에 유레카 설정 추가

spring:

application:

name: store-gateway-server

 

server:

port: 5001

 

 

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka

 

– 각 모듈을 RUN시키고 유레카 콘솔(http://localhost:8761/)을 릴로드 해보면 다음과 같이 등록된 MSA 클라이언트를 확인할수 있다.

  • 게이트웨이 설정

유레카를 이용 할 때 는 이전에 게이트웨이서버의 환경설정을 아래처럼 수정되어야 한다.

이전에는 URL로 호출되었지만, 유레카 이용시에는 serviceId로 처리하면 된다.

# 주울

zuul:

routes:

store-corp-api:

path: /corpsvc/**

serviceId: store-corp-api

#url: http://localhost:5002

stripPrefix: true

 

store-user-api:

path: /usersvc/**

serviceId: store-user-api

#url: http://localhost:5003

stripPrefix: true

 

 

참고로 위의 serviceId는 반드시 아래처럼 각서버의 application.yml에 정의된

이름(spring.application.name) 이어야 한다.

spring:

application:

name: store-user-api

 

 

3.2.5        백엔드 웹(Backend Web)

백엔드 웹에서는 JSP상에서 ajax를 이용하여 MSA로 접근하여 데이터를 가져오는 방법,  Feign 클라이언트를 이용하여 데이터를 가져오는 방법에 대하여 구현하였다.

 

  • Module로 모듈생성

– 모듈명 : store-backend-web

– Group Id : store.backend.web

– Version : 0.0.1-SNAPSHOT

– Packaging: jar

– Name : Store Backend Web

– Description : Store Backend  Project

 

  • xml 파일 추가

– 톰캣관련 라이브러리(Jasper)

– JSTL 라이브러리

– Feign 클라이언트

– 유레카 클라이언트

– Graceful Shutdown 라이브러리 : 셧다운시 안전하게 종료하기 위해서 사용

– 모델 매퍼

 

<!– 톰캣파서(Jasper) –>

<dependency>

<groupId>org.apache.tomcat.embed</groupId>

<artifactId>tomcat-embed-jasper</artifactId>

</dependency>

 

<!– JSTL 라이브러리 –>

<dependency>

<groupId>javax.servlet</groupId>

<artifactId>jstl</artifactId>

</dependency>

 

<!– Feign 클라이언트 –>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-openfeign</artifactId>

</dependency>

 

<!– 유레카 클라이언트 –>

<dependency>

<groupId>org.springframework.cloud</groupId>

<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>

</dependency>

 

<!– graceful한 종료 처리 –>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-actuator</artifactId>

</dependency>

 

<!– 모델 매퍼 –>

<dependency>

<groupId>org.modelmapper</groupId>

<artifactId>modelmapper</artifactId>

<version>${modelmapper.version}</version>

</dependency>

 

 

 

 

  • 패키지 생성 및 java 파일생성

– 패키지명 : store.backend.web

– Application.java : 해당 모듈이 유레카 클라이언트이므로, @EnableDiscoveryClient 아노테이션과, FeignClient를 사용하기 위한 @EnableFeignClients을 입력한다.

 

@EnableDiscoveryClient

@EnableFeignClients

@SpringBootApplication

public class Application

{

public static void main(String[] args)

{

SpringApplication.run(Application.class, args);

}

}

 

 

  • 환경설정파일(resouces/application.yml) 추가

– jsp파일의 위치 및 확장자 등에 대한 설정

– 실행중인 쓰레드가 있는경우 처리 후 종료할 수 있도록 하기 위한 우아한 종료처리에 대한 설정

# 스프링 어플리케이션 명(유레카에서 사용됨)

spring:

application:

name: store-backend-web

 

# 스프링 JSP 설정

mvc:

view:

prefix: /WEB-INF/jsp/

suffix: .jsp

 

# 어플리케이션 포트

server:

port: 8080

 

# 유레카 설정

eureka:

client:

serviceUrl:

defaultZone: http://localhost:8761/eureka

 

# 우아한 종료 처리

management:

endpoints:

shutdown:

enabled: true

sensitive: false

web:

exposure:

include: “*”

 

 

  • 교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS) 설정

Ajax 또는 Axios 에서 다른 도메인으로 콜하기 위해 Cors 설정하여 허락을 해주어야한다.

store.backend.web.config 패키지에 WebConfig.java 파일을 생성하고 아래처럼 기술한다.

 

@Configuration

public class WebConfig

{

public void addCorsMappins(CorsRegistry clsCors)

{

clsCors.addMapping(“/**”)

.allowedOrigins(“*”);

}

}

 

 

  • Feign 클라이언트

Feign 클라이언트는 인터페이스와 아노테이션만으로도 API서버로부터 데이터를 보다 더 싶게 수신받기 위한 클라이언트이다.

store.backend.web.corpuser.client 라는 패키지를 만들고 아래와 같이 클라이언트를 만든다.

– CorpClient.java : store-corp-api 서버로부터 데이터를 수신하는 Feign 클라이언트

//@FeignClient(name=”store-corpapi“)

@FeignClient(name=”store-corp-api”, url=”http://localhost:5001″)

public interface CorpClient

{

//@GetMapping(“/api/corp/findAll”)

@GetMapping(“/corpsvc/api/corp/findAll”)

List<CorpMast> findAll();

}

 

 

– UserClient.java : store-user-api 서버로부터 데이터를 수신하는 Feign 클라이언트

//@FeignClient(name=”store-user-api“)

@FeignClient(name=”store-user-api”, url=”http://localhost:5001″)

public interface UserClient

{

//@GetMapping(“/api/user/findAll”)

@GetMapping(“/usersvc/api/user/findAll”)

List<UserMast> findAll();

}

 

 

  • FeignClient는 name과 url을 적어야하는데 URL이 없으면, 유레카를 이용하기 때문에 유레카에 등록된 명칭으로 동작하게 된다. 즉 각 API서버의 yml에 기록한 name으로 서버를 찾아가기 때문에 명칭이 application.yml에 등록한 이름과 동일해야 한다.
  • URL이 5001번포토를 사용한다는 뜻은 게이트웨어 서버를 이용하여 접속한다는 뜻이다. 따라서 GetMappinig에서는 게이트웨어서버의 yml에 정의된 /corpsvc/나 /usersvc/를 붙어주어야 한다.

 

 

  • Service 작성

위에서 만든 FeignClient를 이용하여 서비스를 만든다.

 

@Service

public class CorpUserService

{

@Autowired

CorpClient mClsCorpClient; // 회사Feign 클라이언트

@Autowired

UserClient mClsUserClient; // 사용자Feign 클라이언트

@Autowired

ModelMapper mClsModelMapper;        // 모델매퍼

 

/**

* 회사정보를 리턴한다.

* @return

*/

public ResponseEntity<?> selectCorpData()

{

return ResponseEntity.ok(mClsCorpClient.findAll());

}

 

/**

* 사용자정보를 리턴한다.

* @return

*/

public ResponseEntity<?> selectUserData()

{

return ResponseEntity.ok(mClsUserClient.findAll());

}

 

/**

* 회사와 사용자정보를 조합하여 리턴한다.

* @return

*/

public ResponseEntity<?> selectCombineData()

{

Map<String, CorpUser> hmBuffer = new HashMap<String, CorpUser>();

 

for(CorpMast clsCorp : mClsCorpClient.findAll())

{

// CorpMast에서 CorpUser로 복사

CorpUser clsDest = mClsModelMapper.map(clsCorp, CorpUser.class);

clsDest.user = new ArrayList<UserMast>();

hmBuffer.put(clsCorp.corpId, clsDest);

}

 

for(UserMast clsUser : mClsUserClient.findAll())

{

String strKey = clsUser.corpId;

if(hmBuffer.containsKey(strKey))

{

// CorpUser의 user에 추가

CorpUser clsDest = hmBuffer.get(strKey);

clsDest.user.add(clsUser);

}

}

List<CorpUser> lstCorpUser = new ArrayList<>(hmBuffer.values());

return ResponseEntity.ok(lstCorpUser);

}

}

 

 

  • Controller 작성
 

@Controller

public class CorpUserController

{

@Autowired

CorpUserService mClsService;

 

@RequestMapping(value=”/”)

public String index()

{

return “index”;

}

 

@RequestMapping(value=”/selectCorpData”)

public ResponseEntity<?> selectCorpData()

{

return mClsService.selectCorpData();

}

 

@RequestMapping(value=”/selectUserData”)

public ResponseEntity<?> selectUserData()

{

return mClsService.selectUserData();

}

 

@RequestMapping(value=”/selectCombineData”)

public ResponseEntity<?> selectCombineData()

{

return mClsService.selectCombineData();

}

}

 

 

  • JSP 파일작성

위 Controller.java 에서 “/”를 입력하면 index를 호출하도록 코딩 되어 있기 때문에

src\main\webapp\jsp 에 index.jsp 파일을 만들고 샘플을 만들면 된다.

Spring boot에서 static 파일의 위치는 “src\main\resources\static” 이므로 Javascript,

stylesheet, image 등은 이곳에 넣어두고 요청하면 된다.

 

 

 

코딩이 완료되면 http://localhost:8080/ 으로 접속하면 작성된 화면을 볼수 있다.

 

 

 

4.    스웨거(Swagger)

API에 대한 문서화 및 시각화를 위한 프레임워크로, springfox 라이브러리와 springdoc 라이브러리가 있다. 기존에는 springfox를 많이 사용하여 문서화를 하였으나, OpenAPI 3.0 지원이 늦고 오류가 많아 나중을 생각하여 springdoc을 사용하기로 하였다.

springdoc-openapi가 지원하고 있는 항목은 다음과 같다.

  • OpenAPI 3
  • Spring Boot(V1, V2)
  • JSR-303(@NotNull, @Min, @Max, @Size)
  • Swagger-ui
  • OAuth 2

 

4.1       의존성 추가(POM.xml)

<dependency>

<groupId>org.springdoc</groupId>

<artifactId>springdoc-openapi-ui</artifactId>

<version>1.4.1</version>

</dependency>

 

4.2       환경설정(SpringDocConfig.java)

@Configuration

public class SpringDocConfig

{

@Bean

public OpenAPI openAPI()

{

return new OpenAPI().info(new Info().title(“회사 API”)

.description(“회사 AOI에 대한 샘플 입니다.”)

.version(“v0.0.1”)

.license(new License()

.name(“Apache 2.0”).url(“http://springdoc.org”)));

}

}

 

 

4.3       Controller

  • Tag : 클래스에 대한 설명
  • Operation : 메소드에 대한 설명
  • ApiResponses: API 응답에 대한 설명 및 리턴 클래스 명시
  • Parameter : 메소드에 대한 파라미터 설명
@RestController

@RequestMapping(“/api/corp”)

@Tag(name=”CorpController”, description=”회사정보 컨트롤러”)

public class CorpController

{

@Autowired

private CorpService mClsService;

 

@GetMapping(value = “findAll”)

@Operation(summary=”회사정보 검색”, description=”회사정보를 검색 합니다.”)

        @ApiResponses(value = {

                       @ApiResponse(responseCode = “200”, description = “회사정보를 리턴한다.”,

                              content= { @Content(schema = @Schema(implementation = CorpMast.class)) }

                       ),

                       @ApiResponse(responseCode = “404”, description = “회사정보를 찾을수 없습니다.”)

        })     

public ResponseEntity<?> findAll(@Parameter(description=”기본 파라미터 정보”)

@ModelAttribute final BaseParam clsParam) throws Exception

{

return ResponseEntity.ok(mClsService.findAll(clsParam));

}

}

 

4.4       Model

  • Schema : 모델의 클래스 또는 멤버변수에 대한 설명
@Getter

@Setter

@Schema(description=”기본 파라미터 정보”)

public class BaseParam implements Serializable

{

private static final long serialVersionUID = 1L;

 

@Schema(description=”소트”)

public String sorts;

 

@Schema(description=”페이지NO”)

public Integer pageNo;

 

@Schema(description=”페이지사이즈”)

public Integer pageSize = 10;

 

@Schema(description=”회사ID”, example=”moramcnt”, required = true)

public String corpId;

 

@Schema(description=”사용자ID”)

public String userId;

 

@Schema(description=”타이틀”)

public String title;

 

@Schema(description=”포맷”)

public String format;

 

@Schema(description=”기타 데이터 전송”)

public String data;

 

@Schema(description=”검색 조건”)

public String searchCondition;

 

@Schema(description=”검색어”)

public String searchValue;

}

 

 

 

 

4.5       swagger-ui

http://localhost:5002/swagger-ui.html 으로 접속하여 확인

  • 메소드 테스트

“/api/corp/findAll 회사정보 검색” 을 클릭하여 “Try it out”버튼을 클릭 한후, 파라미터 항목중 corpId를 valuefactory라고 수정한후에 execute 버튼을 클릭한다.

 

 

 

클릭후 하단에는 다음과 같이 valuefactory에 대한 결과가 나타나게 된다.

 

Raspberry PI3에 중국 USIM을 통한 Alcaltel L800MA 연동 테스트

1. 중국유심
China Unicom : uninet
China Telecom : ??
China Mobile (CMCC) : cmnet

[Dialer Defaults] Modem = /dev/ttyUSB1
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CGDCONT=1,”IP”,”cmnet”
Stupid Mode = 1
Modem Type = Analog Modem
Phone = *99#
New PPPD = yes
ISDN = 0
Username = 1
Auto Reconnect = 1
Password = 1
Baud = 9600
Check Def Route = 1

Raspberry PI3에 Alcaltel L800MA 연동

구글링하면 라즈베리파이3에 Alcaltel L800 연동이 쉽게 된다고 써있는 글이 많아
L800MA구입하였으나 모델간의 차이가 있는건지 그대로 하면 안되었다.
사실 wvdial등을 설치하고 쉘에서 명령을 치면서 하면 되는데
나의 경우는 부팅시 자동으로 연결하게 하려고 하다보니, 잘 안된것이다.
아래는 그중 나의 라즈베리파이에서 되는것을 정리한 글이다.

1. 패키지 설치
usb-modeswitch와 ppp는 현재 라즈베파이 2018-03-13 버전을 설치하여보니 존재하고 있어 wvdial만 설치하였다.

$ sudo apt-get update
$ sudo apt-get install wvdial
$ sudo reboot

2. wvdial.conf 파일 수정

$sudo vi /etc/wvdial.conf

아래와 같이 수정

[Dialer Defaults]
Modem = /dev/ttyUSB1
Init1 = ATZ
Init2 = ATQ0 V1 E1 S0=0 &C1 &D2 +FCLASS=0
Init3 = AT+CGDCONT=1,"IP","lte.sktelecom.com","",0,0
Stupid Mode = 1
Modem Type = Analog Modem
Phone = *99#
New PPPD = yes
ISDN = 0
Username = 1
Auto Reconnect = 1
Password = 1
Baud = 9600
Check Def Route = 1

2. interfaces 파일 수정
“iface ppp0 inet wvdial” 를 추가함

$sudo vi /etc/network/interfaces

아래와 같이 수정

# Include files from /etc/network/interfaces.d:
source-directory /etc/network/interfaces.d

auto wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

# PPP
iface ppp0 inet wvdial

3. 부팅시 PPP 활성화 및 기본 라우트 추가

$sudo vi /etc/rc.local

마지막에 아래와 같이 ppp0를 올리고 잠시후 route를 add 하는것을 추가함.

sleep 20
ifup ppp0
sleep 10
route add default dev ppp0 &

Raspberry Pi3 GPS 연동

1. 하드웨어 연결 및 설정
1) 하드웨어 연결
– GPS 연동을 위하여 NEO-6M 모듈을 이용하였다.
– NEO-6M을 라즈베리파이에 연결하기 위해서 NEO-6M의 핀을 다음과 같이 꽂으면 된다.

NEO-6M 라즈베리파이3
VCC PIN01(3.3v)
RX PIN10(GPIO15)
TX PIN08(GPIP14)
GND PIN14

2) 라즈베리파이 설정
GPS를 시리얼로 연결하귀 위해 다음과 같이 설정을 수정한다.
– cmdline.txt 파일 수정

sudo vi /boot/cmdline.txt
dwc_otg.lpm_enable=0 console=tty1 root=PARTUUID=53707d2f-02 rootfstype=ext4 elevator=deadline fsck.repair=yes rootwait

– 파이썬3 시리얼로 GPS 데이터를 받기 위해 시리얼모듈 설치

sudo apt-get install python3-serial

2. NMEA(National Marine Electronics Association) 프로토콜 분석
GPS 모듈을 연결하면 문자열로 된 GPS 데이터가 넘어오는데 이를 NMEA 데이터라 하고,
우리는 이 포맷을 파싱하여 필요한 데이터만 가져다 사용하면 된다.
NMEA의 섹션의 다음과 같다. 하지만 대부분 GPCGA와 GPRMC만 이용하게 된다.

1) $GPGGA: Global Positioning System Fix Data의 약어로 시간 및 경위도 좌표를 구할때 주로 쓰인다.

    Ex) $GPGGA,103022.132,3735.0079,N,12701.6446,E,1,04,5.4,50.1,M,20.6,M,0.0,0000*48
       - 103022.132: 시간
       - 3735.0079 : 위도
       - N은 북위
       - 12701.6446 : 경도
       - E : 동경
       - 1 : Fix의 종류 [0 : 위성이 안 잡혀 Invalid, 1 : GPS에서 제공하는 기본 위성을 가지고만 계산할 경우, 2 : DGPS를 이용하여 보정하여 계산할 경우)
       - '04':  계산에 사용한 위성을 개수
       - '5.4': horizontal dilution of Precision
       - '50.1M' : 해수면 기준 고도
       - '20.6M' : WGS-84에서 정해놓은 타원체로서 모델링한 지구와 구체로서 모델링된 지구의 고도차이
       - '0.0'과 '0000' : DGPS 사용시 마지막으로 update한 시간과 DGPS 기지국의 ID
       - '48': Check Sum

2) $GPRMC: Recommended minimum specific GPS/Transit data의 약어로 최소한의 데이터가 들어오게 되는데 날자가 들어오므로
주로 날짜를 구하기 위해 사용된다.

   EX) $GPRMC,114455.532,A,3735.0079,N,12701.6446,E,0.000000,121.61,110706,,*0A
       - 114455.532: 시간
       - A : GPS 신호의 신뢰성[A: 신뢰, V : 미신뢰]
       - 3735.0079: 위도
       - N : 북위
       - 12701.6446 : 경도
       - E : 동경
       - '0.000000' : Speed over ground로서 knots 단위의 속도- air speed의 약자이다. km/h로 변환시 대략 1.8을 곱한다.
       - '121.61': 방향 
       - '110706' : 날짜
       - ' ' : Magnetic Variation나침반
       - '*0A': 체크섬

3) $GPGSV: GPS satellites in view의 약어로 현재 GPS Module이 수신할 수 있는 모든 위성의 정보를 출력한다.
4) $GPGSA: GPS DOP and active satellites

3. 파이썬을 이용한 NMEA 파싱

1) $GPRMC의 파싱
– GPMRC의 경우 최소한의 정보가 모두 들어오지만, 그중에 제일 중요한것은 날짜가 들어온다는 것이다. 그리고
날짜는 UTC시간이므로 반드시 Locale시간으로 변환해서 사용해야 한다.
– 속도의 경우 단위는 Knots이므로 Km/h로 환산하려면 반드시 * 1.852을 해야 한다.
– 다음은 GPRMC를 파싱한 파이썬 소스 예제이다.

2) $GPGGA의 파싱
– GPGGA는 시간, 경위도, 고도등의 모든 데이터가 들어오기때문에 주의를 기울여 파싱할 필요가 있다. \
– 시간의 경우, UTC시간이므로 Locale 시간으로 변환해서 사용해야 한다.

Raspberry PI 블루투스 설정

1. bluez 설치
라즈베리파이에서 쓸수 있는 블루투스 라이브러리를 다음과 같은 절차로 설치한다.

1) 설치방법
– bluez 설치

– 파이썬용 pybluez 설치

2) 블루투스 동작 확인
다음과 같이 hciconfig 명령을 입력하여 보면 RUNNING 이라고 뜨는것을 확인할수 있다.

– RUNNING아 아니라면 sudo hciconfig hci0 up 를 입력하여 RUNNING상태로 바꾼다.

3) 파이썬용 비콘스캐너 설치
개발전에 비콘값을 제대로 받을수 있는지 테스트하기 위해 오픈소스로 되어 있는 비콘스캐너를 아래와 같이 다운로드 받아 테스트해보았다.
비콘값을 제대로 받는다면 UUID, RSSI등의 값이 출력되는것을 볼수있다.

2.라즈베리파이에서 블루투스와 시리얼 포트를 모두 사용하기 위한 방안
– GPS장치 및 블루투스 2개를 모두 시리얼 포트로 사용할수 없는 문제가 발생하여
GPS는 시리얼, 블루투스는 miniuart 를 이용하여 데이터를 수신하기로 함

1) cmdline.txt 파일 수정

2) 파이썬3 시리얼로 GPS 데이터를 받기 위해 시리얼모듈 설치

3) config.txt 파일 수정

아래와 같은 내용을 추가한다.

3. 블루투스 비콘 데이터 파싱
– iBeacon이 여러개 켜져있으면 비콘별로 분석하여 파싱처리를 해야 데이터로 이용할수 있다.
즉 비콘데이터를 아래와 같이 패킷의 자리수를 이동하면서 각각 UUID, Major/Minor 버전, Tx Power, RSSI등을 구해야 한다.

라즈베리파이에 Paho MQTT 클라이언트 테스트

1. MQTT 클라이언트 설치
– 라즈베리파이에서 아래와 같이 입력하여 mqtt 클라이언트를 설치한다.

sudo pip3 install paho-mqtt

2. Publish 테스트

import paho.mqtt.client as mqtt

client = mqtt.Client()
client.username_pw_set("yomile", "1234")
client.connect("192.168.0.9", 4530, 60)
client.publish("mbizok-client/iot/door/toilet", "test")

라즈베리 파이 기본 개발환경 구성

1. 파이썬 패키지 인덱스(PyPI) 설치
– 파이썬 라이브러리를 쉽게 설치하기 위한 도구

sudo apt-get install python3-pip

2. GPIO(General Purpose Input/Output) 설치
– 라즈베리파이에 있는 GPIO 핀을 통해 입출력 할수 있게 하는 라이브러리

sudo apt-get install python3-rpi.gpio

3. 시리얼 모듈 설치

sudo apt-get install python3-serial

파이참을 이용하여 라즈베리파이 원격 빌드 환경 설정

1. 파이참 열기
– Create New Project로 하여 프로젝트 생성

2. 작업위치설정

3. 원격지 설정
– Interpreter의 Add Remote를 클릭

4. 원격지 정보 입력
– Host IP, Port, 계정정보 및 원격지의 파이쎤 인터프리터를 설정한다.

5. Remote Project location 설정

6. 파이썬 파일 생성
– 오른쪽 Project에서 New > Python File을 눌러 파일생성

7. 파일명 입력

8. 간단한 코딩

9. 서버로 배포(Deployment)
– 위에서 코딩한것을 Tools > Deployment > Upload to ssh~ 를 눌러 라즈베리파이로 배포

– 하단 로그창에 업로드 상태 표시됨

10. 라즈베리 파이에서 구동

sudo python3 DoorClient.py

11. 라즈베리 파이로 부터 Sync
– 라즈베리 파이에서 직접 vi로 에디팅한 경우 라지베리파이로 부터 동기화를 할수 있다.
– Tools > Deployment > Sync with Deployed to ssh~ 메뉴 클릭하여 동기화.

12.참고사항
파이참 Unresolved reference 에러시
https://hyesun03.github.io/2016/10/04/pycharmImportError/

파이참의 원격빌드시 sudo 문제로 컴파일이 안될때

$sudo vi /usr/bin/python3-sudo.sh

아래와 같이 작성후

#!/bin/bash
sudo /usr/bin/python3.5 "$@"

파이참의 Configure Remote Python Interpreter의 Python interpreter path에 “/usr/bin/python3-sudo.sh” 입력

라즈베리파이(Raspberry PI) 인터넷 연결

1. 유선랜 설정
– 기본적으로 DHCP기능이 활성화 되어 있어 랜선만 꽃기만 하면 된다.
ifconfig를 쳐보면 192.168.0.125라는 IP주소로 할당받은 것을 알수 있다.

pi@raspberrypi:~$ ifconfig
enxb827ebeaadc5: flags=4163  mtu 1500
        inet 192.168.0.125  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::3dba:6631:6fe1:c90f  prefixlen 64  scopeid 0x20
        ether b8:27:eb:ea:ad:c5  txqueuelen 1000  (Ethernet)
        RX packets 5418  bytes 569192 (555.8 KiB)
        RX errors 0  dropped 1239  overruns 0  frame 0
        TX packets 63  bytes 7286 (7.1 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

lo: flags=73  mtu 65536
        inet 127.0.0.1  netmask 255.0.0.0
        inet6 ::1  prefixlen 128  scopeid 0x10
        loop  txqueuelen 1  (Local Loopback)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

wlan0: flags=4099  mtu 1500
        ether b8:27:eb:bf:f8:90  txqueuelen 1000  (Ethernet)
        RX packets 0  bytes 0 (0.0 B)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 0  bytes 0 (0.0 B)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

pi@raspberrypi:~$

2. SSH를 통한 연결 접속
1) SSH 서버 활성화

sudo raspi-config







2) SSH 서버로 접속
위에서 확인한 IP/PORT :192.168.0.125/22로 SecureCRT를 통해 접속

3. 무선랜 설정
1) iwconfig 명령으로 네트워크 어답터 목록 확인
이중 “no wireless extensions”가 아닌 wlan0이 내장되어있는 WiFi 아답터임.

iwconfig

2) 접속가능한 주변 AP 검색

sudo iwlist wlan0 scan | more

– 여러개의 AP가 나오는데, 연구소에 설치되어 있는 “moram-lab”을 이용하기로 한다.

          Cell 05 - Address: 64:E5:99:0A:32:04
                    Channel:6
                    Frequency:2.437 GHz (Channel 6)
                    Quality=60/70  Signal level=-50 dBm  
                    Encryption key:on
                    ESSID:"moram-lab"
                    Bit Rates:1 Mb/s; 2 Mb/s; 5.5 Mb/s; 11 Mb/s; 6 Mb/s
                              9 Mb/s; 12 Mb/s; 18 Mb/s
                    Bit Rates:24 Mb/s; 36 Mb/s; 48 Mb/s; 54 Mb/s
                    Mode:Master
                    Extra:tsf=0000000000000000
                    Extra: Last beacon: 80ms ago
                    IE: Unknown: 00096D6F72616D2D6C6162
                    IE: Unknown: 010882848B960C121824
                    IE: Unknown: 030106
                    IE: Unknown: 2A0100
                    IE: Unknown: 32043048606C
                    IE: Unknown: 2D1A6E181EFFFF000000000000000000000000000000000000000000
                    IE: Unknown: 3D1606070000000000000000000000000000000000000000
                    IE: IEEE 802.11i/WPA2 Version 1
                        Group Cipher : CCMP
                        Pairwise Ciphers (1) : CCMP

3) PSK를 생성
– wpa_passphrase명령을 이용하여 PSK 생성

 wpa_passphrase 접속할AP의SSID 접속할AP의비밀번호
 wpa_passphrase moram-lab 비밀번호
network={
        ssid="moram-lab"
        psk=d847cf7519242cc9486e9bbe317a1ed811b20034cd74b4d995c6d6c8a2e2c3d9
}

4) /etc/wpa_supplicant/wpa_supplicant.conf 파일 수정
– 일단 editing을 위해 vim 설치

sudo apt-get install vim
sudo vim /etc/wpa_supplicant/wpa_supplicant.conf

– 아래와 같이 하단에 위에서 생성한 PSK를 추가한후에 저장

country=GB
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1

network={
        ssid="moram-lab"
        psk=d847cf7519242cc9486e9bbe317a1ed811b20034cd74b4d995c6d6c8a2e2c3d9
}

5) 인터페이스 파일 수정

sudo vim /etc/network/interfaces

하단에 아래와 같이 추가

auto wlan0
iface wlan0 inet dhcp
wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf

6) wifi 아답터 재시작
– WIFI 재시작

sudo ifup wlan0

Internet Systems Consortium DHCP Client 4.3.5
Copyright 2004-2016 Internet Systems Consortium.
All rights reserved.
For info, please visit https://www.isc.org/software/dhcp/

Listening on LPF/wlan0/b8:27:eb:bf:f8:90
Sending on   LPF/wlan0/b8:27:eb:bf:f8:90
Sending on   Socket/fallback
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 4
DHCPDISCOVER on wlan0 to 255.255.255.255 port 67 interval 5
DHCPREQUEST of 192.168.0.126 on wlan0 to 255.255.255.255 port 67
DHCPOFFER of 192.168.0.126 from 192.168.0.1
DHCPACK of 192.168.0.126 from 192.168.0.1
bound to 192.168.0.126 -- renewal in 3297 seconds.

– 참고 : 만약 아래와 같이 에러난 경우, 라즈베리파이에 전원을 뺐다가 다시 넣으니까 해결됨.

wpa_supplicant: /sbin/wpa_supplicant daemon failed to start
run-parts: /etc/network/if-pre-up.d/wpasupplicant exited with return code 1
ifup: failed to bring up wlan0
pi@raspberrypi:~$ 

7) IP 할당

sudo wpa_cli reconfigure
Selected interface 'p2p-dev-wlan0'
OK

8) IP 할당 확인
– ifconfig로 확인

wlan0: flags=4163  mtu 1500
        inet 192.168.0.126  netmask 255.255.255.0  broadcast 192.168.0.255
        inet6 fe80::ba27:ebff:febf:f890  prefixlen 64  scopeid 0x20
        ether b8:27:eb:bf:f8:90  txqueuelen 1000  (Ethernet)
        RX packets 316  bytes 36224 (35.3 KiB)
        RX errors 0  dropped 0  overruns 0  frame 0
        TX packets 40  bytes 6359 (6.2 KiB)
        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0

라즈베리파이(Raspberry PI) OS 설치

1. 라즈비안 OS 다운로드
– 아래 주소에서 다운받아 압축을 푼다.

2. Win32 Disk Imager
– 라즈비안 이미지 파일을 SD카드로 Write하기 위한 도구
– 다운로드 URL

http://sourceforge.net/projects/win32diskimager/

– 설치가 완료되면 “Image File” 칸에 위 라즈비안 이미지 파일을 지정하고
“device”란에 SD카드 리더기 위치를 지정하면 된다.

– “Write” 버튼을 눌러 이미지를 write 한다.
– “Write Successful” 이라고 쓰면 성공적으로 설치

3. UART를 이용하여 PC와 연결
1) UART 활성화 : 부팅시 UART가 활성화되도록 탐색기에서 SD카드에 있는 config.txt 파일을 열어 수정한다.

– 파일의 마지막 라인에 “enable_uart=1” 추가

2) 케이블 만들기
– 아래 GPIO 06, 08, 10 핀에 연결한다.




– DIP 스위치에 주의




– 연결하게 되면 장치관리자에서 아래와 같이 확인

3) PUTTY에서 연결
– 위 장치관리자에서 보여준 COM포트를 이용하여 접속한다.

– 모두 입력하고 접속하면 아무것도 표시되지않는다면 다시 전원을 넣고 putty에서 엔터를 치면 된다.

– 기본 로그인 계정은 pi/raspberry 임.

4. 환경설정

1) 언어 설정




– en_US.ISO-8859-1, en_US.UTF-8, ko_KR.UTF-8 를 선택한다.

2) 타임존 설정
– Asia/Seoul 선택