build.gradle들이 정상적으로 동작하는지 확인하기 위해 boot jar를 만들어서 실행하기위함

 

intelij의 gradle에서 module-main > tasks > build > boot jar 더블클릭 

 

module-main > build > libs 위치에 jar파일 생성 확인 

 

파일 위치에서 탐색기에 cmd 입력 후 엔터

 

 

java -jar {파일명}

 

 

기동 완료

 

 

 


https://github.com/Kmmanki/portfolio_was

 

GitHub - Kmmanki/portfolio_was: portfolio

portfolio. Contribute to Kmmanki/portfolio_was development by creating an account on GitHub.

github.com

 

잘못 기입된 값을 받으면 400(Bad Request)를 반환하도록 ValidationCheck 로직 추가

 

CreateNromalDto

@NotBlank, @Size 등 Validation을 확인하는 어노테이션 추가

ValidationCheck에서 실패 시 MehthodArgumentNotValidException 발생

package com.portfolio.Dto;

import com.portfolio.entity.NormalBoard;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Size;
import lombok.Getter;
import lombok.Setter;


/**
 * 일반 게시판 생성 DTO
 date : 2024.07.26
 author : 김만기

 ====== Annotation description ======
 Schema: swagger 문서 작성을 위한 annotation

 Validation 관련 Annotation(조건에 부합하지않느다면 MethodArgumentNotValidException 발생)
    NotBlank: null, "" 체크
    Size: 길이 체크

 ====== field description ======
 title: 게시판 제목
 content: 게시판 내용

 ====== method description ======
 toEntity: DTO를 DB에 적재하기 위한 Entity로 변환

 ====== etc description ======
 entity를 사용하고 싶었으나 entity를 사용하면 Swagger의 example Value가 모든 필드를 표기하는 문제가 있어서 DTO를 사용

 */
@Getter
@Setter
public class CreateNormalBoardDto {
    @Schema(description = "게시판 제목", example = "게시판 제목")
    @NotBlank(message = "제목은 필수 입니다.")
    @Size(max = 30, message = "제목은 최대 30자 입니다.")
    private String title;

    @Schema(description = "게시판 내용", example = "게시판 내용")
    @NotBlank(message = "내용은 필수 입니다.")
    private String content;

    public NormalBoard toEntity() {
        return NormalBoard.builder()
                .title(title)
                .content(content)
                .build();
    }
}

 

 


ControllerExceptionHandler

Controller의 Exceltion을 처리하는 Handler

MehthodArgumentNotValidException만 처리하는 메소드 handleValidationException 

package com.portfolio.exception.handler;

import com.portfolio.dto.ApiResultDto;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/*
 * 컨트롤러 예외처리 핸들러
 * date: 2024-07-29
 * author: 김만기
 *
 * ====== Annotation description ======
 * RestControllerAdvice: RestController에서 발생하는 예외를 처리하기 위한 annotation
 * ExceptionHandler: 특정 예외를 처리하기 위한 annotation
 * 
 * ====== method description ======
 * handleValidationExceptions: @size, @notnull 등에서 발생하는 예외를 처리
 *  400 Bad Request로 응답하고, data에는 @size 등에서 지정한 message=''를 담아서 전달
 */

@RestControllerAdvice
public class ControllerExceptionHandler {

    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<ApiResultDto<String>> handleValidationExceptions(MethodArgumentNotValidException ex) {
        ApiResultDto<String> result = new ApiResultDto<>();
        result.setResultCode("400");
        result.setResultMessage("Validation Error");
        result.setData(ex.getBindingResult().getAllErrors().get(0).getDefaultMessage());
        return ResponseEntity.badRequest().body(result);
    }
}

 


프로젝트의 build.gradle

module-normal-board의 build.gralde

// 빌드 시 bootJar로 생성하지않음
bootJar { enabled = false }
// 다른 모듈의 라이브러리 형태가 될 것이기 때문에 jar 형태로 진행
jar { enabled = true }

dependencies {
    // common 모듈에 의존
    implementation project(":module-common")
    implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '3.4.0'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '3.3.0'
}

 

 

module-common의 build.gradle

bootJar { enabled = false }
jar { enabled = true }

