【javascript学习指南】java Restlet开发restful webservice学习笔记

更新时间:2020-10-15    来源:WebService    手机版     字体:

【www.bbyears.com--WebService】

Restlet的简单介绍

说道java开发Restful webservie,除了JAX-RS,还有一个就是Restet。Restlet个人感觉要比JAX-RS更灵活,当然,也更复杂点。
特点

和JAX-RS类似,也可以使用注解。但是没JAX-RS那么多注解,很少,Restlet的所有注解类有(有@符号的就是):

Restlet有一个特点,就是可以既作为web应用,放到tomcat之类的容器中,响应http请求。这种方式和JAX-RS差不多,都是通过一个类似于拦截器的servlet将请求拦截,然后转发给Restlet写的应用处理。web.xml中配置如下:


         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
   
   
        RestletServlet
        org.restlet.ext.servlet.ServerServlet
       
           
            org.restlet.application
            adages.AdagesApplication
       

   

   
   
        RestletServlet
        /*
   

同时,Restlet自带了一个http服务器的功能,也就是说Restlet写的webservice,我们可以导出为jar(运行main函数),直接运行jar文件。如下:
编译为jar文件后,运行截图:

按ctrl+c终止。
开发的时候遇到的问题

1.jar库的版本
编译过程导入 org.restlet的相关jar库的时候,必须选择是jee的而不是是jse的。否则接收请求后会报错,如下:

WARNING: Exception or error caught in server resource
java.lang.AbstractMethodError: org.restlet.engine.converter.ConverterHelper.score(Ljava/lang/Object;Lorg/restlet/representation/Variant;Lorg/restlet/resource/Resource;)F
    at org.restlet.engine.converter.ConverterUtils.getBestHelper(ConverterUtils.java:137)
    at org.restlet.service.ConverterService.toRepresentation(ConverterService.java:229)
    at org.restlet.resource.Resource.toRepresentation(Resource.java:738)
    at org.restlet.resource.ServerResource.doHandle(ServerResource.java:509)
    at org.restlet.resource.ServerResource.get(ServerResource.java:695)
    at org.restlet.resource.ServerResource.head(ServerResource.java:977)
    at org.restlet.resource.ServerResource.doHandle(ServerResource.java:587)
    at org.restlet.resource.ServerResource.doNegotiatedHandle(ServerResource.java:637)
    at org.restlet.resource.ServerResource.doConditionalHandle(ServerResource.java:336)
    at org.restlet.resource.ServerResource.handle(ServerResource.java:899)
    at org.restlet.resource.Finder.handle(Finder.java:243)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.routing.Router.doHandle(Router.java:428)
    at org.restlet.routing.Router.handle(Router.java:645)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.engine.application.StatusFilter.doHandle(StatusFilter.java:151)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:208)
    at org.restlet.engine.application.ApplicationHelper.handle(ApplicationHelper.java:81)
    at org.restlet.Application.handle(Application.java:378)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.routing.Router.doHandle(Router.java:428)
    at org.restlet.routing.Router.handle(Router.java:645)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.routing.Router.doHandle(Router.java:428)
    at org.restlet.routing.Router.handle(Router.java:645)
    at org.restlet.routing.Filter.doHandle(Filter.java:156)
    at org.restlet.routing.Filter.handle(Filter.java:203)
    at org.restlet.engine.CompositeHelper.handle(CompositeHelper.java:208)
    at org.restlet.Component.handle(Component.java:389)
    at org.restlet.Server.handle(Server.java:513)
    at org.restlet.engine.ServerHelper.handle(ServerHelper.java:69)
    at org.restlet.engine.adapter.HttpServerHelper.handle(HttpServerHelper.java:149)
    at org.restlet.ext.servlet.ServerServlet.service(ServerServlet.java:1086)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:647)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
    at org.apache.coyote.http11.Http11AprProcessor.process(Http11AprProcessor.java:864)
    at org.apache.coyote.http11.Http11AprProtocol$Http11ConnectionHandler.process(Http11AprProtocol.java:579)
    at org.apache.tomcat.util.net.AprEndpoint$Worker.run(AprEndpoint.java:1665)
    at java.lang.Thread.run(Thread.java:636)   ``
``

2.导入为jar的问题

如果编译的jar运行的时候有报错“中没有主清单属性”,则说明你MANIFEST.MF(清单文件)放错了位置。
你MANIFEST.MF(清单文件)必须放在 src/main/resources/META_INF/
实例:

Restlet使用的jar库也比较多,所以还是使用maven管理:
pom.xml:


         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    4.0.0
    groupId
    RestletForRestWebservcie
    1.0-SNAPSHOT
   
       
           
                org.apache.maven.plugins
                maven-compiler-plugin
                2.3.2
               
                    1.7
                    1.7
               

           

       

   

   
       
            maven-restlet
            Restlet repository
            https://maven.restlet.com
       

   

   
        2.3.4
   

   
       
            org.restlet.jse
            org.restlet
            ${restlet-version}
       

       
            org.restlet.jse
            org.restlet.ext.jackson
            ${restlet-version}
       

       
            org.restlet.jee
            org.restlet
            ${restlet-version}
       

       
            org.restlet.jee
            org.restlet.ext.servlet
            ${restlet-version}
       

       
            org.restlet.jee
            org.restlet.ext.json
            ${restlet-version}
       

       
            org.restlet.jee
            org.restlet.ext.xml
            ${restlet-version}
       

   

web.xml:

当Restlet项目是放在tomcat容器中,则需要在web.xml中配置一个类似拦截器的servlet来拦截和转发请求。


         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
         version="3.1">
   
   
        RestletServlet
        org.restlet.ext.servlet.ServerServlet
       
           
            org.restlet.application
            adages.AdagesApplication
       

   

   
   
        RestletServlet
        /*
   


Adage:

javabean类:

package adages;
/**
 * Created by AlexY on 2016/7/1.
 */
