RESTLET开发实例

1 前提

  由于近期工作的需要,要把RESTLET应用到项目中,于是在网上参考了一些资料的基础上,实践了一个关于RESTLET接口的小例子。

  Restlet的思想是:HTTP客户端与HTTP服务器之间的差别,对架构来说无所谓。一个软件应可以既充当Web客户端又充当Web服务器,而无须采用两套完全不同的APIs。

  Restlet提供了多个版本:Java SE、Java EE、android、Google AppEngine、Google Web Toolkit、Android。这里我们使用的是jee版本。

  RESTLET的实现可以采用JAX-RS方式,也可以采用其他方式,见:

http://www.iteye.com/topic/85928

本例子是采用JAX-RS的API开发的,这种方式提供了一种基于注解的模型来描述分布式资源,可以利用注解的功能提供资源的位置、传递等。可以在一个Resource类中同时对外提供多个rest接口服务。具体的实现步骤见如下章节。

2 实例开发

2.1 工程说明

       此处可以建立一个web工程,也可以建立一个JAVASE工程,如何应用就UP TO YOU了,此处的例子只是为了梳理下RESTLET的开发流程,不涉及到web界面的应用,所以就建立了一个普通的JAVASE的工程。工程的结构图如下:

 

       我们的工程分为如下几个部分:Server启动模块、Application模块、modle模块、REST接口实现的resource模块和客户端模块。

       工程所依赖的jar包,是最基本的这个6个包,因为数据的传输使用的JSON,所以json包是必须的,如果想扩展功能,请自行添加其余的包。

2.2 Server端启动部分

       RestJaxRsServer类的代码如下:

 1 package com.scott.restlet;
 2 
 3 import org.restlet.Component;
 4 import org.restlet.data.Protocol;
 5 
 6 import com.scott.restlet.application.RestJaxRsApplication;
 7 
 8 public class RestJaxRsServer {
 9     
10     public static void main(String[] args) throws Exception {
11         Component component = new Component();
12         component.getServers().add(Protocol.HTTP, 8082);
13         component.getDefaultHost().attach(new RestJaxRsApplication(null));
14         component.start();
15         
16         System.out.println("The restlet server started ...");
17     }
18 }

 

此代码中指定了我们的HTTP的绑定端口,地址就是本地默认的ip。另外,代码中有一个RestJaxRsApplication,这是每个Application能够管理一组restlet接口。

2.3 Application部分

       在application包中有两个类,一个是RestJaxRsApplication类,继承了org.restlet.ext.jaxrs.JaxRsApplication,作为运行类,用于初始化REST的运行环境,其代码如下:

 1 package com.scott.restlet.application;
 2 
 3 import org.restlet.Context;
 4 import org.restlet.ext.jaxrs.JaxRsApplication;
 5 
 6 
 7 public class RestJaxRsApplication extends JaxRsApplication {
 8 
 9     public RestJaxRsApplication(Context context) {
10         super(context);
11         this.add(new MyApplication());
12     }
13 
14 }

 

另外一个是MyApplication,作为应用类,继承了javax.ws.rs.core.Application,这里面绑定了我们的RESTLET的接口RESOURCE类,可以将多个资源绑定在HashSet中,代码如下:

 1 package com.scott.restlet.application;
 2 
 3 import java.util.HashSet;
 4 import java.util.Set;
 5 
 6 import javax.ws.rs.core.Application;
 7 
 8 import com.scott.restlet.resource.StudentResource;
 9 import com.scott.restlet.resource.TeacherResource;
10 
11 public class MyApplication extends Application {
12 
13     @Override
14     public Set<Class<?>> getClasses() {
15         Set<Class<?>> resources = new HashSet<Class<?>>();
16         
17         resources.add(StudentResource.class);
18         resources.add(TeacherResource.class);
19         
20         return resources;
21     }
22 
23 }

 

2.4 模型部分

       此实例的操作模型比较简单,就是一个Student类和一个Teacher类,代码如下:

