Getting Started

Building a RESTful Web Service

A sample page that uses RESTful web services using HTTP support methods such as GET, PUT, POST and DELETE.

GETTING STARTED
EXAMPLE DEMOSTRATION
REVIEWS 0 Comments

root-configuration.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aspectran PUBLIC "-//ASPECTRAN//DTD Aspectran Configuration 4.0//EN"
    "https://aspectran.github.io/dtd/aspectran-4.dtd">

<aspectran>

  <description>
    본 Aspectran Configuration은 Aspectran을 이용해서 RESTful Web Service를 만드는 과정을 안내하기 위한 것입니다.
  </description>

  <!-- 기본 설정 -->
  <settings>
    <setting name="transletNamePattern" value="/gs-rest-service/*"/>
  </settings>

  <bean scan="sample.*Dao">
    <description>
      sample 패키지 하위에 있는 DAO Bean을 찾아서 등록합니다.
    </description>
  </bean>

  <bean scan="sample.*Action">
    <description>
      sample 패키지 하위에 있는 Action Bean을 찾아서 등록합니다.
    </description>
  </bean>

  <bean id="jspViewDispatcher" class="com.aspectran.web.support.view.JspViewDispatcher">
    <description>
      JSP View Dispatcher를 등록합니다.
    </description>
    <properties>
      <item name="prefix">/WEB-INF/jsp/</item>
      <item name="suffix">.jsp</item>
    </properties>
  </bean>

  <aspect id="transletSettings">
    <description>
      요청 정보를 분석 및 응답하는 단계에서 사용할 기본 환경 변수를 정의합니다.
    </description>
    <joinpoint type="translet"/>
    <settings>
      <setting name="characterEncoding" value="utf-8"/>
      <setting name="contentEncoding" value="gzip"/>
      <setting name="viewDispatcher" value="jspViewDispatcher"/>
    </settings>
  </aspect>

  <bean id="corsProcessor" class="com.aspectran.web.support.cors.DefaultCorsProcessor">
    <properties>
      <item name="allowedOrigins" type="set">
        <value>https://www.aspectran.com</value>
        <value>https://backend.aspectran.com</value>
        <value>https://backend2.aspectran.com</value>
      </item>
      <item name="allowedMethods" type="set">
        <value>GET</value>
        <value>POST</value>
        <value>PATCH</value>
        <value>PUT</value>
        <value>DELETE</value>
        <value>HEAD</value>
        <value>OPTIONS</value>
      </item>
      <item name="maxAgeSeconds" value="360" valueType="int"/>
      <item name="exposedHeaders" value="Location"/>
    </properties>
  </bean>

  <aspect id="corsProcessorAspect">
    <joinpoint type="translet">
      methods: [
        GET
        POST
        PATCH
        PUT
        DELETE
      ]
      headers: [
        Origin
      ]
      pointcut: {
        +: /**/*
      }
    </joinpoint>
    <advice bean="corsProcessor">
      <before>
        <action method="processActualRequest"/>
      </before>
    </advice>
    <exception>
      <thrown type="com.aspectran.web.support.cors.CorsException">
        <transform type="transform/text">
          <template engine="builtin">
            @{CORS.HTTP_STATUS_CODE}: @{CORS.HTTP_STATUS_TEXT}
          </template>
        </transform>
      </thrown>
    </exception>
  </aspect>

  <translet name="/**/*" method="OPTIONS">
    <action bean="corsProcessor" method="processPreflightRequest"/>
    <exception>
      <thrown type="com.aspectran.web.support.cors.CorsException">
        <transform type="transform/text">
          <template engine="builtin">
            @{CORS.HTTP_STATUS_CODE}: @{CORS.HTTP_STATUS_TEXT}
          </template>
        </transform>
      </thrown>
    </exception>
  </translet>

  <append file="/WEB-INF/aspectran/config/customers-translets.xml"/>

</aspectran>

customers-translets.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE aspectran PUBLIC "-//ASPECTRAN//DTD Aspectran Configuration 4.0//EN"
        "https://aspectran.github.io/dtd/aspectran-4.dtd">

