1. 개요

LinkRest 는 데이터 기반 REST 웹 서비스를 구축하기 위한 오픈 소스 프레임워크입니다. JAX-RS Apache Cayenne ORM 위에 구축되었으며HTTP/JSON 기반 메시지 프로토콜을 사용합니다.

기본적으로 이 프레임워크는 데이터 저장소를 웹에 쉽게 노출할 수 있는 방법을 제공하기 위한 것입니다.

다음 섹션에서는 LinkRest 를 사용하여 데이터 모델에 액세스하기 위해 REST 웹 서비스를 구축하는 방법을 살펴 보겠습니다 .

2. 메이븐 의존성

라이브러리 작업을 시작하려면 먼저 링크-레스트 의존성을 추가해야 합니다.

<dependency>
    <groupId>com.nhl.link.rest</groupId>
    <artifactId>link-rest</artifactId>
    <version>2.9</version>
</dependency>

이것은 또한 cayenne-server 아티팩트를 가져옵니다.

또한 JerseyJAX-RS 구현으로 사용하므로 JSON 응답을 직렬화하기 위해 jersey-container-servlet 의존성과 jersey-media-moxy 를 추가해야 합니다.

<dependency>
    <groupId>org.glassfish.jersey.containers</groupId>
    <artifactId>jersey-container-servlet</artifactId>
    <version>2.25.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>2.25.1</version>
</dependency>

이 예에서는 설정이 더 쉽기 때문에 메모리 내 H2 데이터베이스로 작업할 것입니다. 결과적으로 h2 도 추가합니다 .

<dependency>
    <groupId>com.h2database</groupId>
    <artifactId>h2</artifactId>
    <version>1.4.196</version>
</dependency>

3. 카이엔 데이터 모델

작업할 데이터 모델에는 일대다 관계를 나타내는 부서직원 엔터티가 포함됩니다.

테이블

언급한 바와 같이 LinkRest 는 Apache Cayenne ORM 을 사용하여 생성된 데이터 개체와 함께 작동합니다 . Cayenne 작업 은 이 기사의 주요 주제가 아니므로 자세한 내용은 Apache Cayenne 문서 를 확인하십시오 .

Cayenne 프로젝트를 cayenne-linkrest-project.xml 파일 에 저장 합니다.

cayenne-maven-plugin 을 실행한 후 두 개의 _Department_Employee 추상 클래스 를 생성합니다. 이 클래스는 CayenneDataObject 클래스와 이들로부터 파생된 두 개의 구체적인 클래스인 DepartmentEmployee 를 확장 합니다.

후자의 클래스는 LinkRest 와 함께 사용자 정의하고 사용할 수 있는 클래스 입니다.

4. LinkRest 애플리케이션 시작

다음 섹션에서는 REST Endpoints을 작성하고 테스트할 것이므로 실행하려면 런타임을 설정해야 합니다.

JerseyJAX-RS 구현 으로 사용하고 있으므로 ResourceConfig 를 확장 하고 REST 엔드포인트를 정의하는 클래스를 보유할 패키지를 지정하는 클래스를 추가해 보겠습니다.

@ApplicationPath("/linkrest")
public class LinkRestApplication extends ResourceConfig {

    public LinkRestApplication() {
        packages("com.baeldung.linkrest.apis");
        
        // load linkrest runtime
    }
}

동일한 생성자에서 LinkRestRuntime 을 빌드하고 Jersey 컨테이너에 등록해야 합니다. 이 클래스는 CayenneRuntime 의 첫 번째 로드를 기반으로 합니다 .

ServerRuntime cayenneRuntime = ServerRuntime.builder()
  .addConfig("cayenne-linkrest-project.xml")
  .build();
LinkRestRuntime lrRuntime = LinkRestBuilder.build(cayenneRuntime);
super.register(lrRuntime);

마지막으로 web.xml 에 클래스를 추가해야 합니다 .

<servlet>
    <servlet-name>linkrest</servlet-name>
    <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.baeldung.LinkRestApplication</param-value>
        </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>linkrest</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>

5. REST 리소스

이제 모델 클래스가 있으므로 REST 리소스 작성을 시작할 수 있습니다.

REST Endpoints은 표준 JAX-RS 어노테이션을 사용하여 생성되는 반면 응답은 LinkRest 클래스를 사용하여 빌드 됩니다 .

우리의 예는 다른 HTTP 방법을 사용하여 /department URL 에 액세스하는 일련의 CRUD Endpoints을 작성하는 것으로 구성됩니다 .

먼저 /department 에 매핑되는 DepartmentResource 클래스를 생성해 보겠습니다 .

@Path("department")
@Produces(MediaType.APPLICATION_JSON)
public class DepartmentResource {

    @Context
    private Configuration config;
    
    // ...
}

LinkRest 클래스 에는 JAX-RS에서 제공하는 컨텍스트 어노테이션을 사용하여 삽입되는 JAX-RS 구성 클래스 인스턴스 가 필요합니다 .

다음으로 부서 개체 에 액세스하는 각 Endpoints을 계속 작성해 보겠습니다 .