Student

 1 package com.scott.restlet.modle;
 2 
 3 public class Student {
 4 
 5     private int id;
 6     private String name;
 7     private int sex;
 8     private int age;
 9     private int grade;
10 
11     public int getGrade() {
12         return grade;
13     }
14 
15     public void setGrade(int grade) {
16         this.grade = grade;
17     }
18 
19     public int getId() {
20         return id;
21     }
22 
23     public void setId(int id) {
24         this.id = id;
25     }
26 
27     public String getName() {
28         return name;
29     }
30 
31     public void setName(String name) {
32         this.name = name;
33     }
34 
35     public int getSex() {
36         return sex;
37     }
38 
39     public void setSex(int sex) {
40         this.sex = sex;
41     }
42 
43     public int getAge() {
44         return age;
45     }
46 
47     public void setAge(int age) {
48         this.age = age;
49     }
50 }

 

Teacher

 1 package com.scott.restlet.modle;
 2 
 3 public class Teacher {
 4     
 5     private int id;    
 6     private String name;
 7     private int sex;
 8     private int age;
 9     private String subject;
10     
11     public int getId() {
12         return id;
13     }
14     public void setId(int id) {
15         this.id = id;
16     }
17     public String getName() {
18         return name;
19     }
20     public void setName(String name) {
21         this.name = name;
22     }
23     public int getSex() {
24         return sex;
25     }
26     public void setSex(int sex) {
27         this.sex = sex;
28     }
29     public int getAge() {
30         return age;
31     }
32     public void setAge(int age) {
33         this.age = age;
34     }
35     public String getSubject() {
36         return subject;
37     }
38     public void setSubject(String subject) {
39         this.subject = subject;
40     }
41 }

 

2.5 RESOURCE部分

       这部分是我们的RESTLET接口实现部分,此处我们有两个接口实现类,一个是StudentResource,一个是TeacherResource,分别对外提供不同的REST接口服务。至于StorageOperator类,把它当做一个内存数据库好了,其实就是一个HashMap,StudentResource和TeacherResource的操作会在StorageOperator类中具体实现。代码如下:

StudentResource

 1 package com.scott.restlet.resource;
 2 
 3 import javax.ws.rs.DELETE;
 4 import javax.ws.rs.GET;
 5 import javax.ws.rs.POST;
 6 import javax.ws.rs.PUT;
 7 import javax.ws.rs.Path;
 8 import javax.ws.rs.PathParam;
 9 import javax.ws.rs.Produces;
10 
11 import org.restlet.data.Form;
12 import org.restlet.representation.Representation;
13 
14 import com.scott.restlet.modle.Student;
15 
16 @Path("/TestRestlet/student/")
17 public class StudentResource {
18 
19     @GET
20     @Path("{id}/json")
21     @Produces("application/json")
22     public Student getStudentJson(@PathParam("id") int id) {
23         return StorageOperator.findStudent(id);
24     }
25 
26     @POST
27     @Path("add")
28     public String addStudent(Representation entity) {
29         
30         //get parameters from client
31         Form form = new Form(entity);
32         String name = form.getFirstValue("name");
33         int grade = Integer.parseInt(form.getFirstValue("grade"));
34         int sex = Integer.parseInt(form.getFirstValue("sex"));
35         int age = Integer.parseInt(form.getFirstValue("age"));
36         
37         Student student = new Student();
38         student.setGrade(grade);
39         student.setName(name);
40         student.setSex(sex);
41         student.setAge(age);
42         
43         int id = StorageOperator.studentID + 1;
44         student.setId(id);
45         return String.valueOf(StorageOperator.addStudent(student));
46     }
47 
48     @PUT
49     @Path("update")
50     public String updateStudent(Representation entity) {
51         Form form = new Form(entity);
52 
53         int id = Integer.parseInt(form.getFirstValue("id"));
54         Student student = StorageOperator.findStudent(id);
55 
56         if (student == null) {
57             return "null";
58         }else{
59             String name = form.getFirstValue("name");
60             int grade = Integer.parseInt(form.getFirstValue("grade"));
61             int sex = Integer.parseInt(form.getFirstValue("sex"));
62             int age = Integer.parseInt(form.getFirstValue("age"));
63 
64             student.setGrade(grade);
65             student.setName(name);
66             student.setSex(sex);
67             student.setAge(age);
68 
69             return String.valueOf(StorageOperator.updateStudent(student));
70         }
71     }
72 
73     @DELETE
74     @Path("delete/{id}")
75     public String deleteStudent(@PathParam("id") int id) {
76         int status = StorageOperator.deleteStudent(id);
77         return String.valueOf(status);
78     }
79 
80 }

 

