New Project!

IntelliJ를 처음 맞이하는 이 순간,,, 안드로이드 스튜디오랑 비슷해서 덜 쫄았다.

프로젝트 생성

프로젝트 생성을 누르면 다음과 같은 창이 뜨는데, Generator에서 Spring Initializr에 들어간다.

프로젝트 파일이 생성되는 위치, 언어, 빌드 도구, JDK, Java 버전 등을 설정한다.

JDK install

Java랑 JDK 버전을 맞추려고 했는데 처음엔 11 버전이 안 떠서 따로 설치해줬다.

설치하는 방법은 다양한데, 나는 homebrew를 사용했다.

brew search zulu

커맨드라인에 위와 같이 치면 현재 설치 가능한 버전 리스트가 나온다. 여기에 바로 내가 원하는 버전이 있으면 install하면 되고, 없으면 우선 버전 리스트를 업데이트해준다.

# 버전 리스트 업데이트
brew tap homebrew/cask-versions

# 해당 버전 설치
brew install --cask zulu11

build & run

이렇게 해서 무사히 프로젝트 파일을 만들고 바로 빌드 & 런을 때려보면 콘솔에 로그가 뜨고, 마지막으로 Started ~~Application in 1.971 seconds 이런 로그가 뜬다.

브라우저를 켜서 localhost:8080(로그에 뜬 포트번호)를 주소창에 넣고 엔터를 치면

404 에러가 뜬다.

이게 정상이다. 굿.

New API GET!

HTTP GET 요청에 대해 응답을 보낼 수 있는 아주 기초적인 API를 만들어보자.

@RestController

이름부터 수상쩍게 Rest다.

JSON 형태로 객체 데이터를 반환하는 컨트롤러로, API를 개발할 때 주로 사용한다.

@RestController
@RequestMapping("/main")
public class MainController {
}

MainController로 명명한 RestController를 정의해준다.

여기에 @RequestMapping을 해줬는데 이는 괄호 안에 들어간 URI에 대해 요청(Request)이 들어오면 해당 클래스 혹은 메서드를 실행시켜주는 어노테이션이다.

위에서 localhost:8080 가 열렸으니, 여기에 /main까지 붙여 요청을 보내면 MainController가 응답하는것.

이대로면 아무 것도 못하니까 특정 값을 반환하는 메서드를 만들어봤다.

@GetMapping

@RestController
@RequestMapping("/main")
public class MainController {

    @GetMapping("/name")
    public String getName() {
        return "Seri";
    }

    @GetMapping("/age")
    public int getAge() {
        return 2023 - 1996 + 1;
    }
}

RequestMapping과 비슷한 친구다.

RequestMapping은 서버가 받는 요청에 대한 다양한 응답을 매핑할 수 있다. GET, POST 등. 어떤 요청을 할건지를 인자로 넣어주면 된다.

GetMapping은 이 요청 중 GET을 처리할 수 있는 어노테이션이다.

즉, /main/name으로 들어가면 getName 메서드를, /main/age로 요청을 보내면 getAge 메서드를 실행시키는 것! 그리고 두 요청은 모두 GET이다.

New query parameter!

이번엔 쿼리 파라미터를 입력받아 이에 대한 응답을 하는 API를 만들어보자.

@RequestParam

Mapping들과 마찬가지로 메서드나 클래스에 붙여 쓰는 앤줄 알았는데, 파라미터 닉값하는 친구였다.

@GetMapping("/login")
public String login(@RequestParam("id") String id, @RequestParam("password") String password) {
    return String.format("id: %s, password: %s", id, password);
}

GetMapping으로 요청 URI를 지정하고, 해당 요청이 들어올 때 실행될 메서드의 인자로 쿼리 파라미터를 받아주면 된다.

요청할 때 /main/login?id=seri&password=1234와 같이 쿼리 파라미터를 붙여 보내주면 된다.

400

쿼리 key, value를 입력하지 않으면 다음과 같은 에러가 뜬다.

Mon Mar 13 23:46:52 KST 2023
There was an unexpected error (type=Bad Request, status=400).

404 Not Found와 다른 에러가 뜨는데, 말 그대로 요청이 잘못됐다는 뜻이다.

New Dependency!

아주 간단한 API를 만들어봤으니 아주 기초적인 라이브러리를 추가해보자.

로깅 기능과 다양한 코드의 자동화를 도와주는 lombok 라이브러리를 사용하며 의존성을 추가해보기로 했다.