<aspectran>

    <description>
      본 Aspectran Configuration은 RESTful Web Service를 만드는 과정을 안내하기 위한 것입니다.
    </description>

    <translet name="echo/${msg}" method="ALL">
      <description>
        요청 URI로부터 ${msg} 부분을 msg 파라메터로 받아서
        텍스트 문서 형식으로 응답을 처리합니다.
      </description>
      <transform type="transform/text">
        <template>
          Message: ${msg}
        </template>
      </transform>
    </translet>

    <translet name="index">
      <dispatch name="customers"/>
    </translet>

    <translet name="customers" method="GET">
      <description>
        전체 고객 목록을 조회합니다.
      </description>
      <action id="customers" bean="class:sample.CustomerAction" method="getCustomerList"/>
      <transform type="transform/json" pretty="true"/>
    </translet>

    <translet name="customers/${id:guest}" method="GET">
      <description>
        id를 파라메터로 받아서 해당 id를 가진 고객의 상세정보를 조회합니다.
        고객번호를 지정하지 않으면 고객번호가 "guest"인 고객의 상세정보를 조회합니다.
      </description>
      <action id="customer" bean="class:sample.CustomerAction" method="getCustomer"/>
      <transform type="transform/json" pretty="true"/>
    </translet>

    <translet name="customers" method="POST">
      <description>
        고객정보를 등록합니다.
      </description>
      <action bean="class:sample.CustomerAction" method="insertCustomer"/>
      <transform type="transform/json" pretty="true"/>
    </translet>

    <translet name="customers/${id}" method="PUT">
      <description>
        고객정보를 수정합니다.
      </description>
      <action bean="class:sample.CustomerAction" method="updateCustomer"/>
      <transform type="transform/json" pretty="true"/>
    </translet>

    <translet name="customers/${id}/approve/${approved}" method="PUT">
      <description>
        id를 파라메터로 받아서 해당 id를 가진 고객에 대해 승인처리를 합니다.
        "${approved}"는 승인여부에 해당하는 값을 지정합니다. (true or false)
      </description>
      <action id="result" bean="class:sample.CustomerAction" method="approve"/>
      <transform type="transform/json" pretty="true"/>
    </translet>

    <translet name="customers/${id}/approve" method="GET">
      <description>
        id를 파라메터로 받아서 해당 id를 가진 고객에 대하여 승인여부를 조회합니다.
      </description>
      <action id="result" bean="class:sample.CustomerAction" method="isApproved"/>
      <transform type="transform/json" pretty="true"/>
    </translet>

    <translet name="customers/${id}" method="DELETE">
      <description>
        id를 파라메터로 받아서 해당 id를 가진 고객의 정보를 삭제합니다.
      </description>
      <action id="result" bean="class:sample.CustomerAction" method="deleteCustomer"/>
      <transform type="transform/json" pretty="true"/>
    </translet>

</aspectran>

Customer.java

package sample;

import com.aspectran.core.util.apon.AbstractParameters;
import com.aspectran.core.util.apon.ParameterDefinition;
import com.aspectran.core.util.apon.ParameterValueType;

/**
 * 고객정보 레코드를 정의합니다.
 * APON의 Parameters 객체를 활용합니다.
 */
public class Customer extends AbstractParameters {

  /** 고객번호 */
  public static final ParameterDefinition id;

  /** 이름 */
  public static final ParameterDefinition name;

  /** 나이 */
  public static final ParameterDefinition age;

  /** 승인 여부 */
  public static final ParameterDefinition approved;

  private static final ParameterDefinition[] parameterDefinitions;

  static {
    id = new ParameterDefinition("id", ParameterValueType.INT);
    name = new ParameterDefinition("name", ParameterValueType.STRING);
    age = new ParameterDefinition("age", ParameterValueType.INT);
    approved = new ParameterDefinition("approved", ParameterValueType.BOOLEAN);

    parameterDefinitions = new ParameterDefinition[] {
      id,
      name,
      age,
      approved
    };
  }

  /**
   * Instantiates a new customer.
   */
  public Customer() {
    super(parameterDefinitions);
  }

  /**
   * Instantiates a new customer.
   *
   * @param text the Text string of APON format
   */
  public Customer(String text) {
    super(parameterDefinitions, text);
  }

}

CustomerDao.java

package sample;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentSkipListMap;
import java.util.concurrent.atomic.AtomicInteger;

import com.aspectran.core.util.logging.Log;
import com.aspectran.core.util.logging.LogFactory;

/**
 * 고객 정보 DAO
 */
public class CustomerDao {

  private final Log log = LogFactory.getLog(CustomerDao.class);

  private final Map<Integer, Customer> customerMap;

  private static final AtomicInteger counter = new AtomicInteger();

  public CustomerDao() {
    // 10명의 고객을 미리 생성합니다.
    customerMap = new ConcurrentSkipListMap<Integer, Customer>();

    for(int i = 1; i <= 10; i++) {
      Customer customer = new Customer();
      customer.putValue(Customer.id, i);
      customer.putValue(Customer.name, "Guest - " + i);
      customer.putValue(Customer.age, i + 20);
      customer.putValue(Customer.approved, true);

      customerMap.put(i, customer);
    }

    counter.set(customerMap.size() + 1);
  }

  public Customer getCustomer(int id) {
    log.info(id + "번 고객의 상세정보를 조회합니다.");

    Customer customer = customerMap.get(id);

    return customer;

  }