TeacherResource

 1 package com.scott.restlet.resource;
 2 
 3 import javax.ws.rs.DELETE;
 4 import javax.ws.rs.GET;
 5 import javax.ws.rs.POST;
 6 import javax.ws.rs.PUT;
 7 import javax.ws.rs.Path;
 8 import javax.ws.rs.PathParam;
 9 import javax.ws.rs.Produces;
10 
11 import org.restlet.data.Form;
12 import org.restlet.representation.Representation;
13 
14 import com.scott.restlet.modle.Teacher;
15 
16 @Path("/TestRestlet/teacher/")
17 public class TeacherResource {
18     @GET
19     @Path("{id}/json")
20     @Produces("application/json")
21     public Teacher getTeacherJson(@PathParam("id") int id) {
22         return StorageOperator.findTeacher(id);
23     }
24 
25     @POST
26     @Path("add")
27     public String addTeacher(Representation entity) {
28         
29         //get parameters from client
30         Form form = new Form(entity);
31         String name = form.getFirstValue("name");
32         String subject = form.getFirstValue("subject");
33         int sex = Integer.parseInt(form.getFirstValue("sex"));
34         int age = Integer.parseInt(form.getFirstValue("age"));
35         
36         Teacher teacher = new Teacher();
37         teacher.setSubject(subject);
38         teacher.setName(name);
39         teacher.setSex(sex);
40         teacher.setAge(age);
41         
42         int id = StorageOperator.teacherID + 1;
43         teacher.setId(id);
44         return String.valueOf(StorageOperator.addTeacher(teacher));
45     }
46 
47     @PUT
48     @Path("update")
49     public String updateTeacher(Representation entity) {
50         Form form = new Form(entity);
51 
52         int id = Integer.parseInt(form.getFirstValue("id"));
53         Teacher teacher = StorageOperator.findTeacher(id);
54 
55         if (teacher == null) {
56             return "null";
57         }else{
58             String name = form.getFirstValue("name");
59             String subject = form.getFirstValue("subject");
60             int sex = Integer.parseInt(form.getFirstValue("sex"));
61             int age = Integer.parseInt(form.getFirstValue("age"));
62 
63             teacher.setSubject(subject);
64             teacher.setName(name);
65             teacher.setSex(sex);
66             teacher.setAge(age);
67 
68             return String.valueOf(StorageOperator.updateTeacher(teacher));
69         }
70     }
71 
72     @DELETE
73     @Path("delete/{id}")
74     public String deleteTeacher(@PathParam("id") int id) {
75         int status = StorageOperator.deleteTeacher(id);
76         return String.valueOf(status);
77     }
78 }

StorageOperator

 1 package com.scott.restlet.resource;
 2 
 3 import java.util.HashMap;
 4 
 5 import com.scott.restlet.modle.Student;
 6 import com.scott.restlet.modle.Teacher;
 7 
 8 public class StorageOperator {
 9     public static int studentID = 1;
10     public static int teacherID = 1;
11     
12     public static HashMap<Integer, Student> students = new HashMap<Integer, Student>();
13     public static HashMap<Integer, Teacher> teachers = new HashMap<Integer, Teacher>();
14     
15     static {
16         Student student = new Student();
17         student.setId(1);
18         student.setGrade(3);
19         student.setName("Scott");
20         student.setSex(0);
21         student.setAge(18);
22         students.put(student.getId(), student);
23         
24         Teacher teacher = new Teacher();
25         teacher.setId(1);
26         teacher.setSubject("MATH");
27         teacher.setName("Toney");
28         teacher.setSex(1);
29         teacher.setAge(27);
30         teachers.put(teacher.getId(), teacher);
31     }
32 
33     public static Student findStudent(int id) {
34         return students.get(id);
35     }
36 
37     public static int addStudent(Student student) {
38         students.put(student.getId(), student);
39         return student.getId();
40     }
41 
42     public static int updateStudent(Student student) {
43         return addStudent(student);
44     }
45 
46     public static int deleteStudent(int id) {
47         if (students.get(id) != null) {
48             students.remove(id);
49             return 1;
50         }
51         return 0;
52     }
53     
54     public static Teacher findTeacher(int id) {
55         return teachers.get(id);
56     }
57 
58     public static int addTeacher(Teacher teacher) {
59         teachers.put(teacher.getId(), teacher);
60         return teacher.getId();
61     }
62 
63     public static int updateTeacher(Teacher teacher) {
64         return addTeacher(teacher);
65     }
66 
67     public static int deleteTeacher(int id) {
68         if (teachers.get(id) != null) {
69             teachers.remove(id);
70             return 1;
71         }
72         return 0;
73     }
74 
75 }

 

       在类的上面标注的PATH注解,作为全局的一个路径变量,方法上部的PATH注解都以类注解作为相对路径。并且,Produce表示返回的数据格式,此处是JSON类型。至于GET和POST,可以简单的理解为:

   POST   /uri     创建 

   DELETE /uri/xxx 删除

   PUT    /uri/xxx 更新或创建  

   GET    /uri/xxx 查看 

