ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • spring-boot-rest를 해보자!(1)
    카테고리 없음 2023. 4. 18. 12:31

    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-restweb, 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);
    }
    
    
    기본 데이터가 있어야 하기 때문에 resourcesimport.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 브라우저를 열어보자! 쉽게 테스트 할 수 있다.

    댓글

Designed by Tistory.