dependencies {
   /*
   * jpa: DB ORM
   * validation: Controller 등, validation Check
   * */
    implementation group: 'org.mariadb.jdbc', name: 'mariadb-java-client', version: '3.4.0'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-data-jpa', version: '3.3.0'
    implementation group: 'org.springframework.boot', name: 'spring-boot-starter-validation', version: '2.5.2'
}

 

 


Sweager 조회 및 validation 테스트

request Body에 미리 적어둔 example 적용 완료 

 

 

shcema에는 validation 내용 및 description 확인

 

 

validation에 맞지 않는 데이터 테스트 및 결과

400 badRequest 및 @size에 함께 작성한 message 출력 확인

 

 

 


https://github.com/Kmmanki/portfolio_was

 

GitHub - Kmmanki/portfolio_was: portfolio

portfolio. Contribute to Kmmanki/portfolio_was development by creating an account on GitHub.

github.com

 

iframe으로 특정서버의 화면을 띄워야하는 일이 생겼다.

현재 운영되고 있는 서버에 추가적으로 batch Application을 올리고 iframe으로 호출하는 방식을 사용하기로 했다.

 


 

서버구성

 

 


문제1. batch 내부의 cookie 사용이 안되어 url에 jsessionId가 붙어감

예시로 /batch;jsessionid=~~~~~~~  형태로 잘못된 url이 생성되었다. 그로인데 Controller를 잘못찾아가는 문제가 발생

 

원인을 찾아보니 로컬에서 테스트 할 때 브라우저의 url을 localhost:8080~~~ 를 사용하였고 iframe의 주소는 
<iframe src="127.0.0.1:8099"..... 형식으로 사용하였기 때문에 발생

 

둘 다 같은 localhost로 변경하여 사용 하니 문제를 해결하였다.
다만 이로인해 운영에서 iframe으로 <iframe src="IP:PORT" ..... 구조를 사용 할수 없을 듯하였다.

 

운영에서는 <iframe src="도메인/batch" 형태로 사용하기로 한다.

 

 


문제2. nginx에 도메인/batch로 들어오면 2번 서버의 8099포트로 보내야한다.

 

배치서버는 1대지만 iframe 껍데기를 호출하는 서버는 2대 이다. 그렇다면 도메인/batch를 접속하게 된다면 LB를 통해
1번 서버 2번 서버 어느곳으로 갈지 알 수 없다.

 

그렇기 때문에 nginx에서 2번서버의 8099 포트로 이동 할수 있도록 proxy를 구성해야한다.

 

이를 위해 nginx의 default.conf를 수정

 

1번 서버, 2번서버 모두  location /batch/를 추가하여 어떤 서버로 요청이 오더라도 2번서버의 8099를 바라볼 수 있도록 구성

......

upstream backend{
	hash #remote_addr;
    server 1번서버아이피:8080;
    server 2번서버아이피:8080;
    
    keepalive 1024;
}

server {
	listen 443 lls;
    .... 
    기타 nginx 설정들, ssl 포함 
    
    ....
    
    location /batch/ {
    	proxy_pass http://2번서버 IP:8099;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
    
    location / {
    	proxy_pass http://backend;
    }

 

 


문제3. https에서 http의 iframe을 사용 할 수 없음

브라우저에서 iframe으로 데이터를 불러올 때 데이터가 보이지 않아 console 을 확인해보니

 

에러로그가 발생

was loaded over an insecure connection. this file should be served over https

 

찾아보니 https 도메인을 사용하며 http를 iframe으로 사용할 수 없어서 발생하는 에러로그 

 

아마 배치 application에 

return "redirect:/" 와 같이 302 redirect를 발생시키며 생기는 문제로 보임.

 

nginx의 batch location에 강제로 http를 https로 변환해주도록 설정 추가

location /batch/ {
...
  proxy_redirect http:// https://
...
}

서버에 ssh로 접속 후 프로그램을 실행 후 ssh를 끊게 되면 해당 프로세스는 종료된다.

 

이때 사용 할 수 있는 명령어가 nohup이다

nohup java -jar -Dspring.profiles.active=dev test.jar 1> /dev/null 2>& &

 

nohup을 사용하면 nohup.out이라는 로그 파일이 생성되는데 이를 생성하지 않고자 한다면 

1> /dev/null 2>& 를 사용하도록 하자

+ Recent posts