2.6 客户端部分

       客户端的访问REST接口,可以通过浏览器来输入url访问,也可以通过代码来访问,通过代码来访问的代码此处封装在了Client类中,代码如下:

StudentOperateClient

 1 package com.scott.restlet.client;
 2 
 3 import java.io.IOException;
 4 
 5 import org.restlet.data.Form;
 6 import org.restlet.resource.ClientResource;
 7 import org.restlet.resource.ResourceException;
 8 
 9 public class StudentOperateClient {
10     public static void testGetStudent(String url) {
11         ClientResource client = new ClientResource(url + "student/1/json");
12         try {
13             System.out.println("Student get " + client.get().getText());
14         } catch (ResourceException e) {
15             e.printStackTrace();
16         } catch (IOException e) {
17             e.printStackTrace();
18         }
19     }
20 
21     public static void testAddStudent(String url) {
22         ClientResource client = new ClientResource(url + "student/add");
23         try {
24             Form form = new Form();
25             form.add("name", "Scott007");
26             form.add("grade", "3");
27             form.add("sex", "0");
28             form.add("age", "15");
29             
30             String id = client.post(form.getWebRepresentation()).getText();
31             
32             System.out.println("Student add " + id);
33         } catch (Exception e) {
34             e.printStackTrace();
35         }
36     }
37 
38     public static void testUpdateStudent(String url) {
39         ClientResource client = new ClientResource(url + "student/update");
40         try {
41             Form form = new Form();
42             form.add("name", "Scott007");
43             form.add("grade", "4");
44             form.add("sex", "0");
45             form.add("id", "1");
46             form.add("age", "16");
47             
48             String id = client.put(form.getWebRepresentation()).getText();
49             
50             System.out.println("Student update " + id);
51         } catch (Exception e) {
52             e.printStackTrace();
53         }
54     }
55 
56     public static void testDeleteStudent(String url) {
57         ClientResource client = new ClientResource(url + "student/delete/1");
58         try {
59             System.out.println("Student delete " + client.delete().getText());
60         } catch (ResourceException e) {
61             e.printStackTrace();
62         } catch (IOException e) {
63             e.printStackTrace();
64         }
65     }
66 }

 

TeacherOperateClient

 1 package com.scott.restlet.client;
 2 
 3 import java.io.IOException;
 4 
 5 import org.restlet.data.Form;
 6 import org.restlet.resource.ClientResource;
 7 import org.restlet.resource.ResourceException;
 8 
 9 public class TeacherOperateClient {
10     public static void testGetTeacher(String url) {
11         ClientResource client = new ClientResource(url + "teacher/1/json");
12         try {
13             System.out.println("Teacher get " + client.get().getText());
14         } catch (ResourceException e) {
15             e.printStackTrace();
16         } catch (IOException e) {
17             e.printStackTrace();
18         }
19     }
20 
21     public static void testAddTeacher(String url) {
22         ClientResource client = new ClientResource(url + "teacher/add");
23         try {
24             Form form = new Form();
25             
26             form.add("name", "Scott008");
27             form.add("subject", "MATH");
28             form.add("sex", "0");
29             form.add("age", "27");
30             
31             String id = client.post(form.getWebRepresentation()).getText();
32             
33             System.out.println("Teacher add " + id);
34         } catch (Exception e) {
35             e.printStackTrace();
36         }
37     }
38 
39     public static void testUpdateTeacher(String url) {
40         ClientResource client = new ClientResource(url + "teacher/update");
41         try {
42             Form form = new Form();
43             
44             form.add("age", "28");
45             form.add("name", "Scott008");
46             form.add("subject", "English");
47             form.add("sex", "0");
48             form.add("id", "1");
49             
50             String id = client.put(form.getWebRepresentation()).getText();
51             System.out.println("Teacher update " + id);
52 
53         } catch (Exception e) {
54             e.printStackTrace();
55         }
56     }
57 
58     public static void testDeleteTeacher(String url) {
59         ClientResource client = new ClientResource(url + "teacher/delete/1");
60         try {
61             System.out.println("Teacher delete " + client.delete().getText());
62         } catch (ResourceException e) {
63             e.printStackTrace();
64         } catch (IOException e) {
65             e.printStackTrace();
66         }
67     }
68 }

 