public class Adage {
    private String words;  //一行字符串
    private int wordCount;// 一行字符串单词的个数
    private int id; //每行的行号
    public Adage() {
    }
    @Override
    public String toString() {
        return String.format("%2d:",id)+ words + "--" + wordCount + "words";
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public int getWordCount() {
        return wordCount;
    }
//    因为在setWord的时候就可以得到wordCount
    public void setWordCount(int wordCount) {
    }
    public String getWords() {
        return words;
    }
    public void setWords(String words) {
        this.words = words;
        this.wordCount = words.trim().split("\\S+").length;
    }
}

Adages :

存放Adage的list,
注意:为了线程安全,使用了CopyOnWriteArrayList来作为集合存放,同时使用了 AtomicInteger。

package adages;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicInteger;
/**
 * Created by AlexY on 2016/7/1.
 */
public class Adages {
    private static CopyOnWriteArrayList adages;
    private static AtomicInteger id;
    static {
        String[] aphorisms =
                {"What can be shown cannot be said.",
                "If a lion could talk, we could not understand him.",
                "Philosophy is a battle against the bewitchment of our intelligence by means of language.",
                "Ambition is the death of thought.",
                "The limits of my language mean the limits of my world."};
       
       
        adages = new CopyOnWriteArrayList<>();
        id = new AtomicInteger();
       
        for (String str : aphorisms){
            add(str);
        }
       
       
    }
   
    public static String toPlain(){
        // TODO: 2016/7/1 可以用stringbuffer优化
        String retval = "";
        int i = 1;
        for (Adage adage : adages){
            retval += adage.toString() + "\n";
        }
       
        return retval;
    }
   
   
    public static CopyOnWriteArrayList getList(){
       
        return adages;
    }
   
   
   