build.gradle

프로젝트에서 쓰는 라이브러리들의 의존성을 관리하는 파일이다. 해당 파일을 열어보면 이런 식으로 코드가 적혀 있다.

여기서 의존성을 관리하는 부분은

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-web'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

이 부분이다.

원하는 라이브러리에 대한 의존성을 위 부분에 넣어주고 프로젝트를 다시 빌드해주면 된다.

    compileOnly 'org.projectlombok:lombok:1.18.26'
    annotationProcessor 'org.projectlombok:lombok:1.18.26'

    testCompileOnly 'org.projectlombok:lombok:1.18.26'
    testAnnotationProcessor 'org.projectlombok:lombok:1.18.26'

빌드가 새로 되고 정상적으로 의존성이 추가되면, External Libraries에 롬복옾눞이 추가된 것을 확인할 수 있다.

build in commandline

IDE 내에서 새로 빌드할수도 있지만, 커맨드라인으로 빌드할수도 있다.

이 때, 프로젝트 파일 위치에 있는 gradlew를 실행시켜 빌드하면 된다.

# 프로젝트 파일로 이동한 상태(ex, ~/IdeaProjects/firstProject)
./gradlew build

빌드가 완료돼 만들어진 실행 가능한 파일(.jar)은 /build/lib 안에 있다.

jar 파일이 두 개 있을텐데, 하나는 의존성 등의 정보가 싹 빠진 라이트한 버전의 파일이고, 하나는 완전체 파일이다. 라이트한 버전의 파일은 .jar 앞에 -plain이 붙어있다. 이 친구는 정상적으로 실행이 불가능하다.

java -jar firstProject-0.0.1-SNAPSHOT.jar

이럼 이제 IDE에서 코드 실행할때와 동일하게 로그가 줄줄이 나온다. 정상적으로 요청, 응답을 할 수 있으면 끝!

@Slf4j

Simple Loggin Facade for Java라고 한다. 이름이 괴상해서 뭔가 했더니 줄임말이었음,,

기본적으로 스프링 부트가 로깅 라이브러리를 추가하기 때문에 lombok 없이도 로깅이 가능하지만, 이러면 로그를 찍기 위해 매번 Logger를 생성해야 한다.

이 과정을 간단하게 만들기 위해 lombok 라이브러리를 추가한 것이고, 클래스에 @Slf4j 어노테이션을 붙여 바로 로그를 찍을 수 있다.

@RestController
@RequestMapping("/main")
@Slf4j
public class MainController {

    @RequestMapping("/test")
    public String logTest() {
        log.trace("++++Log Test++++");
        return "logTest";
    }

    ...(생략)
}

이런 식으로 써주면 된다.

사실 안 된다

이 상태로 장장 몇 시간동안 돌려봤는데 절대 로그가 안 나왔다. 아무리 검색창에 lombok gradle log not showing 이딴걸 쳐봐도 안 나와서 멘토님께 헬프를 쳤고…

알고보니 어플리케이션에서 로그의 레벨을 따로 설정해주지 않아 default 상태, 즉 info 레벨까지의 로그만 출력되는 것이었다!

cf) log level
trace - debug - info(default) - warn - error

생각해보니 콘솔에 로그가 이런식으로 나왔는데 다 INFO였음,,

로그 레벨 변경

application.properties 파일에 로그 레벨을 변경해주는 코드를 작성하면 콘솔에 출력되는 로그의 범위가 달라진다.

// 전체 로그 레벨 설정
logging.level.root=trace

이런식으로 작성하고 돌렸더니 시작부터 어마무시한 로그가 쏟아졌다,,, 물론 위에 적은 코드도,,,같이,,,

느낀점

아기다리고기다리던 API 실습을 처음 해 봤다.

항상 요청 보내서 응답 받아오는 클라이언트 사이드 개발만 하다가 요청에 대한 응답을 처리하는 서버 사이드 개발을 시작해보니 재미있었다.

컨트롤러, 패키지를 나누는 것도 규칙이 있을텐데 드디어 MVC 패턴의 근본을 볼 수 있는건가 기대가 된다.

이젠 에러를 만나도 갓택오버플로우와 기타등등 포럼에서 다 알아서 해주겠지… 했는데 결국 이번에도 잘 안된 부분을 멘토님의 도움을 받았다. 역시,, 개발은 혼자 하는게 아니다,,,

댓글남기기