728x90
반응형
SMALL

도메인 사용하기

지금까지 배포한 서비스에 접속하려면 고정 IP를 입력해서 접근했다.

https://15.164.187.123

 

보통 웹 사이트들은 아래와 같이 쉬운 도메인을 사용한다.

https://www.naver.com/

 

 

도메인 구입하기

1. 도메인을 사용하기 전에 가장 먼저 사용할 수 있는 도메인인지 확인해야 한다.

https://xn--c79as89aj0e29b77z.xn--3e0b707e/

 

KISA 후이즈검색 whois.kisa.or.kr

한국인터넷진흥원 인터넷주소자원 검색(후이즈검색) 서비스 입니다.

xn--c79as89aj0e29b77z.xn--3e0b707e

위처럼 등록되지 않은 도메인을 찾아야 한다.

 

2. 도메인을 찾았다면 이를 구매해보자. AWS에서도 도메인을 판매하며 가비아에서도 판매한다.

[AWS Route 53]

 

Amazon Route 53 - DNS 서비스 - AWS

Amazon Route 53를 사용하면 지연 시간 단축, 애플리케이션 가용성 개선, 규정 준수 보장 등의 특정 요구 사항에 맞게 DNS 라우팅 정책을 조정할 수 있습니다. 이러한 맞춤화를 통해 사용자는 성능, 복

aws.amazon.com

[가비아]

 

웹을 넘어 클라우드로. 가비아

그룹웨어부터 멀티클라우드까지 하나의 클라우드 허브

www.gabia.com

 

3. 도메인 구입 시 네임서버주소를 설정하는 항목이 있는데 일단 해당 업체의 네임 서버 주소를 사용하는 것으로 설정하자.

 

도메인 연결하기

1. 라이트세일에 접속해 로그인한 뒤, [Domain & DNS] -> [Create DNS zone]을 클릭한다.

 

2. 구매한 도메인을 입력하고 [Create DNS zone]을 클릭한다.

 

3. 그럼 다음과 같이 DNS 영역이 생성된다.

 

4. [Assignments]탭에서 [Add assignment]를 클릭한다.

 

5. 도메인명을 선택하고 리소스는 static으로 IP도 고정 ip로 등록 후 할당한다.

 

6. 할당된 화면

 

7. 이제 도메인을 구입한 화면에서 AWS lightsail의 이름 서버 주소 4개를 등록하면 된다.

 

도메인 적용하기

1. 도메인이 생성되었으므로 웹 서버 설정을 변경해야 한다. mobaXterm으로 돌아가 엔진엑스 설정을 변경하자

/etc/nginx/sites-available/sbb

 

2. 엔진엑스 재시작

ubuntu@jumpto:/etc/nginx/sites-available$ sudo systemctl restart nginx
728x90
반응형
LIST
728x90
반응형
SMALL
로그(log)란?
프로그램 또는 시스템에서 발생하는 이벤트, 정보, 상태, 오류 등을 기록한 것을 말하고,
이러한 로그를 생성하고 저장하는 것을 로깅(logging)이라고 한다.
로그는 프로그램의 동작을 추적해 문제를 해겨하거나 성능을 분석하기 위한 목적으로 활용된다.

스프링부트는 기본적으로 로그백(logback)이라는 로깅 도구를 사용하여 로그를 관리한다.
현재 서버에 생성되는 로그파일(sbb.log)에는 몇 가지 문제가 있다.
1. 서비스를 다시 실행할 경우 이전 로그가 삭제된다.
2. 로그가 쌓일수록 파일의 용량이 커지며 무한대로 증가한다.
3. 로그 시간이 시스템 시간이 아닌 UTC시간으로 출력된다.

 

서버 로그 분리하기

위의 문제를 해결하려면 개발 환경의 로그와 서버 환경의 로그를 분리해야 한다.

application-prod.properties

...
#logging
logging.logback.rollingpolicy.max-history=30
logging.logback.rollingpolicy.max-file-size=100MB
logging.file.name=logs/sbb.log
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}-%i.log
logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS,Asia/Seoul
logging.logback.rollingpolicy.max-history=30
-로그 파일을 유지할 기간(일)을 설정한다. 30일만 유지하도록 지정.
logging.logback.rollingpolicy.max-file-size=100MB
-로그파일 1개의 최대용량을 설정한다. 100MB로 설정.
logging.file.name=logs/sbb.log
-로그 파일의 이름을 설정한다. logs디렉터리 아래에 sbb.log 생성.
logging.logback.rollingpolicy.file-name-pattern=${LOG_FILE}.%d{yyyy-MM-dd}-%i.log
-로그 파일의 용량이 초과하거나 날짜가 변경될 경우 새로 만들어질 로그 파일의 이름 규칙
logging.pattern.dateformat=yyyy-MM-dd HH:mm:ss.SSS,Asia/Seoul
-로그 출력시 출력되는 날자와 시간의 형식을 지정한다.

 

이처럼 수정 후 빌드 버전(sbb-0.0.3.jar)을 변경하여 배포 파일을 새로 작성하여 서버에 업로드하자.

아래 글 참고

 

[Spring Boot] 41. 서버 배포 - 배포하기(서버 설정 / 배포 파일 생성 및 전송)

AWS 서버도 생성했고 작업할 수 있는 준비가 완료됐으니, 이제 서버에 SBB를 설치하여 모든 사람이 접근할 수 있도록 해보자. 서버 환경 설정하기먼저 MobaXterm을 이용하여 서버에 접속해보자. 서

exuzii.tistory.com

 

build.gradle

...
group = 'com.mysite'
version = '0.0.3'
...

위처럼 수정한 다음 build.gradle 우클릭 [Gradle -> Refresh...]

 

[Run -> Run Configuration]클릭 후 Gradle Task의 'sbb' Run하기

 

sbb-0.0.3.jar 파일이 생성된 것을 확인

파일질라에서 서버로 업로드하기

 

서버에서 start.sh 변경하기

1. 로깅 설정을 변경했으므로 서버에서 적용하기 위해 mobaXterm으로 돌아가 파일을 수정해보자.

