สร้าง Webservice อย่างไรใช้ให้ใช้งานได้ ทั้ง Soap และ Rest ด้วยภาษา JAVA

--

หัวข้อนี้สืบเนื่องมาจากประสบการณ์ทำงาน ซึ่งเราอยู่ในทีม EAI ย่อมาจาก Enterprise Application Integration โปรเจ็คหลักๆที่ได้ทำจะทำเกี่ยวกับ API มีพี่คนนึงถามเราว่า “โปรเจ็คนี้ วันนี้เป็น Rest ถ้าวันข้างหน้าพี่อยากให้มันเป็น Soap ด้วยล่ะ? เราต้องเขียนโค้ดใหม่หมดหรอ? ” เออว่ะ! น่าคิดค่ะ แต่เค้าก็ถามเองและก็อธิบายเองเพราะเราคิดไม่ออก ขอบคุณค่ะ บล็อคนี้เราจะมาอธิบายเรื่องนี้กัน ที่จริงไม่มีอะไรเลยนะ ทุกอย่างขึ้นอยู่ที่การ Design ล้วนๆ

บล็อคนี้เราจะมายกตัวอย่างการเขียนโปรแกรมด้วยภาษา JAVA ธรรมด๊าาา ธรรมดา ในการสร้าง Webservice แบบ Soap กับ Rest + CRUD แต่เราจะไม่ใช้ Database เราจะเล่นกับ Object แทน ยาวไปปปปปปป วะซ่านนน 😀

software

  • Eclipse
  • WebSphere Application Server(WAS-9)
  • JDK 1.8
  • PostMan
  • SoapUI
  1. เปิด Eclips ขึ้นมาแล้วเลือก File > new >Dynamic Web Project
  2. ตั้งชื่อ Project name: EmployeeWS > ◻ Add project to an EAR > NEX
  3. ถึงหน้า Web Module แล้วเลือก ☑ Generate web.xml deployment descriptor > Finish
  4. โครงสร้างทั้งหมดของโปรเจ็ครวมถึง librarice ที่จำเป็นต้องใช้
โครงสร้างทั้งหมดของโปรเจ็คที่เสร็จสมบูรณ์แล้ว

5. สร้าง Class StringUtil เพื่อเก็บไว้เรียกใช้ฟังก์ชั่น

package com.util;
import java.util.concurrent.atomic.AtomicInteger;
public class StringUtil { // เริ่มต้นที่ 101
private static final AtomicInteger sequence = new AtomicInteger(100);
public static int next() {
return sequence.incrementAndGet();
}
}

6. สร้าง Class EmployeeBean เพื่อใช้เป็น Object ในการเขียนโปรแกรม

package com.bean;import java.io.Serializable;public class EmployeeBean implements Serializable{
private static final long serialVersionUID = 1L;
private Integer id;
private String idCard;
private String fName;
private String lName;
private String email;
private String phone;

// getter and setter
}

7. สร้าง Class EmployeeDao เพื่อเขียน CRUD

package com.dao;import java.util.ArrayList;
import java.util.List;
import javax.annotation.Resource;
import javax.xml.ws.WebServiceContext;
import com.bean.EmployeeBean;
import com.util.StringUtil;
public class EmployeeDao {
@Resource
private WebServiceContext context;
static List<EmployeeBean> empList = new ArrayList<>();public EmployeeBean selectEmployeetById(String id) {
EmployeeBean empBean = new EmployeeBean();
try {
int empId = Integer.parseInt(id);
for (EmployeeBean emp : empList) {
if (emp.getId().equals(empId)) {
empBean.setId(emp.getId());
empBean.setIdCard(emp.getIdCard());
empBean.setfName(emp.getfName());
empBean.setlName(emp.getlName());
empBean.setEmail(emp.getEmail());
empBean.setPhone(emp.getPhone());
}
}
} catch (Exception ex) {
System.out.println("ERROR MESSAG :" + ex.getMessage());
}
return empBean;
}
public List<EmployeeBean> selectEmployeetAll() {
return empList;
}
public EmployeeBean insertEmployee(EmployeeBean empOjb) {
EmployeeBean empBean = new EmployeeBean();
try {
empBean.setId(StringUtil.next());
empBean.setIdCard(empOjb.getIdCard());
empBean.setfName(empOjb.getfName());
empBean.setlName(empOjb.getlName());
empBean.setEmail(empOjb.getEmail());
empBean.setPhone(empOjb.getPhone());
empList.add(empBean);
} catch (Exception ex) {
System.out.println("ERROR MESSAG :" + ex.getMessage());
}
return empBean;
}
public String updateEmployeetById(EmployeeBean empOjb) {
String result = null;
try {
for (int i = 0; i < empList.size(); i++) {
if (empList.get(i).getId().equals(empOjb.getId())) {
empList.get(i).setId(empOjb.getId());
empList.get(i).setIdCard(empOjb.getIdCard());
empList.get(i).setfName(empOjb.getfName());
empList.get(i).setlName(empOjb.getlName());
empList.get(i).setEmail(empOjb.getEmail());
empList.get(i).setPhone(empOjb.getPhone());
result = "UPDATE IS SUCCESS.";
break;
} else {
result = "ID NOT FOUND";
}
}
} catch (Exception ex) {
System.out.println("ERROR MESSAG :" + ex.getMessage());
}
return result;
}
public String deleteEmployeetById(String id) {
String result = null;
try {
int empId = Integer.parseInt(id);
for (EmployeeBean emp : empList) {
if (empId == emp.getId()) {
empList.remove(emp);
result = "DEELETE ID:" + empId + " IS SUCCESS";
break;
} else {
result = "ID NOT FOUND ";
}
}
} catch (Exception ex) {
System.out.println("ERROR MESSAG :" + ex.getMessage());
result = "ERROR MESSAG :" + ex.getMessage();
}
return result;
}
}

