You are browsing the archive for 2008 10月.

通过ADF Data Control 发布RESTFul 服务的资源

9:03 am in Oracle 融合中间件 by aronezhang

 

 

前面2篇文章我们跟随Lucas一起基于RESTLet开发了Restful的Web服务,其中的数据使用的是静态的数据,这样的情景在实际的应用中比较少见,

一般都是通过Business Service层来隐藏数据库的持久层和Web服务,以更清晰的层次来发布资源。

 

下面我们使用ADF Model中的Data Control & Data Bindings功能来实现一个业务服务层(Business Service),

通过创建一个:Placeholder Data Control来实现,首先创建一个Note的数据类型,然后通过Placeholder Data Control来发布一个Note对象的集合。

 

应用中通过BindingContainer才能使用Data Control,BindingContainer负责进行应用程序和数据集合(collections)、数据操作(operations)之间的连接,

这样的连接称为数据绑定(Data Bindings),基于使用这些集合的方式,我们可以使用各种类型的数据绑定,

如:表格,列表和树。BindingContainer通常被页面绑定配置文件PageDefinition文件初始化,页面绑定配置文件包括了数据绑定的配置信息。

 

创建 placeholder data control

路径:Business Tier –> Placeholder Data Control

 

9.placeholder_data_control

 

创建完ResourceDataPlaceHolder之后,从Data Controls属性窗口的上下文菜单中选择Create Placeholder Data Type

在创建Placeholder Data Type窗口中指定数据类型名称:Note;以及数据类型的属性:name, description, creationDate,切换到Sample Data标签页,输入静态的样例数据

 

10.create_placeholder_data_type

 

11.create_placeholder_data_type_data

 

创建完成之后,Data Control显示如下图:

12.data_control

 

打开我们在第一篇文章中创建的restful.jsp页面,从Data Control面板中拖动Note到页面上,然后选择创建一个Table组件,

创建完成之后会生成一个页面绑定文件叫做restfulPageDef.xml,它就是BindingContainer的设计时的配置文件,

它创建了一个基于ResourceDataPlaceHolder数据集合的迭代器,然后绑定到了一个Table来访问Data Control的数据,代码如下:

 

1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8" ?>
 
 
 
 
 
 
    <table id="Note"><tbody></tbody></table>

 

在DataBindings.cpx的文件中对页面绑定配置文件PageDefinition的定义:

 

1
 

 

配置ADF Binding Filter

 

上面通过拖拽来定义JSP页面,JDeveloper在web.xml文件中自动配置了ADF Binding Filter,过滤器会在web应用和BindingContainers交互之前初始化ADF Binding Context,

然而默认创建的是只处理*.jsp 和 *.jspx的相关请求,因此需要修改为*来处理RESTful服务的任何请求,修改URL匹配模式为:

 

1
2
3
4
        ADFBindingFilter
        *
        FORWARD
        REQUEST

 

 

使我们的应用能够访问Note table binding

 

如果在应用中我们需要在多个地方访问Note 表格绑定,那我们需要在一个集中的地方去处理获得表格的绑定,因此将这个方法放到我们的控制类RestfulAppliction中,

这个方法首先得到ADF的上下文ADFContext,绑定上下文BindingContext,然后从绑定容器BindingContainer中获得table binding

 

1
2
3
4
5
6
7
8
9
10
11
12
public static JUCtrlRangeBinding getNotesTableBinding() {
            ADFContext ctx = ADFContext.getCurrent();
            OracleExpressionEvaluatorImpl elev =
                (OracleExpressionEvaluatorImpl)ctx.getExpressionEvaluator();
            HttpBindingContext data = (HttpBindingContext)elev.evaluate(&quot;${data}&quot;);
            DCBindingContainer bc =
                data.findBindingContainer(&quot;com_oracleseeker_demo_restfulPageDef&quot;);
            bc.refresh(DCBindingContainer.PREPARE_MODEL);
            JUCtrlRangeBinding tableBinding =
                (JUCtrlRangeBinding)bc.findNamedObject(&quot;Note&quot;);
            return tableBinding;
        }

 

 

从ADF Data Control中发布Notes资源

 