5.1. POST를 사용하여 엔티티 생성

엔티티를 생성하기 위해 LinkRest 클래스는 UpdateBuilder 객체 를 반환하는 create() 메서드를 제공합니다.

@POST
public SimpleResponse create(String data) {
    return LinkRest.create(Department.class, config).sync(data);
}

데이터 매개변수는 부서 를 나타내는 단일 JSON 개체 이거나 개체 배열일 수 있습니다. 이 매개변수는 sync() 메서드를 사용하여 UpdateBuilder 로 전송되어 하나 이상의 객체를 생성하고 레코드를 데이터베이스에 삽입한 후 메서드가 SimpleResponse 를 반환합니다 .

라이브러리는 응답에 대해 3가지 추가 형식을 정의합니다.

  • DataResponse<T> – T 의 컬렉션을 나타내는 응답
  • MetadataResponse<T> – 유형에 대한 메타데이터 정보를 포함합니다.
  • SimpleResponse – 두 개의 성공메시지 속성 을 포함하는 객체

다음으로 curl 을 사용하여 부서 레코드를 데이터베이스 에 추가해 보겠습니다.

curl -i -X POST -H "Content-Type:application/json" 
  -d "{"name":"IT"}" http://localhost:8080/linkrest/department

결과적으로 이 명령은 상태 201 Created성공 속성을 반환합니다.

{"success":true}

JSON 배열을 전송하여 여러 개체를 만들 수도 있습니다.

curl -i -X POST -H "Content-Type:application/json" 
  -d "[{"name":"HR"},{"name":"Marketing"}]" 
  http://localhost:8080/linkrest/department

5.2. GET을 사용하여 엔티티 읽기

개체를 쿼리하는 기본 메서드 는 LinkRest 클래스 의 select() 메서드입니다 . 추가 쿼리 또는 필터링 메서드를 연결하는 데 사용할 수 있는 SelectBuilder 객체를 반환합니다 .

데이터베이스의 모든 부서 개체 를 반환 하는 DepartmentResource 클래스 에 엔드포인트를 생성해 보겠습니다 .

@GET
public DataResponse<Department> getAll(@Context UriInfo uriInfo) {
    return LinkRest.select(Department.class, config).uri(uriInfo).get();
}

uri() 호출 은 SelectBuilder 에 대한 요청 정보를 설정하는 반면 get() 은 DataResponse<Department> 개체 로 래핑된 부서 컬렉션을 반환합니다.

이 Endpoints을 사용하기 전에 추가한 부서를 살펴보겠습니다.

curl -i -X GET http://localhost:8080/linkrest/department

응답은 데이터 배열과 속성 이 있는 JSON 개체의 형식을 취합니다 .

{"data":[
  {"id":200,"name":"IT"},
  {"id":201,"name":"Marketing"},
  {"id":202,"name":"HR"}
], 
"total":3}

또는 객체 컬렉션을 검색하기 위해 get () 대신 getOne() 을 사용하여 단일 객체를 반환할 수도 있습니다 .

주어진 ID를 가진 객체를 반환하는 /department/{departmentId} 에 매핑된 엔드포인트를 추가해 보겠습니다 . 이를 위해 byId() 메서드를 사용하여 레코드를 필터링합니다.

@GET
@Path("{id}")
public DataResponse<Department> getOne(@PathParam("id") int id, 
  @Context UriInfo uriInfo) {
    return LinkRest.select(Department.class, config)
      .byId(id).uri(uriInfo).getOne();
}

그런 다음 이 URL에 GET 요청을 보낼 수 있습니다.

curl -i -X GET http://localhost:8080/linkrest/department/200

결과는 하나의 요소가 있는 데이터 배열입니다.

{"data":[{"id":200,"name":"IT"}],"total":1}

5.3. PUT을 사용하여 엔티티 업데이트

레코드를 업데이트하려면 update() 또는 createOrUpdate() 메서드를 사용할 수 있습니다. 후자는 존재하는 경우 레코드를 업데이트하고 존재하지 않는 경우 생성합니다.

@PUT
public SimpleResponse createOrUpdate(String data) {
    return LinkRest.createOrUpdate(Department.class, config).sync(data);
}

이전 섹션과 마찬가지로 데이터 인수는 단일 개체 또는 개체 배열일 수 있습니다.

이전에 추가한 부서 중 하나를 업데이트해 보겠습니다.

curl -i -X PUT -H "Content-Type:application/json" 
  -d "{"id":202,"name":"Human Resources"}" 
  http://localhost:8080/linkrest/department

이것은 성공 또는 오류 메시지와 함께 JSON 객체를 반환합니다. 그런 다음 ID가 202인 부서 이름이 변경되었는지 확인할 수 있습니다.

curl -i -X GET http://localhost:8080/linkrest/department/202

물론 이 명령은 새 이름을 가진 개체를 반환합니다.

{"data":[
  {"id":202,"name":"Human Resources"}
],
"total":1}

5.4. DELETE 를 사용하여 엔티티 제거

