Spring boot rest 를 이용하여 API 서버를 개발해보자!
Boot에 대해 알아봤으니 다음은 spring-boot-rest 대해 알아보자.
모르는분은
링크참조
rest중 우리는 jpa를 살펴볼것이다.
프로젝트 생성후 처음 할일은 메이븐에 디펜던시를 추가 하는일이다.
아래와같이 추가를 해보자.
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-rest</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.6</version>
<scope>provided</scope>
</dependency>
</dependencies>
살펴보면
spring-boot-starter-data-rest
는
web
,
jackson
과 관련된 라이브러리가 디펜던시 되어있다.
spring-boot-starter-data-jpa
아시다시피 jpa 관련 라이브러리다.
간단하게 살펴보는거니까 메모리 디비를 사용하겠다.
귀찮은 작업이 있으니 아주 좋은
lombok
을 사용하겠다. 이놈은 선택사항이다. 모르시는분은 인터넷을 찾아보면 아주 자세히 나와있다.
메인 클래스를 만들자.
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
다음으론
entity
(domain) 클래스를 만들자.
@Entity
@Data
public class Account {
@Id
@GeneratedValue
private Long id;
private String name;
private String email;
private String password;
}
다음으론
Repository
인터페이스를 생성해보자
@RepositoryRestResource(collectionResourceRel = "account", path = "account")
public interface AccountRepository extends JpaRepository<Account, Long> {
Page<Account> findByname(@Param("name") String name, Pageable pageable);
}
기본 데이터가 있어야 하기 때문에
resources
에
import.sql
을 추가 한다. 아래와 같이 입력해보자
insert into account(id, name, email, password) values(1,wonwoo,wonwoo@test.com,qwer)
insert into account(id, name, email, password) values(2,kevin,kevin@test.com,asdf)
insert into account(id, name, email, password) values(3,wonwoo1,kevin@test.com,qwqw)
혹은
java8
을 이용한다면 좀더 멋지게 해보자
@Bean
CommandLineRunner runner(AccountRepository accountRepository) {
return args -> {
Arrays.asList(
new Account(1L, "wonwoo", "wonwoo@test.com", "qwer"),
new Account(2L, "kevin", "kevin@test.com", "asdf"),
new Account(3L, "wonwoo", "kevin@test.com", "qwqw")
)
.forEach(account -> accountRepository.save(account));
accountRepository.findAll().forEach(System.out::println);
};
}
아 물론
Account
클래스를 수정해야된다.
@Entity
@Data
@AllArgsConstructor //추가 모든 필드가 있는 생성자를 만든다.
@NoArgsConstructor //추가 디폴트 생성자를 만든다. 이놈이 필요한이유는 JPA 덕분
public class Account {
@Id
@GeneratedValue
private Long id;
private String name;
private String email;
private String password;
}
그럼 이제 메인클래스를 실행해보자!
실행이 완료되었다면
http://localhost:8080/
{
_links: {
account: {
href: "http://localhost:8080/account{?page,size,sort}",
templated: true
},
profile: {
href: "http://localhost:8080/profile"
}
}
}
웹브라우저에 이런 화면을 볼수 있다. 깔끔하게 볼라면 크롬 확장 프로그램을 설치하자.(JSONView) 였던걸로 기억한다.
이번엔 아래와 같이 계정 정보를 봐보자!
http://localhost:8080/account
{
"_embedded": {
"account": [
{
"name": "wonwoo",
"email": "wonwoo@test.com",
"password": "qwer",
"_links": {
"self": {
"href": "http://localhost:8080/account/1"
},
"account": {
"href": "http://localhost:8080/account/1"
}
}
},
{
"name": "kevin",
"email": "kevin@test.com",
"password": "asdf",
"_links": {
"self": {
"href": "http://localhost:8080/account/2"
},
"account": {
"href": "http://localhost:8080/account/2"
}
}
},
{
"name": "wonwoo1",
"email": "kevin@test.com",
"password": "qwqw",
"_links": {
"self": {
"href": "http://localhost:8080/account/3"
},
"account": {
"href": "http://localhost:8080/account/3"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/account"
},
"profile": {
"href": "http://localhost:8080/profile/account"
},
"search": {
"href": "http://localhost:8080/account/search"
}
},
"page": {
"size": 20,
"totalElements": 3,
"totalPages": 1,
"number": 0
}
}
흠. 잘 나온다. 만족하는 결과다.
이번엔
http://localhost:8080/account/search 브라우저에 띄우자
{
"_links": {
"findByname": {
"href": "http://localhost:8080/account/search/findByname{?name,page,size,sort}",
"templated": true
},
"self": {
"href": "http://localhost:8080/account/search"
}
}
}
url 중
search
는 자동으로 생성되는듯하다.
findByname
메소드 명이다.
마지막으로 이름으로 검색을 해보자
http://localhost:8080/account/search/findByname?name=wonwoo
{
"_embedded": {
"account": [
{
"name": "wonwoo",
"email": "wonwoo@test.com",
"password": "qwer",
"_links": {
"self": {
"href": "http://localhost:8080/account/1"
},
"account": {
"href": "http://localhost:8080/account/1"
}
}
}
]
},
"_links": {
"self": {
"href": "http://localhost:8080/account/search/findByname?name=wonwoo"
}
},
"page": {
"size": 20,
"totalElements": 1,
"totalPages": 1,
"number": 0
}
}
이렇게 나왔다면 성공!!
한가지 살펴 볼 것이 있다.
바로
@RepositoryRestResource(collectionResourceRel = "account", path = "account")
이거다.
RepositoryRestResource
이 애노테이션은 선택인거 같다. 없어도 잘 된다(필자는 잘된다.). 물론 스캔 범위에 있다는 가정이다. 하지만 명시적인게 좋으니 써주는것도 나쁘지 않다. 없으면 엔티티 복수형으로 자동생성하는듯 하다.
애노테이션 속성중
collectionResourceRel
은 key 속성이다. 다시말해
"account": { //이 속성
"href": "http://localhost:8080/account{?page,size,sort}",
"templated": true
},
그리고
path
는 url path를 말하는거다.
마지막으로
findByname
메소드 안에
@Param("key")
어노테이션은 파라미터의 키이다. 없으면 에러가 난다. 감지를 할수 없다는 듯하다.
key를 변경해보자.
Page<Account> findByname(@Param("first_name") String name, Pageable pageable);
그럼 키가 변경된 것을 알 수있다.
{
"_links": {
"findByname": {
"href": "http://localhost:8080/account/search/findByname{?first_name,page,size,sort}",
"templated": true
},
"self": {
"href": "http://localhost:8080/account/search"
}
}
}
다음편은 조금더 세부적으로 살펴보자!
참고 : 아래와 같이 maven에 추가해보자.
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-rest-hal-browser</artifactId>
</dependency>
그리고 다시
http://localhost:8080 브라우저를 열어보자!
쉽게 테스트 할 수 있다.