Spring/Spring boot

Restful 웹 서비스 구축

원2 2022. 8. 16. 16:06
728x90
반응형

http get 요청을 수락하는 서비스를 만들어보자

 

프로젝트를 만들고 종속성에 Spring  Web 을 추가

 

{
    "id": 1,
    "content": "Hello, World!"
}

쿼리 매개변수를 보내면?  요런 JSON 데이터를 반환할것임

 

 

 

src/main/java/에 객체를 하나 생성

package com.example.restservice;

import lombok.Data;

@Data
public class Greeting {

    private final long id;
    private final String content;

}

Jackson JSON 라이브러리가 자동으로 JSON 형태로 자동 마샬링 해준다

Jackson Starter에 기본적으로 포함된 기능

 

리소스 컨트롤러 생성

package com.example.restservice;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.atomic.AtomicLong;

// @Controller + @ResponseBody 하위 메서드에 JSON 전송가능
// 하위 모든 메서드가 view 대신 도메인 개체를 반환
@RestController
public class GreetingController {

    private static final String template = "Hello, %s!";
    private final AtomicLong counter = new AtomicLong();

    // Greeting 객체를 JSON 으로 변환해야하는데 Spring 에서는 Http 메세지 변환기를 자동으로 지원
    //  MappingJackson2HttpMessageConverter 가 자동으로 실행됨
    @GetMapping("/greeting")
    public Greeting greeting(@RequestParam(value = "name", defaultValue = "World") String name) {

        return new Greeting(counter.incrementAndGet(), String.format(template, name));
    }

}

 

컨트롤러 자체는 단순하지만 많은 작업이 들어있다

 

@RequestParam 쿼리 매개변수 name 를 받아와서 바인딩 / 매개변수가 없다면 defaultValue 의 값인 "World"

반환값으로 새로운 개체(new)를 생성하고 지정된 형식을 반환

 

MVC 컨트롤러와 RESTful 웹 서비스 컨트롤러의 주요 차이점 : HTTP 응답 본문이 생성됨

MVC 컨트롤러 @Controller : Model 객체 생성 > 데이터 담고 View

RESTful 웹 서비스 컨트롤러 @RestController : JSON / XML 형식 HTTP 응답에 담아서 전송

 

Java - AtomicLong

Long 자료형을 갖고 있는 Wrapping 클래스

Thread-safe로 구현되어 멀티쓰레드에서 synchronized 없이 사용

synchronized 보다 적은 비용으로 동시성을 보장

  • AtomicLong() : 초기 값이 0 인 AtomicLong 생성
  • AtomicLong(10) : 초기 값이 10인 AtomicLong 생성

 

get, set, getAndset

  • get 값을 읽음
  • set 값 설정
  • getAndset 현재 값을 반환하고 새 값을 설정

 

AtomicLong atomic = new AtomicLong();

atomic.set(50);
System.out.println("get() : " + atomic.get());
// 50
System.out.println("getAndSet(150) : " + atomic.getAndSet(150));
// 50
System.out.println("get() : " + atomic.get());
// 150

 

getAndUpdate, updateAndGet

둘다 두번째 인자에 람다식을 전달할 수 있음, 값 변경 가능

  • getAndUpdate : 가져온 값을 리턴후 값 업데이트
  • updateAndGet : 가져온 값을 업데이트 한 후 리턴
AtomicLong atomic = new AtomicLong(10);
LongUnaryOperator square = (n) -> n * n;
System.out.println("getAndUpdate(square) : " + atomic.getAndUpdate(square));
// 10
System.out.println("get() : " + atomic.get());
// 100

AtomicLong atomic2 = new AtomicLong(5);
System.out.println("updateAndGet(square) : " + atomic2.updateAndGet(square));
// 25
System.out.println("get() : " + atomic2.get());
// 25

그 외

  • getAndIncrement() : 현재 값 리턴하고 +1 증가
  • incrementAndGet() : +1 증가시키고 변경된 값 리턴
  • getAndDecrement() : 현재 값 리턴하고 -1 감소
  • decrementAndGet() : -1 감소시키고 변경된 값 리턴
  • getAndAdd(newValue) : 현재 값 리턴하고, 현재 값에 newValue를 더하기
  • addAndGet(newValue) : 현재 값에 newValue를 더하고, 그 결과를 리턴
AtomicLong atomic = new AtomicLong(100);

System.out.println("getAndIncrement() : " + atomic.getAndIncrement());
// 100
System.out.println("get() : " + atomic.get());
// 101
System.out.println("incrementAndGet() : " + atomic.incrementAndGet());
// 102
System.out.println("decrementAndGet() : " + atomic.decrementAndGet());
//101
System.out.println("getAndDecrement() : " + atomic.getAndDecrement());
// 101
System.out.println("get() : " + atomic.get());
// 100
System.out.println("addAndGet(300) : " + atomic.addAndGet(300));
// 400
System.out.println("getAndAdd(400) : " + atomic.getAndAdd(400));
// 400
System.out.println("get() : " + atomic.get());
// 800

 

compareAndSet

현재 값이 예상하는 값(expect) 와 같다면 update 값으로 변경해주고 true 리턴

아니라면 데이터 변경없이 false 리턴

/**
 * Atomically sets the value to the given updated value
 * if the current value {@code ==} the expected value.
 *
 * @param expect the expected value
 * @param update the new value
 * @return {@code true} if successful. False return indicates that
 * the actual value was not equal to the expected value.
 */
public final boolean compareAndSet(long expect, long update)
AtomicLong atomic = new AtomicLong(100);

int expected = 10;
int update = 1000;

System.out.println("success ? " + atomic.compareAndSet(expected, update));
// false
System.out.println("get() : " + atomic.get());
// 100

expected = 100;
System.out.println("success ? " + atomic.compareAndSet(expected, update));
// ture
System.out.println("get() : " + atomic.get());
// 1000

 

Application

package com.example.restservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// @SpringBootApplication 는 다음의 기능들을 포함
// @Configuration : 애플리케이션 컨텍스트에 대한 빈 정의의 소스로 클래스에 태그를 지정
// @EnableAutoConfiguration : Spring Boot 에 클래스 경로 설정, 기타 빈 및 다양한 속성 설정을 기반으로 빈 추가를 시작하도록 지시
// @ComponentScan : Spring 이 해당 패키지에서 다른 구성 요소, 구성 및 서비스를 찾도록 지시하여 컨트롤러를 찾음
@SpringBootApplication
public class GreetingApplication {
    public static void main(String[] args) {
        SpringApplication.run(GreetingApplication.class, args);
    }
}

@SpringBootApplication 는 다음의 기능들을 포함
@Configuration : 애플리케이션 컨텍스트에 대한 빈 정의의 소스로 클래스에 태그를 지정
@EnableAutoConfiguration : Spring Boot 에 클래스 경로 설정, 기타 빈 및 다양한 속성 설정을 기반으로 빈 추가를 시작하도록 지시
@ComponentScan : Spring 이 해당 패키지에서 다른 구성 요소, 구성 및 서비스를 찾도록 지시하여 컨트롤러를 찾음

 

결과

atomic 으로 카운트가 자동으로 올라가고 쿼리 매개변수 user, users 를 받아서 출력ㅇㅣ 잘 된다

728x90
반응형