그리고 개체를 제거하려면 DeleteBuilder 를 생성하는 delete() 메서드를 호출한 다음 id() 메서드 를 사용하여 삭제할 개체의 기본 키를 지정할 수 있습니다 .

@DELETE
@Path("{id}")
public SimpleResponse delete(@PathParam("id") int id) {
    return LinkRest.delete(Department.class, config).id(id).delete();
}

그런 다음 curl 을 사용하여 이 Endpoints을 호출할 수 있습니다 .

curl -i -X DELETE http://localhost:8080/linkrest/department/202

5.5. 엔터티 간 관계 작업

LinkRest 에는 객체 간의 관계 작업을 보다 쉽게 ​​해주는 메서드도 포함되어 있습니다.

Department 는 Employee 와 일대다 관계 이므로 EmployeeSubResource 클래스 에 액세스하는 /department/{departmentId}/employees 엔드포인트를 추가해 보겠습니다 .

@Path("{id}/employees")
public EmployeeSubResource getEmployees(
  @PathParam("id") int id, @Context UriInfo uriInfo) {
    return new EmployeeSubResource(id);
}

EmployeeSubResource 클래스 는 부서에 해당하므로 부서 ID를 설정하는 생성자와 구성 인스턴스를 갖습니다.

@Produces(MediaType.APPLICATION_JSON)
public class EmployeeSubResource {
    private Configuration config;

    private int departmentId;

    public EmployeeSubResource(int departmentId, Configuration configuration) {
        this.departmentId = departmentId;
        this.config = config;
    }

    public EmployeeSubResource() {
    }
}

개체를 JSON 개체로 직렬화하려면 기본 생성자가 필요합니다.

다음으로 부서에서 모든 직원을 검색하는 엔드포인트를 정의해 보겠습니다.

@GET
public DataResponse<Employee> getAll(@Context UriInfo uriInfo) {
    return LinkRest.select(Employee.class, config)
      .toManyParent(Department.class, departmentId, Department.EMPLOYEES)
      .uri(uriInfo).get();
}

이 예제에서는 SelectBuilder 의 toManyParent() 메서드를 사용하여 지정된 부모가 있는 개체만 쿼리했습니다.

POST, PUT, DELETE 메서드의 Endpoints은 비슷한 방식으로 만들 수 있습니다.

직원을 부서에 추가하려면 POST 메서드를 사용 하여 departments/{departmentId}/employees 엔드포인트를 호출할 수 있습니다 .

curl -i -X POST -H "Content-Type:application/json" 
  -d "{"name":"John"}" http://localhost:8080/linkrest/department/200/employees

그런 다음 부서의 직원을 보기 위해 GET 요청을 보내겠습니다.

curl -i -X GET "http://localhost:8080/linkrest/department/200/employees

다음은 데이터 배열이 포함된 JSON 객체를 반환합니다.

{"data":[{"id":200,"name":"John"}],"total":1}

6. 요청 매개변수로 응답 사용자 지정

LinkRest 는 요청에 특정 매개 변수를 추가하여 응답을 사용자 지정하는 쉬운 방법을 제공합니다. 결과 집합의 속성 집합을 필터링, 정렬, 페이지 매기기 또는 제한하는 데 사용할 수 있습니다.

6.1. 필터링

cayenneExp 매개변수 를 사용하여 속성 값을 기반으로 결과를 필터링할 수 있습니다 . 이름에서 알 수 있듯이 Cayenne 의 형식을 따릅니다 .

이름이 "IT"인 부서만 반환하는 요청을 보내봅시다.

curl -i -X GET http://localhost:8080/linkrest/department?cayenneExp=name='IT'

6.2. 정렬

결과 세트를 정렬하기 위해 추가할 매개변수는 sortdir 입니다. 이들 중 첫 번째는 정렬할 속성을 지정하고 두 번째는 정렬 방향을 지정합니다.

이름별로 정렬된 모든 부서를 살펴보겠습니다.

curl -i -X GET "http://localhost:8080/linkrest/department?sort=name&dir=ASC"

6.3. 쪽수 매기기

라이브러리는 시작한계 매개변수를 추가하여 페이지 매김을 지원합니다.

curl -i -X GET "http://localhost:8080/linkrest/department?start=0&limit=2

6.4. 속성 선택

포함제외 매개변수를 사용 하여 결과에 반환되는 속성 또는 관계를 제어할 수 있습니다.

예를 들어 부서 이름만 표시하는 요청을 전송해 보겠습니다.

curl -i -X GET "http://localhost:8080/linkrest/department?include=name

이름만 있는 부서의 직원과 이름을 표시하려면 include 속성을 두 번 사용할 수 있습니다.

curl -i -X GET "http://localhost:8080/linkrest/department?include=name&include=employees.name

7. 결론

이 기사에서는 LinkRest 프레임워크를 사용하여 REST Endpoints을 통해 데이터 모델을 신속하게 노출하는 방법을 보여주었습니다.

예제의 전체 소스 코드는 GitHub 에서 찾을 수 있습니다 .

res – REST (eBook) (cat=REST)