Restful 웹 서비스 구축
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 를 받아서 출력ㅇㅣ 잘 된다