需求
公司有一个产品,包括前台WEB界面和多个后台服务,各个服务都需要在前面界面中进行配置和控
制,以调整服务的行为。以前,配置文件都存放在数据库中,界面上修改配置后入库,并发送消息(Socket)通知特定的服务重新加载配置。这样有些问题,
一方面自己维护Socket带来很多麻烦,二来数据库重建的时候,需要备份/恢复这些配置数据。

所以,我们想把配置文件局部化到各个服务(比如用本地文件存储),然后在界面上修改的时候,实时向服务请求当前配置数据(XML格式),修改完毕后,再直接发给服务进行更新和存储。而在通信方式上,我们希望各个服务提供Web Service接口来实现配置的检索和更新。

但Web Service通常需要在Web Container(比如,tomcat, jboss)中实现,而我们不想把所有的服务都跑在tomcat里,于是想找到一种更加轻量级的方式。

今天偶然看到JSR311,进而发现在Java后台服务中内嵌grizzly(基于NIO的实现)和Jersey(Sun的JSR311参考实现)
来提供Restful Web
Service能力,是非常方便的。个人认为这种方式适用于后台Java程序的控制、配置和监视,其作用有些类似于JMX,但比实现JMX要简单的多
(JSR311基于POJO)。

背景知识
Representational state transfer (REST) Web Service:

是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。在目前三种主流的Web
Service实现方案中,因为REST与SOAP和XML-RPC相比显的更加简洁,因此越来越多的Web
Service开始采用REST风格设计和实现。

参考资料:http://en.wikipedia.org/wiki/Representational_State_Transfer

Jersey:
它是Sun对JSR311的官方参考实现,而JSR311是java中实现Restful Web
Service的API规范(JSR311: JAX-RS: The Java API for RESTful Web
Services)。JSR311有一个重要目标:使用注解(annotation)把POJO暴露成Web Service,这样就比较轻量级。

参考资料:https://jsr311.dev.java.net/nonav/releases/1.0/spec/index.html

Grizzly:
Grizzly于2004年诞生在GlassFish中,开始目的是要建构一个HTTP
Web服务器,用来代替Tomcat的Coyote连接器和Sun WebServ
er6.1。后来,Grizzly成为一种应用程序框架,专门解决编写成千上万用户访问服务器时候产生的各种问题。使用JAVA
NIO作为基础,并隐藏其编程的复杂性。在本例中,我们将其用作内嵌的Servlet Container。

参考资料:https://grizzly.dev.java.net/

准备工作
首先,下载grizzly和jersey。其中,grizzly的下载地址为:http://download.java.net/maven/2/com/sun/grizzly/grizzly-servlet-webserver/1.9.18a/grizzly-servlet-webserver-1.9.18a.jar,jersey的下载地址为:http://download.java.net/maven/2/com/sun/jersey/jersey-archive/1.1.2-ea/jersey-archive-1.1.2-ea.zip

在Eclipse中建一个Java工程,名为jsr331,然后把下载的jersey-archive-1.1.2-ea.zip解压,将
jersey-archive-1.1.2-ea/contribs、jersey-archive-1.1.2-ea/lib两个目录下的jar包,连
同下载的grizzly-http-webserver-1.9.18a.jar都拷贝到jsr331工程下的lib目录,并加入到该工程的Build
Path。(实测中,发现还需要引入一个包,下载地址:http://repository.jboss.org/maven2/org/jvnet
/mimepull/1.2/mimepull-1.2.jar)

编写最简单的服务
JSR331把准备提供Web Service的类称为Resource class。Resource class是一个普通类(POJO),但是按照规范要求增加了特定的注解(annotation)。我们首先实现最简单的hello world服务。

在jinxfei.test.jsr311.service下,建立HelloService类,内容如下:

  1. package jinxfei.test.jsr311.service;  
  2.   
  3. import javax.ws.rs.GET;  
  4. import javax.ws.rs.Path;  
  5. import javax.ws.rs.Produces;  
  6.   
  7. @Path("/hello")  
  8. public class HelloService {  
  9.     @GET   
  10.     @Produces("text/plain")  
  11.     public String helloWorld(){  
  12.         return "Hello world!";  
  13.     }     
  14. }  

