Tutorial RESTFul Service by Jersey and Jetty Embedding

by ,

วันนี้เราจะ setup RESTFul service ด้วยการใช้ Jersey และ Jetty แบบ Embedded กันแบบง่ายๆ โดย Service ของเราสามารถคืน POJO เป็น เป็น JSON อัพโนมัติด้วย Jackson ได้ด้วย

Project นี้ผมใช้ Gradle เป็นตัว Build นะครับ ถ้าใช้ Maven ก็ลองเปลี่ยนดูครับ ต่างกันแค่ตรงประกาศ dependency

เริ่มต้นแบบ Basic

เริ่มจากการกำหนด Dependency ใน build.gradle ให้เป็นตามนี้

dependencies {
    def jettyVersion = "9.3.12.v20160915"
    def jerseyVersion = "2.23.2"

    compile "org.eclipse.jetty:jetty-server:$jettyVersion"
    compile "org.eclipse.jetty:jetty-servlet:$jettyVersion"
    compile "org.eclipse.jetty:jetty-http:$jettyVersion"
    compile "org.glassfish.jersey.containers:jersey-container-servlet-core:$jerseyVersion"
    compile "org.glassfish.jersey.containers:jersey-container-jetty-servlet:$jerseyVersion"
}

หลังจากกำหนด Dependency และทำการ Sync Gradle ใหม่แล้ว เราจะสามารถอ้างถึง Class ต่างๆของ Jetty และ Jersey ได้แล้ว

ต่อไปเราจะทำการให้โปรแกรมของเรา start server เมื่อเราทำการ execute .jar

ที่ Class หลักของเรา หรือก็คือ class ที่มี public void main(String[] args) เพิ่มโค้ดดังนี้

public void main(String[] args){
    Server server = new Server(2222);
    ServletContextHandler context = new ServletContextHandler(server, "/*");

    ServletHolder jersey = new ServletHolder(new ServletContainer(config));
    jersey.setInitOrder(0);
    jersey.setInitParameter("jersey.config.server.provider.classnames",
        SayHello.class.getCanonicalName());
    context.addServlet(jersey , "/*");

    try {
        server.start();
        server.join();
    } finnaly {
        server.destroy();
    }
}

และเพิ่ม class ที่เป็นตัว Service จริงๆ ในที่นี้เราจะสร้าง SayHello.class มีหน้าตาดังนี้

public class SayHello{

     @GET
     @Path("/say")
     @Produces("text/plain")
     public String say(){
          return "Hello"
     }
}

ที่นี้เราก็ Start server ของเราได้เลย ลองเปิด Browser แล้วเข้าไปที่ localhost:2222/say เราจะเจอขอความว่า hello

มี Servlet มากกว่า 1 class

ในชีวิตจริง Service ของเราต้องมีมากกว่า 1 class แน่นอน คงไม่มีใครเขียน Service จริงๆ ให้จบใน Class เดียวจริงไหม? หรือว่ามี?

สิ่งที่เราต้องทำคือไปที่ Main Class ของเราแล้วแก้ให้เป็นดังต่อไปนี้

public void main(String[] args){
    Server server = new Server(2222);

    ServletHolder jersey = new ServletHolder(new ServletContainer());
    jersey.setInitOrder(0);
    jersey.setInitParameter("jersey.config.server.provider.classnames",
        String.join(", ",
              SayHello.class.getCanonicalName(),
              Second.class.getConicalName(),
              Third.class.getConicalName())
        );

    ServletContextHandler context = new ServletContextHandler(server, "/*");
    context.addServlet(jersey , "/*");

    try {
        server.start();
        server.join();
    } finnaly {
        server.destroy();
    }
}

สังเกตสิ่งที่เปลี่ยนแปลงในบรรทัดที่ 7-11 แทนที่เราจะส่งชื่อ class ไป class เดียว เราเอามันมาเชื่อมกันโดยขั้นด้วย , แทน ทีนี้จะมีเพิ่มกี่ class ก็ comma แล้วใส่เพิ่มไปเรื่อยๆได้เลย

Return เป็น JSON ด้วย Jackson Media

ถ้าเราต้องการ Response แบบ application/json จาก POJO เราก็ทำดังนี้

public class JsonResource{

     @GET
     @Path("/josn")
     @Produces("application/json")
     public Entity fromPojo(){
          return new Entity("Say hi, Json");
     }

     public class Entity{
          public String message;

          public Entity(String msg){
              message = msg;
          }
     }
}

จริงๆเรื่องมันควรจบง่ายๆแค่นี้ แต่ถ้าเราลองเรียก Service นี้เราจะพบ Internal Server Error ที่เป็นเช่นนี้ เป็นเพราะว่าเราจำเป็นต้อง Register Feature การแปลง POJO เป็น Json ให้ตัว Jersey รู้ก่อน ดังนี้

ที่เพิ่ม Depdency jersey-media-json-jackson ที่ build.gradle

compile "org.glassfish.jersey.media:jersey-media-json-jackson:$jerseyVersion"

และที่ main ก่อน start server ต้องทำดังต่อไปนี้

...
ResourceConfig config = new ResourceConfig();
config.packages("your.package.name");
config.register(JacksonFeature.class);

ServletHolder jersey = new ServletHolder(new ServletContainer(config));
...

เพียงเท่านี้ เมื่อเข้าที่ localhost:2222/json ก็จะได้ Response เป็น JSON ตามที่เราต้องการแล้ว