sbb-0.0.3.jar가 있는 것도 확인

#!/bin/bash

JAR=sbb-0.0.3.jar
LOG=/dev/null

nohup java -Dspring.profiles.active=prod -jar $JAR > $LOG 2>&1 &

nano start.sh 입력 후 위처럼 파일 수정하기. 수정 후에는 Ctrl+O -> Ctrl+X

 

2. 기존의 로그는 더 이상 필요하지 않으므로 삭제하기.

ubuntu@jumpto:~/sbb$ rm sbb.log

 

3. SBB 서비스를 다음과 같이 재시작하기

ubuntu@jumpto:~/sbb$ ./stop.sh
SBB is not running
ubuntu@jumpto:~/sbb$ ./start.sh

 

4. 재시작하면 다음과 같이 logs 디렉터리가 생성되고 그 아래에 sbb.log라는 파일이 생성된 것을 확인할 수 있다.

 

사용자 로그 작성하기

위에서는 스프링 부트 프레임워크 자체가 출력하는 로그를 관리하는 방법을 말했다.

개발자가 코드를 작성하면서도 로그를 출력할 수 있다.

 

질문 목록 조회 시 GET방식으로 요청되는 매개변수의 입력값을 로그로 출력해보자.

question/QuestionController.java

@Slf4j
@RequestMapping("/question")
@RequiredArgsConstructor
@Controller
public class QuestionController {
	
	private final QuestionService questionService;
	private final UserService userService;
	