  public boolean isCustomer(int id) {
    if(customerMap.containsKey(id)) {
      log.info(id + "번 고객은 등록되어 있습니다.");
      return true;
    } else {
      log.info(id + "번 고객은 등록되어 있지 않습니다.");
      return false;
    }
  }

  public List<Customer> getCustomerList() {
    log.info("전체 고객 목록을 조회합니다.");

    List<Customer> customerList = new ArrayList<Customer>(customerMap.values());

    log.info(customerList.size() + "명의 고객이 조회되었습니다.");

    return customerList;
  }

  public int insertCustomer(Customer customer) {
    int id = counter.incrementAndGet();
    customer.putValue(Customer.id, id);

    customerMap.put(id, customer);

    log.info(id + "번 고객이 등록되었습니다.");

    return id;
  }

  public synchronized boolean updateCustomer(Customer customer) {
    int id = customer.getInt(Customer.id);

    if(customerMap.containsKey(id)) {
      log.info(id + "번 고객의 정보를 수정합니다.");
      customerMap.put(id, customer);
      return true;
    }

    return false;
  }

  public synchronized boolean deleteCustomer(int id) {
    if(customerMap.containsKey(id)) {
      log.info(id + "번 고객의 정보를 삭제합니다.");
      customerMap.remove(id);
      return true;
    }

    return false;
  }

  public boolean approve(int id, boolean approved) {
    Customer customer = customerMap.get(id);

    if(customer != null) {
      log.info(id + "번 고객에 대해 승인처리를 합니다. (승인여부: " + approved + ")");
      customer.putValue(Customer.approved, approved);
      return true;
    }

    return false;
  }

  public boolean isApproved(int id) {
    Customer customer = customerMap.get(id);

    if(customer != null) {
      log.info(id + "번 고객에 대해 승인여부를 조회합니다.");
      return customer.getBoolean(Customer.approved);
    }

    return false;
  }

}

CustomerAction.java

package sample;

import java.util.List;

import com.aspectran.core.activity.Translet;
import com.aspectran.core.context.bean.annotation.Autowired;
import com.aspectran.web.support.http.HttpStatusSetter;

public class CustomerAction {

  @Autowired
  private CustomerDao dao;

  public List<Customer> getCustomerList(Translet translet) {
    return dao.getCustomerList();
  }

  public Customer getCustomer(Translet translet) {
    int id = Integer.parseInt(translet.getParameter("id"));

    Customer customer = dao.getCustomer(id);

    if(customer == null) {
      HttpStatusSetter.notFound(translet);
      return null;
    }

    return customer;
  }

  public Customer insertCustomer(Translet translet) {
    String name = translet.getParameter("name");
    int age = Integer.valueOf(translet.getParameter("age"));
    boolean approved = "Y".equals(translet.getParameter("approved"));

    Customer customer = new Customer();
    customer.putValue(Customer.name, name);
    customer.putValue(Customer.age, age);
    customer.putValue(Customer.approved, approved);

    int id = dao.insertCustomer(customer);

    String resourceUri = translet.getName() + "/" + id;
    HttpStatusSetter.created(translet, resourceUri);

    return customer;
  }

  public Customer updateCustomer(Translet translet) {
    int id = Integer.parseInt(translet.getParameter("id"));
    String name = translet.getParameter("name");
    int age = Integer.valueOf(translet.getParameter("age"));
    boolean approved = "Y".equals(translet.getParameter("approved"));

    Customer customer = new Customer();
    customer.putValue(Customer.id, id);
    customer.putValue(Customer.name, name);
    customer.putValue(Customer.age, age);
    customer.putValue(Customer.approved, approved);

    boolean updated = dao.updateCustomer(customer);

    if(!updated) {
      HttpStatusSetter.notFound(translet);
      return null;
    }

    return customer;
  }

  public boolean deleteCustomer(Translet translet) {
    int id = Integer.parseInt(translet.getParameter("id"));

    boolean deleted = dao.deleteCustomer(id);

    if(!deleted) {
      HttpStatusSetter.notFound(translet);
      return false;
    }

    return true;
  }

  public boolean approve(Translet translet) {
    int id = Integer.parseInt(translet.getParameter("id"));
    boolean approved = Boolean.parseBoolean(translet.getParameter("approved"));

    boolean updated = dao.approve(id, approved);

    if(!updated) {
      HttpStatusSetter.notFound(translet);
      return false;
    }

    return true;
  }

  public boolean isApproved(Translet translet) {
    int id = Integer.parseInt(translet.getParameter("id"));
    return dao.isApproved(id);
  }

}

Customer List

0

Customer Details

0
Approval Status:
200