    public static Adage find(int id){
        Adage adage = null;
        for ( Adage a : adages){
            if ( a.getId() == id){
                adage = a;
                break;
            }
        }
        return adage;
    }
   
   
   
//    支持post请求
    public static void add(String str) {
        int localId = id.incrementAndGet();
        Adage adage = new Adage();
        adage.setWords(str);
        adage.setId(localId);
        adages.add(adage);
    }
}

XmlAllResource :

这是个资源类,必须继承ServerResource类。
可以使用@Get之类的注解,表示在接收到该类型的http请求的 时候,使用该方法做出响应。
但是这个响应的类型没有JAX-RS方便,需要自己手动写方法生成xml或json
返回整个list,以xml的形式。

package adages;
import org.restlet.data.MediaType;
import org.restlet.ext.xml.DomRepresentation;
import org.restlet.representation.Representation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.IOException;
import java.util.List;
/**
 * Created by AlexY on 2016/7/1.
 */
public class XmlAllResource extends ServerResource {
    public XmlAllResource() {
    }
    @Get
    public Representation toXml(){
        List list = Adages.getList();
        DomRepresentation dom = null;
        try {
            dom = new DomRepresentation(MediaType.TEXT_XML);
            dom.setIndenting(true);
            Document doc = dom.getDocument();
            Element root = doc.createElement("adages");
            for ( Adage adage : list){
                Element next = doc.createElement("adage");
                next.appendChild(doc.createTextNode(adage.toString()));
                root.appendChild(next);
            }
            doc.appendChild(root);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dom;
    }
}

JsonAllResource
资源类
返回整个list,以json形式

package adages;
import org.restlet.ext.json.JsonRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import java.util.List;
/**
 * Created by AlexY on 2016/7/1.
 */
public class JsonAllResource extends ServerResource {
    public JsonAllResource() {
    }
    @Get
    public Representation toJson(){
        List list = Adages.getList();
//        生成jspn Representation
        JsonRepresentation json = null;
        try {
           json = new JsonRepresentation(new StringRepresentation(list.toString())) ;
        }catch (Exception e){
            e.printStackTrace();
        }
        return json;
    }
}


XmlOneResource :
这是个资源类,必须继承ServerResource类。
返回单条记录,以xml的形式。

package adages;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.ext.xml.DomRepresentation;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Get;
import org.restlet.resource.ServerResource;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.IOException;
import java.util.List;
/**
 * Created by AlexY on 2016/7/1.
 */
public class XmlOneResource extends ServerResource {
    public XmlOneResource() {
    }
//    响应get请求,并返回xml
    @Get
    public Representation toXml(){
        String sid = (String) getRequest().getAttributes().get("id");
        if ( null == sid){
            return badRequest("No ID provided\n");
        }
        int id;
        try {
            id = Integer.parseInt(sid.trim());
        }catch (Exception e){
            return  badRequest("No such ID\n");
        }
//        搜索这个Adage
        List list = Adages.getList();
        Adage adage = Adages.find(id);
        if ( null == adage){
            return badRequest("No adage with ID " + id + "\n");
        }
//        生成xml响应
        DomRepresentation dom = null;
        try {
            dom = new DomRepresentation(MediaType.TEXT_XML);
//            xml文档是否缩进
            dom.setIndenting(true);
            Document doc = dom.getDocument();
//            创建根节点
            Element root = doc.createElement("adage");
            root.appendChild(doc.createTextNode(adage.toString()));
//            将生成的xml放到响应中
            doc.appendChild(root);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dom;
    }
    private Representation badRequest(String msg) {
        Status error = new Status(Status.CLIENT_ERROR_BAD_REQUEST, msg);
        return new StringRepresentation(error.toString());
    }
}

CreateResource

资源类

响应post请求,用于创建新记录
返回TEXT_PLAIN (纯文本)

package adages;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Post;
import org.restlet.resource.ServerResource;
/**
 * Created by AlexY on 2016/7/1.
 */
public class CreateResource extends ServerResource {
    public CreateResource() {
    }
    @Post
    public Representation create(Representation data){
        Status status  = null;
        String msg  = null;
//        从post的body中提取数据
        Form form = new Form(data);
        String words = form.getFirstValue("words");
        if ( null == words){
            msg = "No words were given for the adage.\n";
            status = Status.CLIENT_ERROR_BAD_REQUEST;
        }else{
            Adages.add(words);
            msg = "The adage "" + words + "" has been added.\n";
            status = Status.SUCCESS_OK;
        }
        setStatus(status);
        return new StringRepresentation(msg, MediaType.TEXT_PLAIN);
    }
}

UpdateResource

资源类

响应put请求,用于更新记录

package adages;
import org.restlet.data.Form;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.Put;
import org.restlet.resource.ServerResource;
/**
 * Created by AlexY on 2016/7/1.
 */
public class UpdateResource  extends ServerResource {
    public UpdateResource() { }
    @Put
    public Representation update(Representation data) {
        Status status = null;
        String msg = null;
        // Extract the data from the POST body.
        Form form = new Form(data);
        String sid = form.getFirstValue("id");
        String words = form.getFirstValue("words");
        if (sid == null || words == null) {
            msg = "An ID and new words must be provided.\n";
            status = Status.CLIENT_ERROR_BAD_REQUEST;
        }
        else {
            int id = Integer.parseInt(sid.trim());
            Adage adage = Adages.find(id);
            if (adage == null) {
                msg = "There is no adage with ID " + id + "\n";
                status = Status.CLIENT_ERROR_BAD_REQUEST;
            }
            else {
                adage.setWords(words);
                msg = "Adage " + id + " has been updated to "" + words + "".\n";
                status = Status.SUCCESS_OK;
            }
        }
        setStatus(status);
        return new StringRepresentation(msg, MediaType.TEXT_PLAIN);
    }
}

AdagesApplication

Application类

这里使用了一个匿名类来处理DETELE请求,用于删除记录。
该类还用来配置路由。

package adages;
import org.restlet.Application;
import org.restlet.Request;
import org.restlet.Response;
import org.restlet.Restlet;
import org.restlet.data.Status;
import org.restlet.routing.Router;
/**
 * Created by AlexY on 2016/7/1.
 */
public class AdagesApplication extends Application {
    @Override
    public synchronized Restlet createInboundRoot() {
//        通过一个匿名类来实现了DELETE操作,其他的操作通过独立的java类实现
//        DELETE处理
        Restlet janitor = new Restlet(getContext()) {
            @Override
            public void handle(Request request, Response response) {
                String msg = null;
                String sid = (String ) request.getAttributes().get("id");
                if ( null == sid){
                    msg = badRequest("No ID given.\n");
                }
                Integer id = null;
                try {
                    id = Integer.parseInt(sid.trim());
                }  catch (Exception e){
                    msg = badRequest("Ill-formed ID.\n");
                }
                Adage adage = Adages.find(id);
                if ( null == adage){
                    msg = badRequest("No adage with ID " + id + "\n");
                }else {
                    Adages.getList().remove(adage);
                    msg = "Adage " + id + " removed.\n";
                }
                response.setEntity(msg, org.restlet.data.MediaType.TEXT_PLAIN);
            }
        };
//        创建路由表
        Router router = new Router(getContext());
        router.attach("/", PlainResource.class);
        router.attach("/xml",         XmlAllResource.class);
        router.attach("/xml/{id}",    XmlOneResource.class);
        router.attach("/json",        JsonAllResource.class);
        router.attach("/create",      CreateResource.class);
        router.attach("/update",      UpdateResource.class);
        return router;
    }
    private String badRequest(String msg) {
        Status error = new Status(Status.CLIENT_ERROR_BAD_REQUEST,msg);
        return error.toString();
    }
}

Main

如果你是将Restlet放到tomcat之类的容器,则不需要这个类。
如果是像Restlet编译为jar文件,单独作为httpserver来响应http请求,则需要这个类。当然也可以将main方法放到其他的类里面,这里为了方便区分,所以单独放到一个java文件中。


package adages;
import org.restlet.Component;
import org.restlet.data.Protocol;
/**
 * Created by AlexY on 2016/7/1.
 */
public class Main {
    public static void main(String[] args) throws Exception {
        // 创建一个ixn的Component
        Component component = new Component();
//        新增一个http server监听8182端口
        component.getServers().add(Protocol.HTTP, 8182);
//        将应用的appilcation类添加进去
//        应用的url就是:
//        http://localhost:8182/adages/xml/1
        component.getDefaultHost().attach("/adages", new AdagesApplication());
        // 启动服务.
        component.start();
    }
}

在tomcat下运行的效果:
运行后访问的地址:
http://localhost:8182/adages/
获取单个的xml记录:
http://localhost:8182/adages/xml/1

 

本文来源:http://www.bbyears.com/asp/104763.html

热门标签

更多>>

本类排行