我们必须在资源类NotesResource中实现represent()方法来处理GET请求,然后返回数据。

 

添加类的私有变量:notesTableBinding

添加代码到构造函数中:

1
notesTableBinding= RestfulApplication.getNotesTableBinding();

 

 

在represent()方法中循环处理TableBinding返回的数据

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
    @Override
    public Representation represent(Variant variant) throws ResourceException {
        if (MediaType.TEXT_XML.equals(variant.getMediaType())) {
            try {
                DomRepresentation representation =
                    new DomRepresentation(MediaType.TEXT_XML);
                Document doc = representation.getDocument();
                Element root = doc.createElement(&quot;notes&quot;);
                doc.appendChild(root);
                RowIterator ri = notesTableBinding.getRowIterator();                    
                ri.reset();                    
                Row[] rows  = ri.getAllRowsInRange();
 
                for (Row row : rows) {
                    Element eltNote = doc.createElement(&quot;note&quot;);
 
                    Element eltName = doc.createElement(&quot;name&quot;);
                    eltName.appendChild(doc.createTextNode((String)row.getAttribute(&quot;name&quot;)));
                    eltNote.appendChild(eltName);
 
                    Element eltDescription = doc.createElement(&quot;description&quot;);
                    eltDescription.appendChild(doc.createTextNode((String)row.getAttribute(&quot;description&quot;)));
                    eltNote.appendChild(eltDescription);
 
                    Element eltCreationDate =
                        doc.createElement(&quot;creationDate&quot;);
                    eltCreationDate.appendChild(doc.createTextNode(((oracle.jbo.domain.Date)row.getAttribute(&quot;creationDate&quot;)).toString()));
                    eltNote.appendChild(eltCreationDate);
                    root.appendChild(eltNote);
                }
                doc.normalizeDocument();
                return representation;
 
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

 

 

运行restful.jsp,修改URL指向资源/notes,运行如下的结果:

 

13.notes_xml_date

 

 

 

添加开始行和最大行的功能

 

 

一般在应用中调用Web服务都会进行分页,因此就会有一个页面显示数据多少行到多少行,

因此我们的URL看起来像是这样的:http://host:port/webapp/notes?start=26&maxRows=25

添加两个私有变量到资源类NotesResource中

 

1
2
    int startRow = 0;
    int maxRows = -1;

 

在类的构造函数中获取请求URL中的开始行和最大行参数的值

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
        String startRowParam =
            request.getResourceRef().getQueryAsForm().getFirstValue(&quot;start&quot;);
        if (startRowParam != null) {
            startRow = Integer.parseInt(startRowParam);
        } else {
            startRow = 0;
        }
        String maxRowsParam =
            request.getResourceRef().getQueryAsForm().getFirstValue(&quot;maxRows&quot;);
        if (maxRowsParam != null) {
            maxRows = Integer.parseInt(maxRowsParam);
        } else {
            maxRows = -1;
        }

 

在represent()方法中加入限制

 

1
2
3
ri.reset();
ri.setRangeSize(maxRows);
ri.setRangeStart(startRow);

 

在URL中添加参数:http://127.0.0.1:7101/oracleseeker-restful/notes?maxRows=2&start=1 运行结果:

14.notes_xml_maxrow_data

 

 

上面三篇文章使用RestLet开源库来创建Restful 服务,同时利用JDeveloper 11g的新特性来发布数据。

 

资源链接

 

Publishing resources exposed by ADF Data Control in RESTful services using RestLet and JDeveloper 11g by Lucas Jellema

http://technology.amis.nl/blog/3600/publishing-resources-exposed-by-adf-data-control-in-restful-services-using-restlet-and-jdeveloper-11g

 

下载本文的JDeveloper 11g应用Download BIP报表中格式化币种金额 Version 1

 

 

 

扩展RestLet应用来创建和更新资源

1:06 am in Oracle 融合中间件 by aronezhang

 

 

上一篇博文中学习了RestLet如何使用它在JDevloper 11g中创建一个简单的Restful服务,它只支持只读操作:GET请求,下面将添加创建和更改Note的功能。

 

一、创建新的资源

 

 

创建一个客户端页面来创建Notes

 

创建是通过HTTP请求的POST来实现,我们需要设计一个HTML页面来提交给我们的RESTful服务的资源链接URL,提交的页面包括了我们需要创建Note的相关数据,Restful服务将接收提交的请求,NotesResource资源类将接收Post请求,将其发送给/notes服务来创建一个Note。

需要保证这个页面不在我们的项目下,否则由于web.xml配置过滤无法运行,因此可以在任何其他目录下创建此静态HTML页面,如test.html 。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<form name="NoteCreator" action="http://127.0.0.1:7101/oracleseeker-restful/notes" method="post">
  <table cellspacing="2" cellpadding="3" width="100%" border="1">
    <tbody>
      <tr>
        <td width="28%">Name</td>
        <td width="72%"> </td>
      </tr><tr><td width="28%">Description</td>
        <td width="72%"> </td>
      </tr>
     </tbody>
    </table>
 
</form>

 

HTML静态页面的主要功能是提交一个表单执行一个POST方法,将表单数据发送给Notes服务

 

添加POST处理逻辑到NotesResource资源类中

 

首先需要在资源类NotesResource类的构造函数中设置属性,让资源类能够接受POST请求来修改资源

 

1
2
// Allow modifications of this resource via POST requests.   
setModifiable(true);

 

然后重载Resource类的acceptRepresentation方法,这个方法监控请求的内容,获取创建资源所需的信息,然后创建资源,将其添加到收集器中

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    @Override
    public void acceptRepresentation(Representation entity) throws ResourceException {
        Form form = new Form(entity);
        String name = form.getFirstValue(&quot;name&quot;);
        String description = form.getFirstValue(&quot;description&quot;);
 
        getNotes().add(new Note(name, description, new Date()));
 
        // Set the response's status and entity
        getResponse().setStatus(Status.SUCCESS_CREATED);
        Representation rep =  new StringRepresentation(&quot;Note created&quot;, MediaType.TEXT_PLAIN);
        // Indicates where is located the new resource.        
        rep.setIdentifier(getRequest().getResourceRef().getIdentifier() + &quot;/&quot; + name);        
        getResponse().setEntity(rep);
    }

 

创建Note资源

 

运行restful.jsp页面用来发布Web服务到WebLogic,然后运行静态HTML文件

4.create_note

输入Note信息,点击Create按钮,然后会弹出一个窗口显示创建成功的消息。

 

修改URL,检测Note创建是否成功

5.create_complete 

 

 

二、更新现有的资源

 

要POST请求能够支持更新现有资源的功能,只要修改NotesResource资源来,根据请求的URL参数来进行资源定位并进行更新就可以了。

 

在资源类NotesResource类的构造函数中设置可修改资源,并获取URL中的资源参数

 

1
2
3
setModifiable(true); 
String noteName = (String)getRequest().getAttributes().get(&quot;noteName&quot;);
note = getTheNote(noteName);

 

重载acceptRepresentation() 方法,在方法中定位资源,并进行修改,如果没有找到资源,返回提示信息

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    @Override
    public void acceptRepresentation(Representation entity) throws ResourceException {
        Form form = new Form(entity);
        Representation rep = null;
        if(note != null){
            String description = form.getFirstValue(&quot;description&quot;);            
            note.setDescription(description);            
            getResponse().setStatus(Status.SUCCESS_CREATED);            
            rep = new StringRepresentation(&quot;Note updated&quot;, MediaType.TEXT_PLAIN);            
            rep.setIdentifier(getRequest().getResourceRef().getIdentifier() + &quot;/&quot; + note.getName());
        }
        else{
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);                        
            rep = new StringRepresentation(&quot;Note could not be found&quot;, MediaType.TEXT_PLAIN);
        }
        getResponse().setEntity(rep);
    }

 

根据URL中的参数,找到资源,并对资源中的描述进行修改

 

修改HTML静态页面test.html ,添加Update按钮来提交资源的更新,如下列代码:

 

1
 

 

 

更新资源展示

 

还是和之前一样,先运行restful.jsp页面,再运行静态HTML文件

 

8.update_form

 

更新之后会有成功的消息返回。

6.update_success

 

 

输入URL检测更新是否成功

7.update_complete

 

应用扩展结束!

 

 

三、资源和链接

 

Extending the RestLet application with support for POST/PUT to create and update Resources by Lucas Jellema

http://technology.amis.nl/blog/3592/extending-the-restlet-application-with-support-for-postput-to-create-and-update-resources

 

下载本文的JDeveloper 11g应用:Download 扩展RestLet应用来创建和更新资源 Version 1

 

 

JDeveloper 11g中利用RestLet开发RESTful服务

2:14 am in Oracle 融合中间件 by aronezhang

 

 

Oracle JDeveloper11g发布之后,Oracle的Guru们也纷纷在她们的Blog中发布各种应用和特性的介绍,这不Lucas Jellema在AMIS的blog中就介绍了使用JDeveloper 11g来开发基于Restlet的RESTFul服务。

我也照葫芦画瓢学习了一下,开始步入REST架构的学习大潮中。

 

随着JCP关于REST网络服务的规范标准JAX-RS: Java API for RESTful Web Services (JSR 311)最终版的尘埃落定,REST设计风格的Web服务应用也得到了进一步的应用与推广,很多流行的架构也宣称在未来的版本中将支持REST架构,如大名鼎鼎的Spring宣称在未来3.0版本中全面支持REST;同时很多Web服务开始采用REST风格设计和实现,例如Amazon,Google和Yahoo都提供了REST风格的Web查询服务。

 

本文就是将围绕Restlet来实现一个RESTFul的web服务

 

 

1,JDeveloper11g下创建一个项目

2,使用默认的配置创建一个JSP页面,将其命名为restful.jsp

3,添加库文件:下载Restlet压缩包,从lib目录中挑选com.noelios.restlet.ext.servlet_2.5.jar, com.noelios.restlet.jar, org.restlet.jar,将它们添加到刚创建的项目库和Classpath中

1.add_restlet_jar

 

4,创建Rest应用控制类

在Java包com.oracleseeker.rest.controller中创建RestApplication类,这个类用来设置各种资源和URI,开始设置一个资源(notes)和一个URL(/notes)映射到这个资源,类中也初始化Note对象。

因此后面进一步向类中添加路由限制来对资源的获取进行限制,路由通过模式匹配的方式来支持。

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
package com.oracleseeker.rest.controller;
 
import com.oracleseeker.rest.resources.Note;
import com.oracleseeker.rest.resources.NotesResource;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import org.restlet.Application;
import org.restlet.Restlet;
import org.restlet.Router;
 
public class RestfulApplication extends Application {
 
    private Collection notes = new ArrayList();
 
    public RestfulApplication() {
        notes.add(new Note(&quot;appointment&quot;,&quot;Keyuan Road&quot;,new Date()));
        notes.add(new Note(&quot;conference&quot;,&quot;Zhangheng Road&quot;,new Date()));
        notes.add(new Note(&quot;training&quot;,&quot;Zhonghuan Road&quot;,new Date()));
    }
 
 
    @Override
    public Restlet createRoot() {
        Router router = new Router(getContext());
        router.attach(&quot;/notes&quot;, NotesResource.class);       
        return router;
    }
 
 
    public void setNotes(Collection notes) {
        this.notes = notes;
    }
 
    public Collection getNotes() {
        return notes;
    }
}

 

5,定义实体类Note

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.oracleseeker.rest.resources;
 
import java.util.Date;
 
public class Note {
    private String name;
    private String description;
    private Date creationDate;
 
    public Note() {
    }
 
    public Note(String name, String description, Date creationDate) {
        super();
        this.name = name;
        this.description = description;
        this.creationDate = creationDate;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getName() {
        return name;
    }
 
    public void setDescription(String description) {
        this.description = description;
    }
 
    public String getDescription() {
        return description;
    }
 
    public void setCreationDate(Date creationDate) {
        this.creationDate = creationDate;
    }
 
    public Date getCreationDate() {
        return creationDate;
    }
}

 

6,定义资源类NoteResource

它用来提供REST架构中的资源,任何通过HTTP的请求要获得REST的资源最终都需要通过它来提供,而对资源的需要来自于上面定义的控制类

定义如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.oracleseeker.rest.resources;
 
import com.oracleseeker.rest.controller.RestfulApplication;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Collection;
import org.restlet.Context;
import org.restlet.data.MediaType;
import org.restlet.data.Request;
import org.restlet.data.Response;
import org.restlet.resource.DomRepresentation;
import org.restlet.resource.Representation;
import org.restlet.resource.Resource;
import org.restlet.resource.ResourceException;
import org.restlet.resource.Variant;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
 
public class NotesResource extends Resource {
    Collection notes;
 
    public NotesResource() {
    }
 
    public NotesResource(Context context, Request request, Response response){
        super(context, request, response);
 
        getVariants().add(new Variant(MediaType.TEXT_XML));       
        notes = getNotes();
    }
 
    private Collection getNotes() {
        return ((RestfulApplication)getApplication()).getNotes();
    }
 
    @Override
    public Representation represent(Variant variant) throws ResourceException {
        if (<font color="#000000">MediaType.TEXT_XML.equals(variant.getMediaType())</font>){
            try{
                DomRepresentation representation = new DomRepresentation(MediaType.TEXT_XML);
                Document doc = representation.getDocument();
                Element root = doc.createElement(&quot;notes&quot;);
                doc.appendChild(root);
 
                for(Note note: notes){
                    Element eltNote = doc.createElement(&quot;note&quot;);
 
                    Element eltName = doc.createElement(&quot;name&quot;);
                    eltName.appendChild(doc.createTextNode(note.getName()));
                    eltNote.appendChild(eltName);
 
                    Element eltDescription = doc.createElement(&quot;description&quot;);
                    eltDescription.appendChild(doc.createTextNode(note.getDescription()));
                    eltNote.appendChild(eltDescription);
 
                    Element eltCreationDate = doc.createElement(&quot;creationDate&quot;);
                    eltCreationDate.appendChild(doc.createTextNode(new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;).format(note.getCreationDate())));
                    eltNote.appendChild(eltCreationDate);
                    root.appendChild(eltNote);
                }
                doc.normalizeDocument();
                return representation;
            }catch (IOException e){
                e.printStackTrace();
            }
        } 
        return null;
    }
}

 

这个类继承了org.restlet.resource.Resource类,类的构造函数中指定了只支持TEXT_XML表现形式,然后类中重载了represent方法,这个方法是用来处理GET请求的,还有其它的方法用来处理POST,PUT,DELETE。方法创建了以notes为根元素note为子元素的XML文档,XML文档中的内容来自于RestfulApplication中的notes收集器

 

7,配置web.xml文件

为了保证所有访问Restful资源的请求都能够被RestLet Servlet处理,需要创建URL模式(*)来匹配所有的请求。

添加如下的配置信息到web.xml文件中

 

1
2
3
4
5
6
7
8
9
10
  org.restlet.application
  com.oracleseeker.rest.controller.RestfulApplication 
 
 
  RestletServlet  
  com.noelios.restlet.ext.servlet.ServerServlet 
 
 
  RestletServlet  
  *

 

8,发布RESTFul服务,运行restful.jsp页面

 

运行restful.jsp页面,JDeveloper会将web服务发布到内置的Weblogic服务器,由于我们在web.xml中定义了所有的请求都通过RestLet Servlet来处理,因此运行的jsp页面报错。

只要修改浏览器中的URL地址,将restful.jsp修改为notes,修改为REST样式的URL,输出的结果如下:

2.restlet_xml_output

 

 

9,添加Note资源访问的限制

 

上面输出的是所有的Note资源,我们希望只是将某个Note的资源展现出来,因此需要对上面的控制类和提供资源的类进行修改,使它能够通过URL提供特定的Note资源: host:port/application/notes/{noteName}

REST资源URL的定位路由是由控制类来负责,因此需要将控制类RestfulApplication中的

router.attach("/notes}", NotesResource.class); 

修改为

router.attach("/notes/{noteName}", NotesResource.class);

 

而原来我们的资源类NotesResource返回的是所有的Note资源信息,因此需要添加根据控制类传递过来的参数进行资源的过滤,将资源提供类修改为如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
public class NotesResource extends Resource {
    Collection notes;
    Note note;
 
    public NotesResource() {
    }
 
    public NotesResource(Context context, Request request, Response response) {
        super(context, request, response);
 
        getVariants().add(new Variant(MediaType.TEXT_XML));
        notes = getNotes();
 
        String noteName = (String)getRequest().getAttributes().get(&quot;noteName&quot;);
        // Get the items directly from the &quot;persistence layer&quot;.
        note = getTheNote(noteName);
    }
 
    private Collection getNotes() {
        return ((RestfulApplication)getApplication()).getNotes();
    }
 
    @Override
    public Representation represent(Variant variant) throws ResourceException {
        if (MediaType.TEXT_XML.equals(variant.getMediaType())) {
            try {
                DomRepresentation representation =
                    new DomRepresentation(MediaType.TEXT_XML);
                Document doc = representation.getDocument();
                Element root = doc.createElement(&quot;notes&quot;);
                doc.appendChild(root);
 
                    Element eltNote = doc.createElement(&quot;note&quot;);
 
                    Element eltName = doc.createElement(&quot;name&quot;);
                    eltName.appendChild(doc.createTextNode(note.getName()));
                    eltNote.appendChild(eltName);
 
                    Element eltDescription = doc.createElement(&quot;description&quot;);
                    eltDescription.appendChild(doc.createTextNode(note.getDescription()));
                    eltNote.appendChild(eltDescription);
 
                    Element eltCreationDate =
                        doc.createElement(&quot;creationDate&quot;);
                    eltCreationDate.appendChild(doc.createTextNode(new SimpleDateFormat(&quot;yyyy-MM-dd HH:mm:ss&quot;).format(note.getCreationDate())));
                    eltNote.appendChild(eltCreationDate);
                    root.appendChild(eltNote);
                doc.normalizeDocument();
                return representation;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
 
    private Note getTheNote(String noteName) {
        Collection notes =
            ((RestfulApplication)getApplication()).getNotes();
        for (Note note : notes) {
            if (noteName.equalsIgnoreCase(note.getName()))
                return note;
        }
        return null;
    }
}

 

指定Note名称来得到相应的资源(/notes/conference)

3.special_xml

 

 

参考资料和链接

下载本文的JDeveloper 11g应用: Download JDeveloper 11g中利用RestLet开发RESTful服务 Version 1

 

Restlet

http://www.restlet.org/

First Steps with RestLet 1.1RC2 in JDeveloper 11g – restful services 101 by Lucas Jellema

http://technology.amis.nl/blog/3587/first-steps-with-restlet-11rc2-in-jdeveloper-11g-restful-services-101

 

目前主要几个支持REST的java架构:

Restlet(http://www.restlet.org/)

Cetia4(https://cetia4.dev.java.net/)

Apache Axis2(http://http://ws.apache.org/axis2/

sqlREST(http://sqlrest.sourceforge.net/)

REST-art(http://rest-art.sourceforge.net/

 

 

-

REST 初识

2:35 am in Oracle 融合中间件 by aronezhang

 

现在满世界的Web应用都在宣称自己已经RESTful了,目前三种主流的Web服务实现方案中,由于REST模式的Web服务比起SOAP和XML-RPC的服务有着明显的简洁,而导致越来越多的Web服务开始采用REST风格设计和实现,例如Amazon,Google和Yahoo都提供了REST风格的Web查询服务;Google的也推出了Ajax应用下的REST风格搜索API。

 

同时也出现了一些优秀的REST 网络架构实现,如Java版的 Restlet;JCP也制定了关于REST网络服务的规范标准:JAX-RS: Java API for RESTful Web Services (JSR 311)

 

REST简介

 

REST (Representational State Transfer) 表述性状态转移

REST是由Roy Thomas Fielding博士在2000年的博士论文中首次提出的,REST被定义为是一种网络应用的架构风格(architecture style)而不是一个标准,它包括架构元素(element)和架构约束(constraint),REST通常基于使用HTTP,URI,和XML以及HTML这些现有的协议和标准。

 

REST从资源的角度来审视这个网络,分布在各处的资源有URI来确定,客户端的应用通过URI来获取资源的,获取这些资源致使这些应用程序转变其状态,随着不断的获取资源,客户端应用不断地在转变状态,即所谓的表述性状态转移(Representational State Transfer)

 

REST的设计概念和准则

 

  1. 网络上的所有事物都被抽象为资源(resource)
  2. 每个资源对应一个唯一的资源标识(resource identifier)
  3. 对资源的操作包括获取、创建、修改和删除资源,这些操作对应HTTP协议的GET, POST, PUT和DELETE方法
  4. 通过通用的连接器接口(generic connector interface)对资源进行操作
  5. 对资源的各种操作不会改变资源标识
  6. 所有的操作都是无状态的(stateless)
  7. 资源的表现形式为XML或HTML,它取决于读者是机器还是人,消费web服务的客户应用是web浏览器或者其它
  8. 客户端和服务器结构
  9. 能够利用Cache机制
  10. 层次化的系统
  11. Code on Demand – Javascript

 

 

REST的优点

  1. 可以利用Cache来提高响应速度
  2. 通讯本身的无状态可以让不同的服务器处理一系列请求中的不同请求,提高服务器的扩展性
  3. 浏览器即可作为客户端,简化客户端软件系统的要求
  4. REST直接基于现有流行的协议和标准,依赖性更小
  5. 不需要而外的资源发现机制

 

 

参考资料

 

Roy Thomas Fielding博士论文英文版链接

http://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

JSR-000311 JAX-RS: The JavaTM API for RESTful Web Services
http://jcp.org/aboutJava/communityprocess/final/jsr311/index.html

Restlet

http://www.restlet.org/

Google Ajax Search API

http://code.google.com/apis/ajaxsearch/

 

 

后续

 

前面通过发布一个PL/SQL 的功能为一个Web Service展示了基于SOAP的Web服务实现,后续将基于Restlet来实现一个RESTful的Web服务。

 

编写Java Web Service Proxy

6:53 am in Oracle 融合中间件 by aronezhang

 

 

 

我们已经将PL/SQL Web Service发布到WebLogic应用服务器上,后面希望通过应用程序来调用它。

下面是用JDeveloper自带的功能来生成Web Service Proxy。

 

 1.generate_proxy

右键选择需要生成Proxy的Web Service 的 WSDL文件,点击如上图的菜单项来生成Proxy

 

 

根据向导生成Java Web Service Proxy,其中需要注意Endpoint URL的设置,修改应用服务器的地址和端口

如我的例子是:http://localhost:7001/oracleseeker/GreatingWordsSoapHttpPort 

3.setup_endpoint_url

 

生成的Proxy如下图中红线框内的Java类

4.java_proxy_pacakage_structure

 

生成的客户端入口类,命名以Web Service Http 调用端口 + Client

下面即是生成的代码,部分代码已被省略:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class GreatingWordsSoapHttpPortClient {
 
    // @Generated method (value={&quot;oracle.j2ee.ws&quot;} );
    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
 
            // @GeneratedBlockBegin (value={&quot;oracle.j2ee.ws&quot;} );
            com.oracleseeker.deom.ws.GreatingWordsSoapHttpPortClient myPort = new com.oracleseeker.deom.ws.GreatingWordsSoapHttpPortClient();
            // @GeneratedBlockEnd   (value={&quot;oracle.j2ee.ws&quot;} );
 
            System.out.println(&quot;calling &quot; + myPort.getEndpoint());
 
            // Add your own code here
 
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    } 
}

 

 

代码中我们可以看到一个变量:myPort,后续的程序中只要调用它便可以执行Web Service中的方法,

在// Add your own code here 之后添加自己的程序逻辑就可以了,添加如下的代码,用来输入用户名,返回欢迎词:

1
2
// Add your own code here
System.out.println(myPort.getGreetingWords(&quot;Arone.Zhang&quot;));

 

运行的结果如下:

1
2
calling http://localhost:7001/oracleseeker/GreatingWordsSoapHttpPort
Hello Arone.Zhang, 2008-10-13

 

 

在JDeveloper 中生成Java的Web Service Proxy非常的简单,基本无需做什么编码工作。只要在生成的代码中加入自己的代码逻辑。