一什么是REST REST是REpresentational State Transfer的缩写代表分布式超媒体系统(如World Wide Web)上的一种软件架构体系并不仅仅是创建Web Service的一种方法它最早由Roy Fielding于年在其博士论文Architectural Styles and the Design of Networkbased Software Architectures中提出并定义了一些基本原则简单的说放到World Wide Web上就是所有的应用程序对象和功能都可以抽象为一种资源(Resource)并通过URI来定位并使用因此我们可以把符合REST原则的系统称为RESTful也就是说REST是一种架构风格而不是一个标准你永远不会看到WC发布一个叫REST的Specification RESTful Web Service与基于SOAP和WSDL的Web Service有着很多的不同它有着以下特点 ·将Web Service作为一种资源并通过URI来定位 ·使用HTTP中的POSTGETPUT和DELETE方法来代表对资源的CREATEREADUPDATEDELETE(CRUD)操作 ·使用无状态通信 ·传输XML或者SON 在JAXWS中提供了对开发和部署一个RESTful的Web Service的基本支持即通过实现Provider接口使得Web Serivce可以对传输的XML消息进行完全的控制因此我们可以在WAS CE中使用JAXWS开发一个RESTful的Web Service 对RESTful Web Service提供完整支持的JAXRS Specification将会加入Java EE 的大家庭中当前的WAS CE Vx是遵循Java EE 的企业级应用服务器因此若想使用JAXRS开发RESTful Web Service请关注WAS CE的后续版本 二开发环境设置 本文基于WAS CE的最新版本V开发一个RESTful的Web Service在开始编写代码之前请确认如下的开发环境 ·Sun JDK V ·Eclipse IDE for Java EE Developers Ganymede ·WASCE Eclipse Plugin (WEP) V 此外WAS CE使用Axis作为JAXWS引擎但是由于其存在一个已知的关于HTTP ContentType Header的问题(在Axis中才解决)所以我们需要将JAXWS引擎切换成Apache CXF (WAS CE使用版本为V)不用担心WAS CE的模块化架构使这个过程十分简单过程如下 启动WAS CE 打开Web //localhost:/console 进入Application > Plugins页面点击Add Repository 由于WAS CE V是基于Geronimo V开发所以我们也可以使用Geronimo的Server plugins在New Repository中输入 / 然后点击Add Repository 选择刚刚添加的Repository然后点击Show Plugins in selected repository 勾选上以下plugins并且点击install按钮 在以上CXF相关的Plugin安装完成之后 我们需要更新WAS CE的配置文件以使得WAS CE在启动时加载CXF以代替Axis(注意在更改配置文件前先要停止WAS CE服务器) 停止WAS CE后打开<WASCE_HOME>/var/config/configxml 去掉以下四个module的condition属性 <module name=orgnfigs/axisdeployer//car condition=…/> <module name=orgnfigs/axisejbdeployer//car condition=…/> <module name=orgnfigs/cxfdeployer//car condition=…/> <module name=orgnfigs/cxfejbdeployer//car condition=…/> 增加load属性axis相关的为falsecxf相关的为true <module name=orgnfigs/axisdeployer//car load=false/> <module name=orgnfigs/axisejbdeployer//car load=false/> <module name=orgnfigs/cxfdeployer//car load=true/> <module name=orgnfigs/cxfejbdeployer//car load=true/> 重新启动WAS CE服务器 三开发一个简单的RESTful Web Service 在Eclipse中创建一个Dynamic Web Project作为Web Service的宿主 选择File>New>Dynamic Web Project 输入Project Name为HelloRestfulService 右击Java Resources src新建一个class其中packageNameInterfaces如下设置 加入如下代码 package comibmwascesamplesjaxwsrest; import javaioByteArrayInputStream; import javaxannotationResource; import javaxservletServletRequest; import javaxxmlparsersDocumentBuilder; import javaxxmlparsersDocumentBuilderFactory; import javaxxmltransformSource; import javaxxmltransformdomDOMSource; import javaxxmltransformstreamStreamSource; import javaxxmlwsBindingType; import javaxxmlwsProvider; import javaxxmlwsWebServiceContext; import javaxxmlwsWebServiceProvider; import javaxxmlwshandlerMessageContext; import javaxxmlwshttpHTTPBinding; import javaxxmlwshttpHTTPException; import orgwcdomNode; import orgwcdomNodeList; import orgxmlsaxInputSource; @WebServiceProvider @BindingType (value = HTTPBinding HTTP_BINDING ) public class HelloWorld implements Provider<Source> { @Resource protected WebServiceContext wsContext ; public Source invoke(Source source) { try { String targetName = null ; if (source == null ) { //Get: Getting input from query string MessageContext mc = wsContext getMessageContext(); String query = (String) mcget(MessageContext QUERY_STRING ); System out println( Query String = + query); ServletRequest req = (ServletRequest) mcget(MessageContext SERVLET_REQUEST ); targetName = reqgetParameter( target ); } else { //POST: Getting input from input box Node n = null ; if (source instanceof DOMSource) { n = ((DOMSource) source)getNode(); } else if (source instanceof StreamSource) { StreamSource streamSource = (StreamSource) source; DocumentBuilder builder = DocumentBuilderFactorynewInstance()newDocumentBuilder(); InputSource inputSource = null ; if (streamSourcegetInputStream() != null ) { inputSource = new InputSource(streamSourcegetInputStream()); } else if (streamSourcegetReader() != null ) { inputSource = new InputSource(streamSourcegetReader()); } n = builderparse(inputSource); } else { throw new RuntimeException( Unsupported source: + source); } NodeList children = ngetChildNodes(); for ( int i = ; i < childrengetLength(); i++) { Node child = em(i); if (childgetNodeName()equals( people )) { targetName = childgetAttributes()getNamedItem( target )getNodeValue(); break ; } } } String body = <ns:return xmlns:ns=\\> + <ns:HelloWorldResponse> + this sayHello(targetName) + </ns:HelloWorldResponse> + </ns:return> ; return new StreamSource( new ByteArrayInputStream(bodygetBytes())); } catch (Exception e) { eprintStackTrace(); throw new HTTPException(); } } private String sayHello(String target){ return Hello + target; } } 让我们看一看代码中的几个关键点 a) @WebServiceProvider 表明这个Web Service实现了Provider接口可以对XML消息进行完全的处理 b) Provider 是这类Web Service都要实现的接口它只有一个方法需要实现即 public abstractjavalangObject invoke(javalangObject arg) c) Source 是交换信息的载体 当Source对象为空时表示是一个GET Request因为这种情况下所有信息是被拼成一个URI的参数并传到这个URI对应的Web Service 否则是一个POST Request其内容会包括在一个Source对象内 另外Response的内容也要放到一个Source对象内 编写webxml 为了使我们前面编写的Web Service能够成功部署到WAS CE中我们需要将如下内容加入到webxml中 <servlet> <servletname>Hello</servletname> <servletclass>comibmwascesamplesjaxwsrestHelloWorld</servletclass> </servlet> <servletmapping> <servletname>Hello</servletname> <urlpattern>/Hello</urlpattern> </servletmapping> 注意这里只是借用了<servlet>和<servletmapping>标签来帮助暴露Web Service并不是真是要求这个Web Service必须要实现HttpServlet接口 部署运行并测试这个Web Service 右击这个HelloRestfulService工程选择Run As > Run on Server会将其部署到WAS CE中当Status栏变为Synchronized时在Console中会有类似如下信息显示 通过访问如下地址测试使用GET方式调用RESTful Web Service返回的结果 //localhost/HelloRestfulService/Hello?target=Rex 四开发一个简单的RESTful Web Service Client 创建一个Dynamic Web Project作为Client 选择File>New>Dynamic Web Project 输入Project Name为HelloRestfulClient 新建一个testgetjsp加入如下内容 <form method=POST action=HelloGetMethodRequester> Target Name: <input type=text name=target> <input type=submit value=Submit> </form> 这个JSP用来为HelloGetMethodRequester Servlet提供参数 创建HelloGetMethodRequester Servlet加入如下内容 protected void doPost(HttpServletRequest request HttpServletResponse response) throws ServletException IOException { PrintWriter ut = responsegetWriter(); String target = requestgetParameter( target ); String queryRequest = //localhost:/HelloRestfulService/Hello?target= + target; GetMethod method = new GetMethod(queryRequest); HttpClient client = new HttpClient(); int statusCode = clientexecuteMethod(method); if (statusCode != ) { //HttpStatusSC_OK System err println( Method failed: + methodgetStatusLine()); } try { DocumentBuilder builder= DocumentBuilderFactorynewInstance()newDocumentBuilder(); Document queryResponse = builderparse(methodgetResponseBodyAsStream()); XPath xPath = XPathFactorynewInstance()newXPath(); NodeList nodes = (NodeList) xPathevaluate( /return queryResponse XPathConstants NODESET ); for ( int i = ; i < nodesgetLength(); i++) { // Get eachxpathexpression as a string String str = (String) xPathevaluate( HelloWorldResponse em(i) XPathConstants STRING ); outprintln( Service return: + str); } } catch (Exception e) { eprintStackTrace(); } } 在这个Servlet中我们用到了commonscodecjar和commons两个包因此我们需要将它们加入到Build Path中 这两个包在WAS CE的如下目录中可以找到 <WASCE_HOME>\repository\commonscodec\commonscodec\\commonscodecjar <WASCE_HOME >\repository\commonshttpclient\commonshttpclient\\commons 让我们看一看这段Servlet代码中的一些关键点 a) 首先创建了一个HttpClient对象并运行了GetMethod即使用GET请求如下URI //localhost/HelloRestfulService/Hello?target= + target b) 如果成功返回即statusCode为则可以从method对象中得到返回的结果 methodgetResponseBodyAsStream() c) 因为返回的结果为自定义的一段XML文档所以我们可以使用XPath来处理并输出到页面上 编写部署计划geronimowebxml 为使这个Web Client能够成功部署到WAS CE中我们还需要在geronimowebxml的<environment>中加入如下依赖 <dep:dependencies> <dep:dependency> <dep:groupId>commonscodec</dep:groupId> <dep:artifactId>commonscodec</dep:artifactId> <dep:version></dep:version> <dep:type>jar</dep:type> </dep:dependency> <dep:dependency> <dep:groupId>commonshttpclient</dep:groupId> <dep:artifactId>commonshttpclient</dep:artifactId> <dep:version></dep:version> <dep:type>jar</dep:type> </dep:dependency> </dep:dependencies> 部署和运行 右击这个HelloRestfulClient工程选择Run As > Run on Server会将其部署到WAS CE中当Status栏变为Synchronized时表示部署成功 在浏览器中打开如下页面 输入Rex并点击Submit可得到如下结果 五总结 本文介绍了REST的基本概念以及如何在WAS CE V下开发一个RESTful Web Service和一个使用GET方式的Client如果读者朋友有兴趣的话也可以尝试扩展这个Client如增加testpostjsp和HelloPostMethodRequester Servlet两个文件 testpostjsp包括一个文件上载框用以上传一个XML文件 HelloPostMethodRequester Servlet用于将XML文件以POST方式传送给HelloWorld这个Service 事实上我们的HelloWorld RESTful Web Service已经具备了处理接收一个XML文件的能力 六资源链接 ·WAS CE及Samples下载 ·WAS CE Eclipse Plugin (aka WEP WAS CEs WTP Server Adapter)下载 ·WAS CE文档 ·WAS CE主页 |