Client

 1 package com.scott.restlet.client;
 2 
 3 public class Client {
 4 
 5     public static final String url = "http://localhost:8082/TestRestlet/";
 6 
 7     public static void main(String args[]){
 8         
 9         StudentOperateClient.testGetStudent(url);
10         StudentOperateClient.testUpdateStudent(url);
11         
12         TeacherOperateClient.testGetTeacher(url);
13         TeacherOperateClient.testUpdateTeacher(url);
14     }
15 }

 

2.7 运行

       运行,得到如下结果:

服务端启动后:

2013-9-3 23:22:51 org.restlet.engine.http.connector.HttpServerHelper start
信息: Starting the internal HTTP server on port 8082
The restlet server started ...

客户端启动后的客户端信息:

2013-9-3 23:24:12 org.restlet.engine.http.connector.HttpClientHelper start
信息: Starting the default HTTP client
Student get {"id":1,"sex":0,"age":18,"name":"Scott","grade":3}
2013-9-3 23:24:12 org.restlet.engine.http.connector.HttpClientHelper start
信息: Starting the default HTTP client
Student update 1
2013-9-3 23:24:12 org.restlet.engine.http.connector.HttpClientHelper start
信息: Starting the default HTTP client
Teacher get {"id":1,"sex":1,"subject":"MATH","age":27,"name":"Toney"}
2013-9-3 23:24:12 org.restlet.engine.http.connector.HttpClientHelper start
信息: Starting the default HTTP client
Teacher update 1

 

客户端启动的服务端信息:

2013-9-3 23:22:51 org.restlet.engine.http.connector.HttpServerHelper start
信息: Starting the internal HTTP server on port 8082
The restlet server started ...
2013-9-3 23:24:12 org.restlet.engine.log.LogFilter afterHandle
信息: 2013-09-03    23:24:12    127.0.0.1    -    -    8082    GET    /TestRestlet/student/1/json    -    200    -    0    70    http://localhost:8082    Restlet-Framework/2.0.6    -
2013-9-3 23:24:12 org.restlet.engine.log.LogFilter afterHandle
信息: 2013-09-03    23:24:12    127.0.0.1    -    -    8082    PUT    /TestRestlet/student/update    -    200    1    39    4    http://localhost:8082    Restlet-Framework/2.0.6    -
2013-9-3 23:24:12 org.restlet.engine.log.LogFilter afterHandle
信息: 2013-09-03    23:24:12    127.0.0.1    -    -    8082    GET    /TestRestlet/teacher/1/json    -    200    -    0    1    http://localhost:8082    Restlet-Framework/2.0.6    -
2013-9-3 23:24:13 org.restlet.engine.log.LogFilter afterHandle
信息: 2013-09-03    23:24:13    127.0.0.1    -    -    8082    PUT    /TestRestlet/teacher/update    -    200    1    47    2    http://localhost:8082    Restlet-Framework/2.0.6    -

 

当然,此处的例子规模和功能都很小,是在参考了[2]的基础上稍加改造,算是可以作为学习RESTLET的第一步吧。

3 一些可参考的网址

[1]http://whui0110.iteye.com/blog/1682388

[2]http://www.infoq.com/cn/articles/rest-introduction

[3]http://www.lifeba.org/arch/restlet_develop_jax-rs_service_1.html

posted @ 2013-09-03 23:27  Scott007  阅读(12298)  评论(1编辑  收藏  举报