代码中的注解(annotation)决定了程序发布成Web Service后的行为和特性。其中,HelloService类前面的@PATH,表明该Service的URL路径,这种类名前面带@PATH注解的类被称为Root Resource Class,因为他们决定了访问Service时URI中的第一级路径;@GET表示访问该服务使用HTTP GET方法;@Produces规定该服务返回结果的类型,这里的”text/plain”表名返回纯文本。

发布服务
实现服务类后,我们要启动一个内嵌的grizzly servlet
container,并把HelloService发布到该Container中,这样就能通过HTTP协议访问该服务。Jersey提供了两种发布方
式,标准的做法需要在web.xml中做配置,所以比较适用于部署在独立的Web Container下的应用,本文不做深入介绍,可参见:http://docs.sun.com/app/docs/doc/820-4867/6nga7f5o4?l=en&a=view。本例与grizzly整合,所以使用grizzly的工具类,通过代码进行部署配置。

在jinxfei.test.jsr311包下创建ServiceDeployer类,内容如下:

  1. package jinxfei.test.jsr311;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.URI;  
  5. import java.util.HashMap;  
  6. import java.util.Map;  
  7. import javax.ws.rs.core.UriBuilder;  
  8. import com.sun.grizzly.http.SelectorThread;  
  9. import com.sun.jersey.api.container.grizzly.GrizzlyWebContainerFactory;  
  10.   
  11. public class ServiceDeployer {  
  12.       
  13.     public static void main(String[] args) throws IOException {  
  14.         URI ServerURI=UriBuilder.fromUri("http://localhost/").port(9876).build();  
  15.         startServer(ServerURI);  
  16.         System.out.println("服务已启动,请访问:"+ServerURI);  
  17.     }      
  18.       
  19.     protected static SelectorThread startServer(URI serverURI) throws IOException {  
  20.         final Map<String, String> initParams = new HashMap<String, String>();  
  21.         initParams.put("com.sun.jersey.config.property.packages","jinxfei.test.jsr311.service");  
  22.         System.out.println("Grizzly 启动中...");  
  23.         SelectorThread threadSelector = GrizzlyWebContainerFactory.create(serverURI, initParams);       
  24.         return threadSelector;  
  25.     }      
  26. }  


码很简单,其中:initParams.put("com.sun.jersey.config.property.packages" ,
"jinxfei.test.jsr311.service");
这一行的第二个参数表明服务实现类所在的包名,系统会自动搜索做了注解的类并将其发布成服务。

在Eclipse中运行该类,控制台上打印“服务已启动”字样,表示系统启动成功,打开浏览器,输入:http://localhost:9876/hello,即可看到效果,如下图所示:

让功能再强一点点
接下来,我们要让服务能够接受参数,并根据参数打印不同的信息,最简单的就是回显(Echo)。为了实现这一功能,我们给HelloService类增加一个方法:

  1. @POST @Path("echo")
  2. @Consumes("application/x-www-form-urlencoded")
  3. public String echo(@FormParam("msg") String message){
  4. return "Are you saying:"+message;
  5. }

@POST表明该方法要用HTTP Post来访问,@Path表明访问该方法的相对路径是echo,@Consumes表明该方法处理HTTP Post请求中何种类型的数据。该方法参数中的注解@FormParam("msg")说明后面的“String message”参数取自表单提交数据中的msg。

由于该方法需要Post访问,且需要通过表单提交数据,所以我们创建一个test.htm,在其中写一个简单的Form:

  1. <form action="http://localhost:9876/hello/echo" method="post">
  2. <input type="text" name="msg">
  3. <input type="submit" value="submit">
  4. </form>

重启ServiceDeployer,然后在浏览器中打开test.htm,表单中输入任意信息:

然后点提交按钮,可以看到如下信息:

这说明HelloService已经提取了表单参数,并回显给用户。

