2013年9月23日星期一

JDev_043:使用Jersey 实现CRUD

开发运行环境:JDeveloper 11.1.2.4

一直对Restful风格的Web Service很感兴趣,正好项目中需要把一个服务包装成Restful服务,就尝试做了一把CRUD。
Restful服务的设计理念:服务的设计以系统资源为中心,而不是以服务的功能为中心。

(1)GET 用来获取集合资源或单个资源。
比如:GET http://www.store.com/products 获取所有商品;
GET http://www.store.com/products/ 呈现指定的某件商品
(2)POST 用来创建一个新资源。
比如:POST http://www.store.com/products 增加一个新商品。
注意,这里不能用型如 http://www.store.com/products/的URI,因为此时新的product_id还没产生呢。
(3)PUT 用来修改集合资源或单个资源。
比如:PUT http://www.store.com/products 修改所有商品;
PUT http://www.store.com/products/ 修改指定的某件商品。
(4)DELETE 用来删除集合资源或单个资源,与PUT的URI一样。
(5)GET、PUT 和 DELETE 方法是幂等的,POST方法则不是。

1. Employee.java
一个很简单的Java Bean,即有些人常说的Data Object,代码从略。

2. EmployeeServcie.java
所有操作Employee Data Object的服务都在这里,即有些人常说的Service Object,代码如下:
package restfulservice;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;

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.QueryParam;
import javax.ws.rs.core.MediaType;

import javax.ws.rs.core.Response;

@Path("/employees")
public class EmployeeService {

    private ArrayList employees = new ArrayList();

    public EmployeeService() {
        super();
        employees.add(new Employee(3, "test3", 10, 100));
        employees.add(new Employee(6, "test6", 10, 100));
        employees.add(new Employee(9, "test9", 10, 100));
    }