ตัวอย่าง การสร้าง Rest

  1. สร้าง Class EmployeeController เพื่อใช้เป็นหน้ากากของ Rest โดยการเรียกใช้ Model CRUD ที่เราเตรียมไว้ข้างต้น
package com.controller;import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import com.bean.EmployeeBean;
import com.dao.EmployeeDao;
@Produces({ MediaType.APPLICATION_JSON })
@Consumes({ MediaType.APPLICATION_JSON })
@Path("/empservices")
public class EmployeeController {
EmployeeDao dao = new EmployeeDao();

@GET
@Path("{id}")
public Response getEmployeeId(@PathParam("id") String id){
EmployeeBean empBean = dao.selectEmployeetById(id);
return Response.status(Response.Status.OK).entity(empBean).build();
}
@GET
@Path("/all")
public Response getEmployeeAll(){
List<EmployeeBean> empList = dao.selectEmployeetAll();
return Response.status(Response.Status.OK).entity(empList).build();
}

@POST
@Path("/post")
public Response addEmployee(EmployeeBean emp){
EmployeeBean empBean = dao.insertEmployee(emp);
return Response.status(Response.Status.ACCEPTED).entity(empBean).build();
}

@PUT
@Path("/put")
public Response changEmployeeById(EmployeeBean emp){
String result = dao.updateEmployeetById(emp);
return Response.status(Response.Status.OK).entity(result).build();
}

@DELETE
@Path("{id}")
public Response removeEmployeeId(@PathParam("id") String id){
String result = dao.deleteEmployeetById(id);
return Response.status(Response.Status.OK).entity(result).build();
}
}

2. สร้าง Class RestApplication เพื่อใช้ Control path แล้วเรียก Class EmployeeController อีกทีนึง

package com.util;import java.util.HashSet;
import java.util.Set;
import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
import com.controller.EmployeeController;
@ApplicationPath("/*")
public class RestApplication extends Application {

public Set<Class<?>> getClasses() {
Set<Class<?>> classes = new HashSet<Class<?>>();
classes.add(EmployeeController.class);
return classes;
}
}

3. มาถึงการ config file web.xml ให้ไปที่ EmployeeWS >WebContent >WEB-INF >web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_ID" version="3.0"
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>EmployeeWS</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>EMPLOYEEWS</servlet-name>
<servlet-class>com.ibm.websphere.jaxrs.server.IBMRestServlet</servlet-class>
<init-param>
<param-name>javax.ws.rs.Application</param-name>
<param-value>com.util.RestApplication</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<enabled>true</enabled>
<async-supported>false</async-supported>
</servlet>
<servlet>
<display-name>Apache-Axis Servlet</display-name>
<servlet-name>AxisServlet</servlet-name>
<servlet-class>org.apache.axis.transport.http.AxisServlet</servlet-class>
<enabled>true</enabled>
<async-supported>false</async-supported>
</servlet>
<servlet>
<display-name>Axis Admin Servlet</display-name>
<servlet-name>AdminServlet</servlet-name>
<servlet-class>org.apache.axis.transport.http.AdminServlet</servlet-class>
<load-on-startup>100</load-on-startup>
<enabled>true</enabled>
<async-supported>false</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>EMPLOYEEWS</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/servlet/AxisServlet</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AxisServlet</servlet-name>
<url-pattern>/services/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>AdminServlet</servlet-name>
<url-pattern>/servlet/AdminServlet</url-pattern>
</servlet-mapping>
</web-app>