webservice restful一个小例子的更多相关文章

  1. java连接mysql的一个小例子

    想要用java 连接数据库,需要在classpath中加上jdbc的jar包路径 在eclipse中,Project的properties里面的java build path里面添加引用 连接成功的一 ...

  2. java操作xml的一个小例子

    最近两天公司事比较多,这两天自己主要跟xml打交道,今天更一下用java操作xml的一个小例子. 原来自己操作xml一直用这个包:xstream-1.4.2.jar.然后用注解的方式,很方便,自己只要 ...

  3. MVVM模式的一个小例子

    使用SilverLight.WPF也有很长时间了,但是知道Binding.Command的基本用法,对于原理性的东西,一直没有深究.如果让我自己建一个MVVM模式的项目,感觉还是无从下手,最近写了一个 ...

  4. 使用Trinity拼接以及分析差异表达一个小例子

    使用Trinity拼接以及分析差异表达一个小例子  2017-06-12 09:42:47     293     0     0 Trinity 将测序数据分为许多独立的de Brujin grap ...

  5. 从一个小例子认识SQL游标

    1    什么是游标: 关系数据库中的操作会对整个行集起作用. 例如,由 SELECT 语句返回的行集包括满足该语句的 WHERE 子句中条件的所有行. 这种由语句返回的完整行集称为结果集. 应用程序 ...

  6. 关于SVN配置文件的一个小例子

    1   背景假设 厦门央瞬公司是一家电子元器件设备供应商,其中有个ARM部门,专门负责ARM芯片的方案设计.销售,并在北京.上海各设立了一个办事处.对于工作日志,原先采用邮件方式发给经理,但是这种方式 ...

  7. Vue2.x源码学习笔记-从一个小例子查看vm实例生命周期

    学习任何一门框架,都不可能一股脑儿的从入口代码从上到下,把代码看完, 这样其实是很枯燥的,我想也很少有人这么干,或者这么干着干着可能干不下去了. 因为肯定很无聊. 我们先从一个最最简单的小例子,来查看 ...

  8. Spring和Hibernate结合的一个小例子

    1.新建一个SpringHibernate的maven项目 2.pom文件的依赖为 <dependency> <groupId>junit</groupId> &l ...

  9. Spring.Net在ASP.NET Mvc里使用的一个小例子

    就贴个小例子,就不注意格式了. 1.下载dll NuGet的下载地址:http://docs.nuget.org/docs/start-here/installing-nuget 在vs的NuGet里 ...

随机推荐

  1. Unity做AR

    Unity做AR呢这里借助了高通的AR包 这里是视频教程  http://www.tudou.com/programs/view/dnvEbIubNzI/ 这里是结果演示  http://www.tu ...

  2. centos7环境下安装mysql5.6-----解压安装包的方法

    参考连接:https://blog.csdn.net/qq_17776287/article/details/53536761 linux下有很多服务,如何查看服务是否启动,以mysql为例子 使用命 ...

  3. Kanboard简单的可视化任务板,项目管理

    采用docker安装 简单快捷 下载 docker pull kanboard/kanboard:latest 运行 docker run -d --name kanboard -p 10080:80 ...

  4. rabbitmq用户授权

    创建用户 rabbitmqctl add_user kye01 123456 设置用户角色 rabbitmqctl set_user_tags kye01 monitoring 查看用户清单 rabb ...

  5. KDevelop使用经验

    KDevelop中不显示行号: 1.上方菜单栏"编辑器"->查看->Show Line Numbers 2.设置->配置编辑器->Appearance-&g ...

  6. PHP7 学习笔记(十)会话控制

    防守打法 1.设置Cookie,[基于内存的Cookie] setcookie('Username','tinywan'); setcookie('Age','24'); 2.查看Cookie存储位置 ...

  7. I2C和SPI总线对比

    1 iic总线不是全双工,2根线SCL SDA.spi总线实现全双工,4根线SCK CS MOSI MISO 2 iic总线是多主机总线,通过SDA上的地址信息来锁定从设备.spi总线只有一个主设备, ...

  8. matplotlib-2D绘图库

    安装  python -m pip install matplotlib  允许中文: 使用matplotlib的字体管理器指定字体文件 plt.rcParams['font.sans-serif'] ...

  9. transition,过渡效果

    语法: transtion:property time change-speed delay. 人话就是:属性(property )在多少秒内(time )通过什么样的速度(change-speed) ...

  10. A - 地精部落 (DP)

    题目链接:https://cn.vjudge.net/contest/281960#problem/A 题目大意:中文题目. 具体思路:首先,如果有一段是山谷的话,那么这一段中也能用来表示山峰,只要将 ...