	@GetMapping("/list")
	public String list(Model model, @RequestParam(value = "page", defaultValue = "0")int page,
			@RequestParam(value="kw", defaultValue = "") String keyword) {
		
		log.info("page:{}, kw:{}", page, keyword);
		
		Page<Question> paging = this.questionService.getList(page, keyword);
		model.addAttribute("paging",paging);
		model.addAttribute("keyword", keyword);
		return "question_list";
	}

먼저 컨트롤러에 롬복이 제공하는 @Slf4j 어노테이션을 추가하고 메서드 안에는 'log.info("page:{}, kw:{}", page, keyword);'를 추가했다.

 

* 로그 단계

- trace(1단계): 가장 낮은 로그 레벨, debug보다 정보를 훨씬 상세하게 기록.
- debug(2단계): 디버깅 목적
- info(3단계): 주요 이벤트나 상태 등의 일반 정보를 출력할 목적
- warn(4단계): 문제가 발생할 가능성이 있는 상태나 상황 등 경고 정보 출력
- error(5단계): 심각한 문제나 예외 상황에 대한 오류 정보 출력 목적
- fatal(6단계): 가장 높은 로그 레벨, 프로그램 기능 일부가 실패하거나 오류 발생 등 심각한 문제 정보 출력

 

728x90
반응형
LIST
728x90
반응형
SMALL

우리는 그동안 로컬 서버의 8080번 포트를 사용했다.

하지만 운영환경에서는 실제로 가장 많이 사용하는 80번 포트를 사용해야 한다.

 

사실 아래와 같은 옵션을 추가하면 80번 포트로 서비스를 운영할 수 있다.

$sudo java -Dserver.port=80 -jar sbb-0.0.2.jar

하지만 직접 지정하는 방법은 옳지 않다.

80번 포트로 실행하려면 루트 권한도 필요할 뿐더러, SSL을 이용한 HTTPS 서비스를 운영하기 쉽지 않다.

 

따라서 엔진엑스나 아파티와 같은 웹 서버를 이용해 설정할 수 있다.

 

엔진엑스 설치 및 설정하기

1. MobaXterm에서 아래와 같이 입력해 루트 권한으로 엔진엑스를 설치하자.

$sudo apt install nginx

이 화면이 나오면 OK를 선택한다.

 

2. 설치 후에는 /etc/nginx/sites-available 디렉터리로 이동하자.

cd /etc/nginx/sites-available

이 디렉터리는 엔진엑스의 설정 파일이 위치하며 현재 이 폴더에는 'default'파일만 존재한다.

 

3. SBB서비스의 엔진엑스 설정 파일을 다음과 같이 루트 권한으로 생성해자.

ubuntu@jumpto:/etc/nginx/sites-available$ sudo nano sbb

 

/etc/nginx/sites-available/sbb

server {
        listen 80;
        server_name localhost;

        location / {
                proxy_pass http://localhost:8080;
                proxy_set_header X-Real_IP $remote_addr;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_set_header Host $http_host;
        }
}

 

4. 이제 작성한 sbb파일을 엔진엑스가 SBB서비스의 설정 파이로 읽을 수 있도록 sbb파일을 /etc/nginx/sites-enabled 디렉터리에 링크해야 한다.

ubuntu@jumpto:/etc/nginx/sites-available$ cd /etc/nginx/sites-enabled/
ubuntu@jumpto:/etc/nginx/sites-enabled$

 

5. ls를 수행하면 현재 'default'만 있다.

ubuntu@jumpto:/etc/nginx/sites-enabled$ ls
default

 

6. site-enabled 디렉터리의 default 링크는 삭제하자.

ubuntu@jumpto:/etc/nginx/sites-enabled$ sudo rm default

 

7. 그리고 sbb파일을 이 디렉터리로 링크하자.

ubuntu@jumpto:/etc/nginx/sites-enabled$ sudo ln -s /etc/nginx/sites-available/sbb
ubuntu@jumpto:/etc/nginx/sites-enabled$ ls
sbb

 

 

엔진엑스 실행 및 적용하기

1. 엔진엑스를 설치할 때 엔진엑스가 자동으로 실행됐기 때문에 재실행해야 한다.

ubuntu@jumpto:/etc/nginx/sites-enabled$ sudo systemctl restart nginx

 

위 명령어를 통해 엔진엑스에 오류가 없는지 확인한다.

 

2. 이제 브라우저로 접속해보자. http://15.164.187.123/

 

502 Bad Gateway 오류 발생시 스프링 부트를 실행해줘야 한다.(./start.sh)

728x90
반응형
LIST
728x90
반응형
SMALL

개발 환경과 서버 환경을 분리하여 서버 환경에 보안을 위해 DB에 비밀번호를 설정해야 한다.

 

서버 환경 파일 생성하기

H2 데이터베이스에 비밀번호를 설정은 application.properties 파일을 열어 아래와 같이 입력하면 된다.

spring.datasource.password=1234

 

하지만 로컬 개발 환경은 비밀번호 없이 사용하고 서버 환경에서만 설정하고 싶다면 어떻게 해야할까?

스프링부트 시작 옵션으로 아래와 같이 spring.profiles.active 항목을 같이 전달할 수 있다.

java -Dspring.profiles.active=prod -jar sbb-0.0.1-SNAPSHOT.jar

이렇게 prod로 지정하면 스프링부트는 appliction-prod.properties를 사용한다.

spring.profiles.active=aaa로 지정하면 스프링부트는 appliction-aaa.properties를 사용한다.

 

STS에서 application.properties를 복사하여 application-prod.properties 파일을 생성하고 아래와 같이 작성하자.

 

빌드 버전 변경하여 배포 파일 생성하기

위의 환경 파일 생성으로 SBB가 업데이트되었다. build.gradle에서 빌드 버전도 변경해주자.

build.gradle

...
group = 'com.mysite'
version = '0.0.2-SNAPSHOT'
...

 

위처럼 수정 후 [Run->Run Configuration]에서 [Gradle Task - sbb]를 선택하고 [Run]버튼을 클릭하여 배포 파일을 새로 생성하자.

 

이제 이 파일도 파일질라를 이용하여 서버에 업로드하자.

 

서버에 변경 내용 적용하기

1. 데이터베이스에 비밀번호를 설정했기 때문에 기존의 데이터베이스 파일을 지워야 한다.

MobaXterm에서 아래와 같이 입력하고 파일을 삭제하자.

ubuntu@jumpto:~$ ls
sbb test.mv.db
ubuntu@jumpto:~$ rm test.mv.db

 

2. 다시 sbb 디렉터리로 이동 후 start.sh 파일을 수정하자.

#!/bin/bash

JAR=sbb-0.0.2-SNAPSHOT.jar
LOG=/home/ubuntu/sbb/sbb.log

nohup java -Dspring.profiles.active=prod -jar $JAR > $LOG 2>&1 &

 

3. 수정 완료 후 아래와 같이 입력하여 SBB서비스를 재시작하자.

ubuntu@jumpto:~/sbb$ ./stop.sh
SBB is not running
ubuntu@jumpto:~/sbb$ ./start.sh

 

 

서버의 H2 콘솔 접속하기

1. 설정했던 비밀번호를 입력하고 접속해보자.

 

2. 우리가 만들었던 테이블을 확인할 수 있다.

 

728x90
반응형
LIST
728x90
반응형
SMALL

서비스를 실행할 때 아래와 같은 명령어를 이용하여 실행한다.

ubuntu@jumpto:~/sbb$ java -jar sbb-0.0.1-SNAPSHOT.jar

하지만 이렇게 실행할 경우 터미널을 종료하면 서비스도 중단된다. 이를 방지하기 위해 백그라운드로 서비스를 실행해야 한다.

 

SBB 시작 스크립트 작성하기

서버에서는 nano 편집기를 사용해야 한다.

 

1.MobaXterm에서 sbb디렉터리로 이동한 다음, nano start.sh명령을 입력한다.

ubuntu@jumpto:~$ cd sbb/
ubuntu@jumpto:~/sbb$ nano start.sh

 

2. 그럼 아래와 같은 화면이 나오는데 이 화면이 나노 편집기이다. 마우스를 사용할 수 없고 화살표 키로 커서를 움직이거나 단축키를 사용한다.

 

3. 아래 내용을 입력한 후 Ctrl+O와 enter를 눌러 파일을 저장하고 Ctrl+X를 눌러 편집기를 종료하자.

#!/bin/bash

JAR=sbb-0.0.1-SNAPSHOT.jar
LOG=/home/ubuntu/sbb/sbb.log

nohup java -jar $JAR > $LOG 2>&1 &
이 때 JAR 변수는 배포 파일 이름이고, LOG변수는 로그를 출력할 파일 이름이다.

start.sh에서 nohup은 프로세스를 실행한 터미널 연결이 끊겨져도 프로세스가 지속적으로 동장할 수 있게 해주는 명령어이다.

이어서 java -jar $JAR 는 JAR변수에 저장된 .jar 파일을 실행하라는 의미이고 >$LOG 는 프로세스 출력을 로그 파일에 저장하라는 의미이다.

2>&1은 오류 출력을 일반 출력으로 전달하라는 의미이고 마지막 &는 이를 백그라운드로 실행하라는 의미이다.

 

4. 이제 start.sh라는 스크립트명만 입력해도 실행될 수 있도록 실행 권한을 부여하자.

ubuntu@jumpto:~/sbb$ chmod +x start.sh

 

5. 아래와 같이 파일을 실행하여 백그라운드로 서버를 실행해보자.

ubuntu@jumpto:~/sbb$ ./start.sh

 

 

SBB 중지 스크립트 작성하기

1. 시작 스크립트와 마찬가지로 나노편집기를 통해 파일을 생성하고 다음과 같이 작성하자.

ubuntu@jumpto:~/sbb$ nano stop.sh
#!/bin/bash

SBB_PID=$(ps -ef | grep java | grep sbb | awk '{print $2}')

if [ -z "$SBB_PID"];
then
       echo "SBB is not running"
else
       kill -9 $SBB_PID
       echo "SBB stopped"
fi
SBB_PID는 현재 실행중인 SBB 서비스의 프로세스 아이디이다.

만약 서비스 프로세스가 없다면 SBB is not running 메시지를,
있다면 kill -9명령으로 프로세스를 강제 종료시킨다.

 

2. Ctrl+O로 파일을 저장시키고 Ctrl+X로 편집기를 빠져나와 스크립트명만 입력해도 실행될 수 있게 권한을 변경해준다.

ubuntu@jumpto:~/sbb$ chmod +x stop.sh

 

3. 다음과 같이 stop.sh파일을 실행하여 SBB서비스를 중지해보자.

 

4. 만약 프로그램이 변경되어 jar 파일을 새로 업로드 했다면 변경 내용을 적용하기 위해 stop.sh와 start.sh를 순서대로 다시 실행하면 된다.

728x90
반응형
LIST
728x90
반응형
SMALL
AWS 서버도 생성했고 작업할 수 있는 준비가 완료됐으니, 이제 서버에 SBB를 설치하여 모든 사람이 접근할 수 있도록 해보자.

 

서버 환경 설정하기

먼저 MobaXterm을 이용하여 서버에 접속해보자. 서버를 더블클릭하면 터미널 창으로 접속된다.

 

호스트 이름 변경하기

서버에 접속하게 되면 맨 하단에 아래와 같은 프롬프트가 보인다.

ubuntu@ip-172-26-2-4:~$

여기서 'ip-172-26-2-4'가 호스트 이름이다. 만약 의미 있는 호스트 명으로 변경하고자 한다면 다음순서대로 명령해보자.

 

1. 'jumpto'로 호스트이름 변경

172-26-2-4:~$ sudo hostnamectl set-hostname jumpto

sudo는 관리자 권한으로 명령을 실행한다는 의미이다.

 

2. 호스트명을 변경하고 나면 서버를 재시작해야 한다.

172-26-2-4:~$ sudo reboot

그럼 네트워크가 끊기므로 30초~1분 후에 다시 접속해보자.

 

3. 다시 접속해보면 다음과 같이 변경된 프롬프트를 확인할 수 잇다.

ubuntu@jumpto:~$

 

4. hostname 명령을 수행하면 아래와 같이 변경된 호스트명이 출력된다.

ubuntu@jumpto:~$ hostname
jumpto

 

서버 시간 설정하기

1. 먼저 date명령을 실행해보자. 그럼 우리나라 시간이 아닌 UTC 시간이 출력된다.

ubuntu@jumpto:~$ date
Tue May 28 00:58:17 UTC 2024

 

2. 한국 시간으로 맞추기 위해 다음 명령을 입력해보자.

ubuntu@jumpto:~$ sudo ln -sf /usr/share/zoneinfo/Asia/Seoul /etc/localtime

 

3. 다시 date명령을 입력하면 우리나라 시간으로 출력된 것을 확인할 수 있다.

ubuntu@jumpto:~$ date
Tue May 28 09:59:49 KST 2024

 

서버에 자바 설치하기

스프링 부트를 사용하려면 반드시 자바가 설치되어 있어야 한다.

1. 서버에 자바 설치 유무를 확인하기 위해 java 명령을 입력해보자.

ubuntu@jumpto:~$ java
Command 'java' not found, but can be installed with:
sudo apt install openjdk-11-jre-headless # version 11.0.20.1+1-0ubuntu1~22.04, or
sudo apt install default-jre # version 2:1.11-72build2
sudo apt install openjdk-17-jre-headless # version 17.0.8.1+1~us1-0ubuntu1~22.04
sudo apt install openjdk-18-jre-headless # version 18.0.2+9-2~22.04
sudo apt install openjdk-19-jre-headless # version 19.0.2+7-0ubuntu3~22.04
sudo apt install openjdk-8-jre-headless # version 8u382-ga-1~22.04.1

자바가 설치되어 있지 않아 위와 같은 메시지가 출력된다.

 

2. 자바를 설치하기 전에 먼저 sudo apt update 명령을 수행해 우분투 패키지를 최신으로 업데이트해야한다.

ubuntu@jumpto:~$ sudo apt update
Hit:1 http://ap-northeast-2.ec2.archive.ubuntu.com/ubuntu jammy InRelease
Get:2 http://ap-northeast-2.ec2.archive.ubuntu.com/ubuntu jammy-updates InRelease [119 kB]
Get:3 http://ap-northeast-2.ec2.archive.ubuntu.com/ubuntu jammy-backports InRelease [109 kB]
Get:4 http://security.ubuntu.com/ubuntu jammy-security InRelease [110 kB] Fetched 338 kB in 1s (275 kB/s)
...

 

3. 이어서 자바를 설치해보자.

ubuntu@jumpto:~$ sudo apt install openjdk-19-jdk

설치 중간에 'Do you swant to continue?' 라는 문구가 나오면 y를 입력하면 된다.

 

4. 설치를 완료했다면 java -version을 실행해보자.

ubuntu@jumpto:~$ java -version
openjdk version "19.0.2" 2023-01-17
OpenJDK Runtime Environment (build 19.0.2+7-Ubuntu-0ubuntu322.04)
OpenJDK 64-Bit Server VM (build 19.0.2+7-Ubuntu-0ubuntu322.04, mixed mode, sharing)

19버전이 정상적으로 설치되었다.

프로젝트 디렉터리 생성하기

서버에 SBB 서비스를 적용하기 위해 홈 디렉터리 아래에 sbb디렉터리를 생성하자.

ubuntu@jumpto:~$ mkdir sbb //sbb 디렉터리 생성
ubuntu@jumpto:~$ ls //현재 디렉터리 내 확인
sbb

 

 

STS에서 SBB 배포 파일 생성하기

이제 서버에 올릴 SBB 배포 파일을 만들어보자. 배포 파일은 단 하나의 jar 파일로, 서버에서 이 파일을 구동시킨다.

 

1. jar 파일은 Gradle을 사용하여 생성한다. 그 전에 Gradle에 JDK 설정을 먼저 해야 한다. 그러기 위해 [Widow -> Preference -> Gradle] 클릭하고 'Advanced Options'의 'Java home'항목에 JDK의 디렉터리를 입력한다.

 

2.AWS 서버에는 JDK 19버전을 설치했으므로 build.gradle java항목을 아래와 같이 수정하자.

...
java {
	sourceCompatibility = '19'
}
...

 

3. 서버에 적용할 SBB 배포파일인 jar파일을 만들기 위해 [Run -> Run Configurations]선택 후 'Gradle Task'를 선택하고 마우스 우클릭 후 [New Configuration]을 클릭하자.

 

4. 그럼 다음과 같은 화면이 나타나면 순서대로 각 항목을 입력해보자. 그리고 Apply 클릭 후 Run을 클릭하자.

5. 완성되면 하단에 Gradle Executions 창이 나타나고 진행결과나 나온다.

 

6. 오류가 없다면 프로젝트 워크스페이스 하단에 build 디렉터리가 생성되고 배포파일이 생성된 것을 확인할 수 있다.

 

 

SFTP로 SBB 배포 파일 전송하기

생성된 .jar파일을 파일질라를 이용하여 서버에 전송해보자.

1. 다음과 같이 sbb-0.0.1-SNAPSHOT.jar 파일을 찾아 서버의 /home/ubuntu/sbb 디렉터리로 드래그 앤 드롭해보자.

 

2.MobaXterm을 사용하여 다시 서버에 접속 후 아래와 같이 입력하여 배포 파일을 실행하자. 실행된 서비스를 종료하려면  Ctrl+C를 누른다.

ubuntu@jumpto:~$ cd sbb
ubuntu@jumpto:~/sbb$ ls
sbb-0.0.1-SNAPSHOT.jar
ubuntu@jumpto:~/sbb$ java -jar sbb-0.0.1-SNAPSHOT.jar

 

3. 웹 브라우저를 실행하고 앞서 설정한 고정IP:8080을 입력하여 접속해보자.

http://15.164.187.123:8080 과 같이 입력하면 아래와 같은 화면을 볼 수 있다.

그런데 이전의 데이터들이 다 사라졌다. 왜냐하면 서버에서도 H2 DB의 데이터 파일인 local.mv.db 파일이 새로 만들어지기 때문이다.
728x90
반응형
LIST
728x90
반응형
SMALL
AWS 서버에 접속하려면 먼저 고정 IP가 필요하다.

 

고정 IP 생성하기

고정IP란?
말 그대로 IP가 변하지 않고 고정된다.

 

1. AWS 라이트세일의 메인 화면 왼쪽에 있는 [Networking] -> [Create static IP] 클릭한다.

 

2. 다음과 같은 화면에서 'Attach to an instance'에서 [Ubuntu-1]을 선택하고 고정 IP명 확인한 후 [Create]을 클릭하여 고정 IP를 생성한다.

 

3. 다음과 같이 고정 IP주소를 얻게 된다. 개인마다 IP는 모두 다르며, 나의 경우 '15.164.187.123'이라는 고정 IP가 생성되었다.

 

방화벽 해제하기

그동안 로컬서버의 8080번 포트를 사용해왔다. 이제 AWS에 설치할 SBB서비스를 외부에서도 접속할 수 있어야 하기 때문에 이 8080포트의 방화벽을 해제해야 한다.

 

1. AWS 라이트세일의 메인화면 왼쪽 [Instance] -> [Ubuntu-1] 클릭

 

2. 이어서 상단 [Networking] -> [+Add rule] 클릭

 

3. 아래와 같이 포트번호는 '8080'으로 입력하고 [Create]를 클릭하여 생성한다. 이제 외부에서 고정IP의 8080포트로 쉽게 접근할 수 있다.

 

서버 접속 프로그램 설치하기

SBB서비스를 서버에 배포하기 위해 서버에 접속하기 위한 프로그램을 서치하고 환경설정을 해야 한다.

 

프라이빗 키 만들기

SSH또는 SFTP 프로그램으로 서버에 접속하기 위해서는 AWS 계정의 SSH 키가 필요하다.

SSH키는 프라이빗 키로 서버에 안전하게 접속할 수 있다.

SSH(Secure Shell)란? 네트워크상의 다른 컴퓨터에 로그인하거나 원격 서버의 명령을 수행하는 프로토콜이나 프로그램을 가리킨다.
SFTP(SSH File Transfer Protocol)란? SSH프로토콜 위에서 파일을 안전하게 전송하고 관리하는 역할을 한다. 원격 서버간에 파일을 업로드하고 내려받을 때 사용한다.

 

1. AWS 라이트세일 메인화면 [계정] -> [Account] 클

 

2. [SSH keys] -> [다운로드] 클릭

 

그럼 아래와 같은 LightsailDefaultKey-ap-northeast-2.pem이라는 SSH키 파일을 내려받을 수 있다.

3. 이 키를 컴퓨터의 루트(C:/) 디렉토리에 붙여넣고 '이름 바꾸기'로 파일명은 'mysite.pem'으로 변경하자.

 

SSH 클라이언트 설치하기

SSH 클라이언트는 SSH 프로토콜을 사용하여 우너격 서버에 접속해 명령을 실행할 수 있는 프로그램이다.

우리는 SSH 키가 있으므로 SSH 클라이언트를 내려받고 설치할 수 있다.

MobaXterm 을 사용해보자.

 

1. MobaXterm 사이트( https://mobaxterm.mobatek.net/download.html )에 접속해 무료버전인 'Home Edition' 설치파일을 내려받자.

 

MobaXterm free Xserver and tabbed SSH client for Windows

The ultimate toolbox for remote computing - includes X server, enhanced SSH client and much more!

mobaxterm.mobatek.net

 

2. 다운로드 되면 압축을 해제하고 설치 후 MobaXterm을 실행하여 [Session]을 클릭하자.

 

3. [SSH]클릭 후 아래와 같이 입력하자.

4. 모두 입력 후 [OK]클릭하게 되면 다음과 같이 MobaXterm으로 AWS 에 생성한 인스턴스 서버에 접속할 수 있다.

 

SFTP 클라이언트 설치하기

SBB 서비스는 JAR파일 형태로 서버에 배포할 것이다. 즉, 배포파일로 만든 .jar 파일을 서버에 전송해야 한다.

이처럼 파일을 서버에 전송하려면 SFTP 클라이언트 프로그램이 별도로 필요하다. 파일질라를 사용해보자.

 

1. 파일질라 홈페이지(https://filezilla-project.org/)에 접속하여 설치 파일을 내려받아 설치해보자.

 

2. 다음과 같은 화면에서 가장 왼쪽의 FileZilla 의 [Download]를 클릭한다.

 

3. 설치완료 후 파일질라를 실행하여 화면 왼쪽 상단 [사이트 관리자] 아이콘을 클릭한다.

 

4. 아래와 같이 나오면 [새 사이트]를 클릭한다.

 

5. 아래와 같이 순서대로 내용을 입력해보자.

 

6. 위와 같이 설정값을 모두 입력하고 [연결]을 클릭하면 아래와 같이 서버에 접속된 것을 확인할 수 있다.

왼쪽의 '로컬 사이트'는 내 컴퓨터를 말하고 오른쪽의 '리모트 사이트'는 서버인 AWS 라이트세일의 인스턴스 서버를 말한다.

여기서 드래그 앤 드롭으로 파일을 업로드하거나 내려받을 수 있다.

728x90
반응형
LIST
728x90
반응형
SMALL
우리가 만든 서비를 누구나 사용할 수 있도록 하려면 외부에서 접속이 가능하도록 만들어야 한다.
클라우드 시스템으로 아마존 웹 서비스(AWS) 를 사용하여 배포해보자.

 

AWS 라이트 세일이란?

아마존에서 운영하는 웹 서비스에 특화된 클라우드 서비스이다.

AWS와 비교하여 웹 서비스 운영에 꼭 필요한 기능만 준비되어 있어 공부할 내용이 적고 가성비가 좋다.

첫 3달은 무료이며 그 이후에는 매달 5달러씩 지불해야 한다.

이번에 우리가 사용할 AWS라이트세일 서버의 기본 사양은 아래와 같다.

- 메모리: 1GB
- CPU: 2vCPU
- SSD: 40GB
- 트래픽: 2TB

 

AWS 가입하기

aws가입 방법은 아래 글을 참고하자.

 

[Spring Boot] 38. AWS 회원가입

AWS 가입하기 1. 먼저 AWS 공식 홈페이지( https://aws.amazon.com/ko )에 접속한 다음 [AWS 계정 생성]을 클릭한다. 클라우드 서비스 | 클라우드 컴퓨팅 솔루션| Amazon Web Services필요한 만큼 이용할 수 있는

exuzii.tistory.com

 

AWS 라이트세일 시작하기

위에서 AWS 계정 생성을 완료했다면 AWS 라이트세일을 사용할 수 있다.

 

AWS 라이트세일에 접속하기

1. AWS 라이트세일 홈페이지에 접속해보자. 접속하면 다음과 같은 로그인 화면이 나타난다. 루트 사용자 이메일 주소를 입력한 후 [다음]을 클릭한다.

 

https://lightsail.aws.amazon.com/ls/webapp

 

lightsail.aws.amazon.com

 

2. 비밀번호를 입력하고 [로그인]을 클릭한다.

 

3. 다음과 같은 라이트세일 시작 화면이 나타난다. [Let's get started]을 클릭한다.

 

4. 그럼 다음과 같은 라이트세일 메인 화면이 나타난다.

 

 

인스턴스 생성하기

여기서 가장 먼저 할 일은 인스턴스를 생성하는 것이다. 여기서 인스턴스는 서버역할을 하는 라이트세일의 서비스이다.

 

1. 라이트세일 메뉴에서 인스턴스를 선택한 후 [Create instance] 버튼을 클릭한다.

 

2. 다음으로 화면과 같이 선택해보자.

플랫폼은 [Linux/Unix]를 선택하고 블루프린트는 [OS전용]을 선택한다. 그 다음 [Ubuntu 22.04 LTS]를 선택한다.

 

3. 스크롤을 내려 'Choose instance plan'에서 [Price per month]와 [$5]를 선택하자.

 

4. 또 스크롤을 내려 인스턴스명이 'Ubuntu-1'을 확인하고 [인스턴스 생성]을 클릭한다.

 

5. 그럼 아래와 같은 화면이 나타난다. 인스턴스를 생성하는데 시간이 걸리기 때문에 'Pending(대기중)'이 보여진다.

 

6. 1~2분 후에는 실행중으로 바뀐다.




728x90
반응형
LIST
728x90
반응형
SMALL

AWS 가입하기

 

1. 먼저 AWS 공식 홈페이지( https://aws.amazon.com/ko )에 접속한 다음 [AWS 계정 생성]을 클릭한다.

 

클라우드 서비스 | 클라우드 컴퓨팅 솔루션| Amazon Web Services

필요한 만큼 이용할 수 있는 것은 물론 필요에 따라 몇 분 만에 확장 또는 축소할 수 있습니다. 자세히 알아보세요.

aws.amazon.com

 

2. 아래와 같은 AWS 계정 생성 화면이 나타난다. 여기서 이메일 주소와 계정 이름을 입력하고 [이메일 주소 확인] 버튼을 클릭한다.

 

3. 그럼 다음과 같은 '사용자 확인' 화면이 나타난다. 등록한 이메일로 전달된 확인 코드를 입력한 후 [확인]을 클릭한다.

 

4.그럼 다음과 같이 암호를 입력하는 화면이 나온다. 암호를 입력하고 [계속] 버튼을 클릭한다.

 

5. 그러면 다음과 같은 '연락처 정보' 화면이 나타난다. 이름,주소, 전화번호 등을 입력한 후 '동의'에 체크하고 [계속]을 클릭한다. 이때 이름과 주소는 모두 영문으로 입력해야 한다.

영문 주소는 아래 주소에서 확인해보자.
https://juso.go.kr

 

6. 다음으로 '결제 정보' 화면이 나타난다. 계정을 생성하려면 해외결제가 가능한 신용카드 또는 체크카드를 등록해야 한다. 카드정보를 입력하고 [확인 및 계속]을 클릭한다.

 

7. 다음과 같이 '카드 정보 입력' 화면이 나타난다. 비밀번호와 생년월일을 입력 후 '동의'에 체크하고 [다음]을 클릭한다.

100원이 자동결제되는데 바로 다시 입금되니 걱정하지 않아도 된다.

 

8. 이제 '자격 증명 확인' 화면이 나타난다. 이를 위해 자신의 핸드폰 번호를 입력하고 [SMS전송]버튼을 클릭한다.

 

9.  '코드 확인' 화면이 나타난다. 핸드폰으로 전달된 4자리 확인 코드를 입력하고 [계속]버튼을 클릭한다.

 

10. 다음과 같은 'Support 플랜 선택' 화면이 나타난다. '기본지원-무료'플랜을 선택하고 가입 완료 버튼을 클릭한다.

 

11. 그럼 다음과 같은 가입 완료 화면이 나타난다.

 

 

728x90
반응형
LIST
728x90
반응형
SMALL
검색기능을 구현하는 방법 두가지를 살펴보려고 한다.

1. JPA의 Specification 인터페이스 사용하기
2. @Query 사용하기

 

검색 기능 구현하기

보통 검색 대상으로는 질문 제목, 질문 내용, 질문 작성자, 답변 내용, 답변 작성자 정도가 있다.

만약 이러한 조건으로 검색하려면 아래와 같은 SQL 쿼리문이 필요하다.

select distinct
	q.id,
    q.author_id,
    q.content,
    q.create_date,
    q.modify_date,
    q.subject
from question q
left outer join site_user u1 on q.author_id = u1.id
left outer join answer a on q.id = a.question_id
left outer join site_user u2 on a.author_id = u2.id
where
	q.subject like '%스프링%'
    or q.content like '%스프링%'
    or u1.username like '%스프링%'
    or a.content like '%스프링%'
    or u2.username like '%스프링%'

이 쿼리문은 question, answer, site_user 3개의 테이블을 대상으로 '스프링' 문자열이 포함된 데이터를 검색한다.

검색된 데이터는 중복되지 않아야 하므로 distinct를 사용하여 제거했다.

이 쿼리를 이용하여 JPA를 사용해 자바 코드로 만들 것이다.

 

JPA의 Specification 인터페이스 사용하기

Specification 인터페이스는 DB검색을 더 유연하게 하고, 복잡한 검색을 처리할 수 있다.

먼저 서비스에 search메서드를 추가하자.

/question/QuestionService.java

	private Specification<Question> search(String keyword){
		return new Specification<Question>() {
			private static final long serialVersionUID = 1L;
			
			@Override
			public Predicate toPredicate(Root<Question> q, CriteriaQuery<?> query, CriteriaBuilder cb) {
				query.distinct(true); //중복 제거
				Join<Question, SiteUser> u1 = q.join("author", JoinType.LEFT);
				Join<Question, Answer> a = q.join("answerList", JoinType.LEFT);
				Join<Answer, SiteUser> u2 = a.join("author", JoinType.LEFT);
				
				return cb.or(cb.like(q.get("subject"), "%"+keyword+"%"), //제목
						cb.like(q.get("content"), "%"+keyword+"%"), //내용
						cb.like(u1.get("username"), "%"+keyword+"%"), //질문 작성자
						cb.like(a.get("content"), "%"+keyword+"%"), //답변 내용
						cb.like(u2.get("username"), "%"+keyword+"%")); //답변 작성자
			}
		};
	}
search 메서드는 검색어인 keyword를 받아 쿼리 조인문과 where절을 Specification 객체로 생성하여 리턴하는 메서드이다.

아래는 사용된 변수 설명이다.
- q: Root자료형으로 기준이 되는 Question 엔티티의 객체를 말한다.
- u1: Question 엔티티와 SiteUser 엔티티를 left outer join하여 만든 SiteUser 엔티티의 객체이다.
- a: Question 엔티티와 Answer 앤티티를 left outer join하여 만든 Answer 엔티티의 객체이다.
- u2: 앞에 작성한 답변 엔티티인 a와 다시 SiteUser 엔티티와 left outer join하여 만든 SiteUser엔티티이다.

그리고 검색어가 포함되어 있는지 like로 확인하기 위해 각각 cb.like를 사용하고 이들을 최종적으로 cb.or로 OR검색을 한다.

 

질문 리포지터리 수정하기

/question/QuestionRepository.java

...
Page<Question> findAll(Specification<Question> spec, Pageable pageable);
...

위처럼 추가한 findAll 메서드는 Specification과 Pageable 객체를 사용하여 Question엔티티를 조회한 결과를 페이징하여 반환해준다.

 

질문 서비스 수정하기

검색어를 포함한 질문 목록을 반환하기 위해 getList 메서드를 수정하자.

/question/QuestionService.java

...
public Page<Question> getList(int page, String keyword){
		List<Sort.Order> sorts = new ArrayList<>();
		sorts.add(Sort.Order.desc("createDate"));
		Pageable pageable = PageRequest.of(page, 10, Sort.by(sorts));
		Specification<Question> spec= search(keyword);
		return this.questionRepostiory.findAll(pageable);
	}
...
검색어를 의미하는 keyword를 getList 매개변수로 추가하고 keyword값으로 Specification 객체를 생성하여 questionRepository의 위에서 생성한 findAll 메서드에 전달했다.

 

질문 컨트롤러 수정하기

앞서 서비스를 수정했으니 이에 맞춰 컨트롤러도 수정하자.

/question/QuestionController.java

...
	@GetMapping("/list")
	public String list(Model model, @RequestParam(value = "page", defaultValue = "0")int page,
			@RequestParam(value="keyword", defaultValue = "") String keyword) {
		Page<Question> paging = this.questionService.getList(page, keyword);
		model.addAttribute("paging",paging);
		model.addAttribute("keyword", keyword);
		return "question_list";
	}
...
일단 검색어인 keyword를 매개변수에 추가했고, questionService.getList 메서드의 매개변수를 위에서 변경했으므로 전달값을 수정해준다.
getList는 검색어가 있을수도, 없을수도 있기 때문에 기본값으로는 빈 문자열로 지정했다.
또 화면에서 검색 시 검색 키워드를 유지하기 위해 model.addAttribute("keyword", keyword)로 키워드 값을 저장했다.

 

검색 화면 구현하기

이제 화면에서 검색 기능이 동작하도록 템플릿을 수정하자.

질문 등록하기 버튼을 상단으로 옮기기 위해 제거해준다.

/templates/question_list.html

<html layout:decorate="~{layout}">
<div layout:fragment="content" class="container my-3">
	<div class="row my-3">
		<div class="col-6">
			<a th:href="@{/question/create}" class="btn btn-primary">질문 등록하기</a>
		</div>
		<div class="col-6">
			<div class="input-group">
				<input type="text" id="search_kw" class="form-control" th:value="${keyword}">
				<button class="btn btn-outline-secondary" type="button" id="btn_search">찾기</button>
			</div>
		</div>
	</div>
    ...

 

질문 목록 상단에 검색창이 있도록 했다.
오른쪽에는 입력창과 검색버튼, 왼쪽에는 기존에 있던 질문 등록하기 버튼이 배치되도록 했다.

또 자바스크립트에서 검색창에 입력된 값을 읽을 수 있도록 id속성에 'search_kw'를 지정했다.

 

검색 폼 만들기

page와 keyword를 동시에 GET방식으로 요청하기 위해 searchForm 을 추가해보자.

/templates/question_list.html

...
<!-- 페이징 처리 끝 -->

<form th:action="@{/question/list}" method="get" id="searchForm">
	<input type="hidden" id="kw" name="kw" th:value="${keyword}">
	<input type="hidden" id="page" name="page" th:value="${paging.number}">
</form>

</div>
</html>
GET방식으로 요청하기 위해 method값을 'get'으로 지정했다.
kw와 page값은 검색하기 이전의 값을 기억해야 하므로 value값에 유지하도록 했다. 이 값들은 컨트롤러부터 다시 전달받는다.

그리고 action 속성에는 폼이 전송되는 URL인 '/question/list'를 지정했다.
POST방식이 아닌 GET으로 전달하는 이유

만약 POST방식으로 전달했다면 '새로고침'이나 '뒤로가기' 버튼을 클릭하게 되면
'만료된 페이지입니다.'라는 오류가 난다.
그렇기 때문에 GET방식을 통해 주소로 keyword와 page 값을 전달하는 것이 좋다.

 

페이징 수정하기

페이징 부분도 기존의 ?page=3과 같이 직접 URL을 통해 링크하는 방식이 아니라 값을 읽어 폼에 설정할 수 있도록 변경해야한다.

왜냐하면 검색어가 있을 경우 검색어와 페이지 번호를 함께 전달해야 하기 때문!

/templates/question_list.html

...
<!-- 페이징 처리 시작 -->
<div th:if="${!paging.isEmpty()}">
	<ul class="pagination justify-content-center">
		<li class="page-item" th:classappend="${!paging.hasPrevious} ? 'disabled'">
			<a class="page-link" href="javascript:void(0)" th:data-page="${paging.number-1}">
				<span>이전</span>
			</a>
		</li>
		<li th:each="page: ${#numbers.sequence(0, paging.totalPages-1)}"
		th:if="${page >= paging.number-5 and page <= paging.number+5}"
		th:classappend="${page == paging.number}? 'active'" class="page-item">
			<a th:text="${page}" class="page-link" href="javascript:void(0)" th:data-page="${page}"></a>
		</li>
		<li class="page-item" th:classappend="${!paging.hasNext} ? 'disabled'">
			<a class="page-link" href="javascript:void(0)" th:data-page="${paging.number+1}">
				<span>다음</span>
			</a>
		</li>
	</ul>
</div>
<!-- 페이징 처리 끝 -->
...
모든 링크 a태그의 href속성에 직접 입력하지 않고 dat-page 속성으로 값을 읽도록 수정했다.

 

검색 스크립트 추가하기

page값과 keyword값을 동시에 요청할 수 있는 스크립트를 추가해보자.

/templates/question_list.html

...
<script layout:fragment="script" type='text/javascript'>
	const page_elements = document.getElementsByClassName("page-link");
	Array.from(page_elements).forEach(function(element){
		element.addEventListener('click', function(){
			document.getElementById('page').value = this.dataset.page;
			document.getElementById('searchForm').submit();
		});
	});
	
	const btn_search = document.getElementById("btn_search");
	btn_search.addEventListener('click', function(){
		document.getElementById('keyword').value = document.getElementById('search_kw').value;
		document.getElementById('page').value = 0; //검색은 0페이지부터 조회
		document.getElementById('searchForm').submit();
	});
</script>
</html>

 

결과 확인하기

질문등록하기 버튼이 상단으로 이동, 검색 기능 생성

@Query 애너테이션 사용하기

직접 쿼리를 작성하는 방법이다.

/question/QuestionRepository.java

...
	@Query("select"
			+ "distinct q "
			+ "from Question q "
			+ "left outer join Siteuser u1 on q.author=u1 "
			+ "left outer join Answer a on a.question=q "
			+ "left outer join SiteUser u2 on a.author=u2 "
			+ "where"
			+ " q.subject like %:kw% "
			+ " or q.content like %:kw% "
			+ " or u1.username like %:kw% "
			+ " or a.content like %:kw% "
			+ " or u2.subject like %:kw% ")
	Page<Question> findAllByKeyword(@Param("kw") String kw, Pageable pageable);

 

/question/QuestionService.java

...
	public Page<Question> getList(int page, String keyword){
		List<Sort.Order> sorts = new ArrayList<>();
		sorts.add(Sort.Order.desc("createDate"));
		Pageable pageable = PageRequest.of(page, 10, Sort.by(sorts));
		Specification<Question> spec= search(keyword);
		return this.questionRepostiory.findAllByKeyword(keyword, pageable);
	}
...

더 간단하게 구현된다.

728x90
반응형
LIST

+ Recent posts