เสร็จเรียบร้อยแล้วจ้าาาา ต่อไปเรามาเริ่ม Test Rest ของเรากันค่ะ 👩🏻

Path ที่ใช้ในการ Test Rest
- Method GET = http://<Host>:<Port>/EmployeeWS/empservices/all
- Method GET = http://<Host>:<Port>/EmployeeWS/empservices/<id>
- Method POST = http://<Host>:<Port>/EmployeeWS/empservices/post
- Method PUT = http://<Host>:<Port>/EmployeeWS/empservices/put
- Method DELETE = http://<Host>:<Port>/EmployeeWS/empservices/<id>

เปิด Postman ขึ้นมาแล้วทำตามแต่ละ Case ตามรูปภาพได้เลยค่ะ

Test Rest Method Post

สำหรับ Method Post ให้ลองเปลี่ยน Reques แล้วยิงเล่นสัก 2–3 ครั้ง หรือกี่ครั้งก็ได้ จะสังเกตได้ว่า Respons ที่ได้มาจะมี File id เพิ่มขึ้นและมีการ GenerateId เริ่มต้นจาก 101 ซึ่งแปลได้ว่า File id คือ Primary key

ตัวอย่าง Request{
"idCard":"1440400111111",
"fName":"test",
"lName":"eiei",
"email":"test$@gmail.com",
"phone":"0855555555"
}
ตัวอย่างการ Test Method Post เพื่อใช้ในการเพิ่มข้อมูล

Test Rest API Method GET

ตัวอย่างการ Test Method Get เพื่อดูข้อมูลทั้งหมด
ตัวอย่างการ Test Method Get เพื่อดูข้อมูลของแต่ล่ะ id

Test Rest Method Put

ตัวอย่าง Request{
"id":101,
"idCard":"1440400111111",
"fName":"vip",
"lName":"eiei",
"email":"test$@gmail.com",
"phone":"0855555555"
}
ตัวอย่างการ Test Method Put เพื่อ update data กรณีค้นพบ id in data
ตัวอย่างการ Test Method Get เพื่อดูผลลัพธ์การ update data of method Put

Test Rest API Method Delete

จากตัวอย่าง เรามี Employee จำนวน 2 id เราจะมายกตัวอย่างกรณีค้นพบ id ส่วน กรณีที่ไม่ค้นพบ id ไปลองเล่นดูค่ะ เราเขียนโค้ด Support ไว้แล้ว เดี๋ยวย๊าววววว

ตัวอย่างการ Test Method Delete กรณีค้นพบ id

ตัวอย่าง การสร้าง Soap

  1. สร้าง Class EmployeeService เพื่อใช้เป็นหน้ากากของ Soap
package com.soap;import java.util.List;
import com.bean.EmployeeBean;
import com.dao.EmployeeDao;
public class EmployeeService {

public EmployeeBean getEmployeeId(String id){
EmployeeDao dao = new EmployeeDao();
EmployeeBean empBean = dao.selectEmployeetById(id);
return empBean;
}

public EmployeeBean[] getEmployeeAll(){
EmployeeDao dao = new EmployeeDao();
List<EmployeeBean> empList = dao.selectEmployeetAll();
return empList.toArray(new EmployeeBean[0]);
}

public EmployeeBean addEmployee(EmployeeBean emp){
EmployeeDao dao = new EmployeeDao();
EmployeeBean empBean = dao.insertEmployee(emp);
return empBean;
}

public String changEmployeeById(EmployeeBean emp){
EmployeeDao dao = new EmployeeDao();
String result = dao.updateEmployeetById(emp);
return result;
}

public String removeEmployeeId( String id){
EmployeeDao dao = new EmployeeDao();
String result = dao.deleteEmployeetById(id);
return result;
}
}

2. Click right at class EmployeeService >New >Other ทำตามรูปภาพไปเลยจ้า

ตัวอย่างการสร้าง Soap 2.1
ตัวอย่างการสร้าง Soap 2.2
ตัวอย่างการสร้าง Soap 2.3

3. Start server แล้วกด Finish ไปโลดดดด

ตัวอย่างการสร้าง Soap 2.4

4. สิ่งที่ได้จากการทำตามข้อ 2 และ ข้อ 3 จะเกิดไฟล์ใหม่ดังนี้

ตัวอย่างการสร้าง Soap 2.5 การเกิดไฟล์ใหม่

เสร็จเรียบร้อยแล้วจ้าาาา ต่อไปเรามาเริ่ม Test Soap ของเรากันค่ะ

Path ที่ใช้ในการ Test Soap
http://<Host>:<Port>/EmployeeWS/services

เปิด Browser ขึ้นมาสักตัว แล้วเอา Path ไปวางจะเห็นว่าใน Soap ของเรามี Service อะไรบ้าง

ภาพตัวอย่าง Services ทั้งหมด

มาถึงขั้นตอนนี้คงเห็นแล้วว่ามี Service อะไรใน Soap ของเราบ้าง ทุกคนคะเห็นคำว่า EmployeeService (wsdl) Click ตรงคำว่า (wsdl) ที่ขีดเส้นใต้ไว้เราจะเจอหน้าตาของ WSDL ดังนี้

ภาพตัวอย่าง หน้าตาของ WSDL

หลังจากที่เราได้ WSDL มาแล้วให้เอา Path ของ WSDL ลองไป Test ดู เปิด SoapUI ขึ้นมาโลด

ภาพตัวอย่าง icon SoapUI

Click menu Soap จะได้หน้าต่าง New Soap Project

  • Project Name: ใช้สำหรับตั้งชื่อ Project
  • Initial WSDL: ใช้สำหรับใส่ Path WSDL
http://<Host>:<Port>/EmployeeWS/services/EmployeeService?wsdl
ภาพตัวอย่าง การเรียกใช้ WSDL in soapUI

Click OK ไปโลดดดดดดดดดด….

จากรูปด้านล่างจะเห็นได้ว่าแต่ล่ะ Method ของ WSDL เรานั้นจะมีตัวอย่าง Request ทุกๆ Method เห็นหน้าต่าง Request1 ที่ปรากฎในรูปด่านล่างมั้ยคะ? ส่วน “?” ที่อยู่ใน Request นั้น คือ WSDL เค้าบอกว่าให้ใส่ Parameter อะไรบ้าง ? หู้ยยยยยทำไม Soap เค้าเจ๋งเบอร์นี้

ภาพตัวอย่าง หน้าตา WSDL in soapUI

*** เราจะไม่ยกตัวอย่างการ Test Soap ให้ดูนะคะ ลองไปเล่นดู เพราะว่า Soap เค้ามี WSDL เป็นหน้าเป็นตาอยู่แล้ว หลักการ Test ก็เหมือนๆ กับ Rest ที่ยกตัวอย่างไว้ข้างบนเลยค่ะ ต่างกันแค่ Rest return type is Json ส่วน Soap return type is XML

สรุป

สังเกตุได้ว่าเราจะมีการสร้าง Class เพื่อทำ CRUD แยกไว้เพื่อเก็บไว้เรียกใช้งาน
อยากสร้าง Rest ก็ทำหน้ากากให้ Rest แล้วไปเรียกใข้ Class, Method CRUD ที่เราเตรียมไว้แล้ว
อยากสร้าง Soap ก็ทำหน้ากากให้ Soap แล้วไปเรียกใช้ Class, Method CRUD ที่เราเตรียมไว้แล้ว
*** เค้าเรียกใช้ Class, Method เดียวกันค่ะ แค่หน้ากากของใครของมันมัน อารมณ์ประมาณแบบใช้บริการอะไรสักอย่างที่เดียวกัน! Something like that.

*** หมายเหตุ ถ้าใครใช้ server runtime is tomcat ต้องใช้ libraries jersey และเพิ่ม cinfig servlet-class ที่ web.xml

<servlet>
<servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
</servlet>
  • jersey-json-1.19.jar
  • jersey-core-1.19.jar

แต่เอ๊ะ! จะมีใครอ่านหรือลองทำจนจบมั้ยน๊าาา ถ้าทำตามแล้วติดอะไรสามารถคอมเม้นถามไว้ได้เลยค่ะเดี๋ยวมาตอบจ้า

ทั้งนี้ทั้งนั้นถ้าอธิบายผิด หรือไม่ถูก สามารถแนะนำได้เลยนะคะ 👩🏻

Source code ทั้งหมดhttps://gitlab.com/java59/employeews.git

--

--

No responses yet