    @POST
    @Consumes( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Response createEmployee(Employee emp) {
        employees.add(emp);
        return Response.ok(emp).build();
    }


    @PUT
    @Path("{employeeId}")
    @Consumes( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Response upadteEmployee(@PathParam("employeeId")
        int employeeId, Employee emp) {
        deleteEmployeeByPathParam(employeeId);
        createEmployee(emp);
        return Response.ok(emp).build();
    }

    @PUT
    @Consumes( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Response upadteEmployees(Employee[] emps) {
        deleteEmployees();
        employees.addAll(Arrays.asList(emps));
        return Response.ok(emps).build();
    }

    @DELETE
    @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Response deleteEmployeeByQueryParam(@QueryParam("employeeId")
        int employeeId) {
        Employee emp = getEmployee(employeeId);
        employees.remove(emp);
        return Response.ok(emp).build();
    }

    @DELETE
    @Path("{employeeId}")
    @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Response deleteEmployeeByPathParam(@PathParam("employeeId")
        int employeeId) {
        Employee emp = getEmployee(employeeId);
        employees.remove(emp);
        return Response.ok(emp).build();
    }

    @DELETE
    public void deleteEmployees() {
        employees.clear();
    }

    @GET
    @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public ArrayList getEmployees() {
        return employees;
    }

    @GET
    @Path("{employeeId}")
    @Produces( { MediaType.APPLICATION_XML, MediaType.APPLICATION_JSON })
    public Employee getEmployee(@PathParam("employeeId")
        int employeeId) {
        Iterator iter = employees.iterator();
        while (iter.hasNext()) {
            Employee emp = (Employee)iter.next();
            if ((emp.getId()) == employeeId) {
                return emp;
            }
        }
        return null;
    }
}

3. EmployeeClient.java
调用Restful服务的客户端,我还是费了些功夫的,注意CRUD的调用方式各有不同:

package restfulclient;


import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.WebResource;
import com.sun.jersey.api.client.filter.LoggingFilter;

import javax.ws.rs.core.MediaType;

public class EmployeeClient {
    public EmployeeClient() {
        super();
    }

    private final static String restfulUrl = "http://localhost:7101/RestfulSample/jersey/employees";

    public static void main(String[] args) {
        System.out.println("\n***************************************** POST ****************************************");
        Client client_post = Client.create();
        WebResource resource_post = client_post.resource(restfulUrl);
        resource_post.addFilter(new LoggingFilter());
        String response_post = resource_post.type(MediaType.APPLICATION_XML).post(String.class, buildPostXml());

        System.out.println("\n***************************************** PUT ONE ****************************************");
        Client client_putOne = Client.create();
        WebResource resource_putOne = client_putOne.resource(restfulUrl + "/1");
        resource_putOne.addFilter(new LoggingFilter());
        String response_putOne = resource_putOne.type(MediaType.APPLICATION_XML).put(String.class, buildPutXml());


        System.out.println("\n******************************* DELETE ONE BY QUERY PARAMETER *********************************");
        Client client_deleteOne = Client.create();
        WebResource resource_deleteOne = client_deleteOne.resource(restfulUrl + "?employeeId=3");
        resource_deleteOne.addFilter(new LoggingFilter());
        resource_deleteOne.delete();
     
        System.out.println("\n********************************** DELETE ONE BY PATH PARAMETER ******************************");
        Client client_deleteOne2 = Client.create();
        WebResource resource_deleteOne2 = client_deleteOne2.resource(restfulUrl + "/6");
        resource_deleteOne2.addFilter(new LoggingFilter());
        String response_deleteOne2 = resource_deleteOne2.type(MediaType.APPLICATION_XML).delete(String.class);

        System.out.println("\n***************************************** GET ALL ****************************************");
        Client client_getAll = Client.create();
        WebResource resource_getAll = client_getAll.resource(restfulUrl);
        resource_getAll.addFilter(new LoggingFilter());
        resource_getAll.get(String.class);
        resource_getAll.accept(MediaType.APPLICATION_JSON).get(String.class);

        System.out.println("\n***************************************** GET ONE ****************************************");

        Client client_getOne = Client.create();
        WebResource resource_getOne = client_getOne.resource(restfulUrl + "/9");
        resource_getOne.addFilter(new LoggingFilter());
        resource_getOne.get(String.class);
        resource_getOne.accept(MediaType.APPLICATION_JSON).get(String.class);

        System.out.println("\n***************************************** PUT ALL ****************************************");
        Client client_putAll = Client.create();
        WebResource resource_putAll = client_putAll.resource(restfulUrl);
        resource_putAll.addFilter(new LoggingFilter());
        String response_putAll = resource_putAll.type(MediaType.APPLICATION_XML).put(String.class, buildPutsXml());

        System.out.println("\n***************************************** DELETE ALL ****************************************");
        Client client_deleteAll = Client.create();
        WebResource resource_deleteAll = client_deleteAll.resource(restfulUrl);
        resource_deleteAll.addFilter(new LoggingFilter());
        resource_deleteAll.delete();    
    }

    private static String buildPostXml() {
        StringBuffer xml = new StringBuffer("\n");
        xml.append("1\n");
        xml.append("test1\n");
        xml.append("10\n");
        xml.append("100\n");
        xml.append("\n");     
        return xml.toString();
    }

    private static String buildPutXml() {
        StringBuffer xml = new StringBuffer("\n");
        xml.append("1\n");
        xml.append("test1\n");
        xml.append("11\n");
        xml.append("111\n");
        xml.append("\n");     
        return xml.toString();
    }

    private static String buildPutsXml() {
        StringBuffer xml = new StringBuffer("\n");
        xml.append("\n");
        xml.append("2\n");
        xml.append("test2\n");
        xml.append("10\n");
        xml.append("100\n");
        xml.append("\n");
        xml.append("\n");
        xml.append("3\n");
        xml.append("test3\n");
        xml.append("10\n");
        xml.append("100\n");
        xml.append("\n");     
        xml.append("\n");     
        return xml.toString();
    }
}

4. 修改web.xml,增加com.sun.jersey.config.feature.Formatted参数,这样输出的XML内容是格式化的。

<servlet>
    <servlet-name>jersey</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.feature.Formatted</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

Project 下载:RestfulSample.7z

最后再多说一句,什么时候用SOAP Web Service,什么时候用Restful Service?
简单来说,面向资源的服务使用Restful Web Service,面向功能的使用SOAP Web Service。
即如果想本例一样,都是对员工的CRUD,可以使用Restful Web Service;如果还有其它的操作,比如入职、离职,升迁,调岗等等,应该使用SOAP Web Service。

参考文献:
1. http://stackoverflow.com/questions/630453/put-vs-post-in-rest
2. http://zh.wikipedia.org/wiki/REST
3. http://www.infoq.com/cn/articles/understanding-restful-style?utm_source=infoq&utm_medium=popular_links_homepage
4. http://blog.csdn.net/zouzhile/article/details/5017347
5. http://www.restapitutorial.com/httpstatuscodes.html

没有评论: