REST(三)Restlet实现REST

Restlet项目为“建立REST概念与Java类之间的映射”提供了一个轻量级而全面的框架。它可用于实现任何种类的REST式系统,而不仅仅是REST式Web服务。
Restlet参考REST标准的术语,如:资源(resource)、表示(representation)、连接器(connector)、组件(component)、媒体类型(media type)、语言(language),等等。Restlet增加了一些专门的类(如Application、Filter、Finder、Router和Route),用以简化restlets的彼此结合,以及简化把收到的请求(incoming requests)映射为处理它们的资源。

其他Restlet介绍见:[url=http://sb33060418.iteye.com/blog/1340722]Restlet 入门[/url]。本节简单介绍restlet2+spring4的集成及客户端访问。

[b]1.spring web基础环境[/b]
见上一节Jersey创建的web工程testRest。

[b]2.REST地址[/b]
与上一节类似,设计restlet模块rest接口地址:
/restlet/teachers GET 获取所有资源
/restlet/teachers POST 创建新资源,content中包含资源内容
/restlet/teacher/{id} GET 获取编号为id的资源
/restlet/teacher/{id} PUT 更新编号为id的资源,content中包含资源内容
/restlet/teacher/{id} DELETE 删除编号为id的资源

[b]3.restlet库[/b]
在项目pom.xml中加入Restlet依赖:

<repositories>
<repository>
<id>maven-restlet</id>
<name>Restlet repository</name>
<url>https://maven.restlet.com</url>
</repository>
</repositories>
<properties>
<restlet.version>2.3.5</restlet.version>
<fastjson.version>1.2.7</fastjson.version>
</properties>
<dependencies>
...
<!-- restlet begin -->
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet</artifactId>
<version>${restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet.ext.json</artifactId>
<version>${restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet.ext.spring</artifactId>
<version>${restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet.ext.servlet</artifactId>
<version>${restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet.ext.xml</artifactId>
<version>${restlet.version}</version>
</dependency>
<dependency>
<groupId>org.restlet.jee</groupId>
<artifactId>org.restlet.ext.oauth</artifactId>
<version>${restlet.version}</version>
</dependency>
<!-- json 相关jar包 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<!-- restlet end -->
...

Restlet使用版本2.3.5,并加入servlet、spring、json、xml等包。因Restlet库不在中央仓库中,所以要加入https://maven.restlet.com仓库。

[b]4.Servlet[/b]
配置Restlet访问入口。

<!-- restlet -->
<servlet>
<servlet-name>restlet</servlet-name>
<servlet-class>org.restlet.ext.spring.SpringServerServlet</servlet-class>
<init-param>
<param-name>org.restlet.component</param-name>
<param-value>component</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>restlet</servlet-name>
<url-pattern>/restlet/*</url-pattern>
</servlet-mapping>

Restlet Servlet将拦截/restlet/*下的所有访问。
Restlet与web、spring集成后,不需要再自己实现Router、Application、Component。但需要在spring中进行配置。
在配置文件目录src\main\resources\下创建restlet配置目录config\restlet,并创建配置文件restlet.xml:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"
default-autowire="byName" default-lazy-init="true">

<bean id="component" class="org.restlet.ext.spring.SpringComponent">
<property name="defaultTarget" ref="router" />
</bean>
<bean id="router" class="org.restlet.ext.spring.SpringBeanRouter"></bean>

</beans>

此处定义的component bean将被web.xml配置的Restlet servlet引用。

[b]5.实现api[/b]
在com.sunbin.test.restlet新增TeachersResource类,以实现/teachers路径的接口:

package com.sunbin.test.restlet;

import java.util.HashMap;
import java.util.Map;

import org.restlet.data.Form;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSON;
import com.sunbin.test.teacher.pojo.Teacher;
import com.sunbin.test.teacher.service.TeacherService;

public class TeachersResource extends ServerResource {

@Autowired
private TeacherService teacherService;

@Get
public Representation get() {
System.out.println("Restlet TeachersResource.get");
Map map = new HashMap();
map.put("teachers", teacherService.list());
return new JsonRepresentation(JSON.toJSONString(map));
}

@Post("*:json")
public Representation post(Representation entity){
Map map = new HashMap();
try {
Form form = new Form(entity);
System.out.println("Restlet TeachersResource.post:"+form);
Teacher teacher = new Teacher();
teacher.setName(form.getFirstValue("name"));
teacher.setAge(Integer.parseInt(form.getFirstValue("age")));
teacherService.save(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new JsonRepresentation(JSON.toJSONString(map));
}
}

用到了以下Restlet自带注解:
@Get:GET请求的响应方法。
@Post("*:json"):POST请求的响应方法,指定*可接受各种Content-Type的请求数据,json可返回Content-Type:application/json数据。

需要注意的是,Restlet自带的json返回new JsonRepresentation(map)会对Map中的键值简单调用toString,再返回json串例如:{"teachers":["Teacher [id=1, age=1, name=a]","Teacher [id=2, age=2, name=b]"]},这就不是标准json了。所以干脆使用阿里的fastjson库先将结果转成JSONString,再返回:{"teachers":[{"age":1,"id":1,"name":"a"},{"age":2,"id":2,"name":"b"}]}。

新增TeacherResource类,以实现/teacher/{id}路径的接口:

package com.sunbin.test.restlet;


import java.util.HashMap;
import java.util.Map;


import org.restlet.data.Form;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.Delete;
import org.restlet.resource.Get;
import org.restlet.resource.Put;
import org.restlet.resource.ServerResource;
import org.springframework.beans.factory.annotation.Autowired;

import com.alibaba.fastjson.JSON;
import com.sunbin.test.teacher.pojo.Teacher;
import com.sunbin.test.teacher.service.TeacherService;

public class TeacherResource extends ServerResource{

@Autowired
private TeacherService teacherService;

@Get
public Representation get(){
String id = (String)getRequest().getAttributes().get("id");
System.out.println("Restlet TeacherResource.get:"+id);
Teacher teacher = new Teacher();
teacher.setId(Integer.parseInt(id));
Map map = new HashMap();
map.put("teacher", teacherService.get(teacher));
return new JsonRepresentation(JSON.toJSONString(map));
}

@Put
public Representation put(Representation entity){
Map map = new HashMap();
try {
String id = (String)getRequest().getAttributes().get("id");
Form form = new Form(entity);
System.out.println("Restlet TeacherResource.put:"+id+":"+form);
Teacher teacher = new Teacher();
teacher.setId(Integer.parseInt(id));
teacher.setName(form.getFirstValue("name"));
teacher.setAge(Integer.parseInt(form.getFirstValue("age")));
teacherService.update(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new JsonRepresentation(JSON.toJSONString(map));
}

@Delete
public Representation delete(){
Map map = new HashMap();
try {
String id = (String)getRequest().getAttributes().get("id");
System.out.println("Restlet TeacherResource.delete:"+id);
Teacher teacher = new Teacher();
teacher.setId(Integer.parseInt(id));
teacherService.remove(teacher);
map.put("status", "y");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return new JsonRepresentation(JSON.toJSONString(map));
}
}

同样使用的不是JAX-RS注解,而是Restlet自带注解(大小写不同)。

restlet的路径绑定需要配置在spring文件中。在restlet.xml中增加配置:

<bean name="/teacher/{id}" id="teacherResource"
class="com.sunbin.test.restlet.TeacherResource" scope="prototype">
</bean>
<bean name="/teachers" id="teachersResource"
class="com.sunbin.test.restlet.TeachersResource" scope="prototype">
</bean>


[b]6.js测试[/b]
使用上一节的测试页面src\main\webapp\rest\index.jsp进行测试:

...
<script type="text/javascript">
// 测试框架
//var restType = "jersey";
var restType = "restlet";
//var restType = "resteasy";
//var restType = "restCxf";
//var restType = "restMvc";
...

重新部署后,使用浏览器访问[url]http://localhost:8080/testRest/rest[/url],测试内容和jersey测试相同。

[b]7.RestletClient测试[/b]
Restlet提供Client库用于测试REST接口。
新建TestRestlet类,代码如下:

package com.sunbin.test.restlet;

import java.io.IOException;

import org.restlet.resource.ClientResource;
import org.restlet.resource.ResourceException;

public class TestRestlet {

public static final String URL_BASE = "http://localhost:8080/testRest/restlet/";

/**
* @param args
* @throws IOException
* @throws ResourceException
*/
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
String module = "teacher";
String url = "";
ClientResource client = null;
String entity = "";
String result = "";

url = URL_BASE + module + "s";
System.out.println("get\t " + url);
client = new ClientResource(url);
result = client.get().getText();
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("post\t " + url);
client = new ClientResource(url);
entity = "name=a&age=1";
result = client.post(entity).getText();
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("get\t " + url);
client = new ClientResource(url);
result = client.get().getText();
System.out.println(result);

url = URL_BASE + module + "/1";
System.out.println("get\t " + url);
client = new ClientResource(url);
result = client.get().getText();
System.out.println(result);

url = URL_BASE + module + "/1";
System.out.println("put\t " + url);
client = new ClientResource(url);
entity = "name=aa&age=11";
result = client.put(entity).getText();
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("get\t " + url);
client = new ClientResource(url);
result = client.get().getText();
System.out.println(result);

url = URL_BASE + module + "/1";
System.out.println("delete\t " + url);
client = new ClientResource(url);
result = client.delete().getText();
System.out.println(result);

url = URL_BASE + module + "s";
System.out.println("get\t " + url);
client = new ClientResource(url);
result = client.get().getText();
System.out.println(result);
}

}

测试结果与Jersey类似。

[b]8.部署至jboss[/b]
将Restlet Web工程部署至jboss,会因为jboss类加载配置导致无法启动。
需要修改jboss目录/modules/system/layers/base/sun/jdk/main下的module.xml文件:

<dependencies>
<system export="true">
<paths>
...
<path name="com/sun/net/httpserver"/>
...

加入httpserver配置行。

[b]9.Restlet访问session[/b]
Restlet不推荐在Resource中访问会话信息,因为这是违背REST的无状态设计的。
但如果需要在Resource中访问Session,可以按以下代码获取:

import org.restlet.Request;
import org.restlet.engine.adapter.HttpRequest;
import org.restlet.engine.adapter.ServerCall;
import org.restlet.ext.servlet.internal.ServletCall;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

...
Request request = getRequest();
if (request instanceof HttpRequest) {
final ServerCall httpCall = ((HttpRequest) request)
.getHttpCall();
if (httpCall instanceof ServletCall) {
HttpServletRequest httpServletRequest = ((ServletCall) httpCall)
.getRequest();
HttpSession session = httpServletRequest.getSession();
...
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值