深入了解JAVA Jersey框架
java jersey的详情概述
jersey是一个restful请求服务java框架,与常规的java编程使用的struts框架类似,它主要用于处理业务逻辑层。
与springmvc 的区别:
1. jersey同样提供di,是由glassfish hk2实现,也就是说,如果想单独使用jersey一套,需要另外学习bean容器;
2. mvc出发点即是web,但jersey出发点确实restfull,体现点在与接口的设计方面,
如mvc返回复杂结构需要使用modelandview,而jersey仅仅需要返回一个流或者文件句柄;
3. jersey提供一种子资源的概念,这也是restfull中提倡所有url都是资源;
4. jersey直接提供application.wadl资源url说明;
5. mvc提供session等状态管理,jersey没有,这个源自restfull设计无状态化;
6. response方法支持更好返回结果,方便的返回status,包括200,303,401,403;
7. 提供超级特别方便的方式访问restfull;
jersey
1.x的版本是sun公司提供的独立的jar包,在2.x版本中,已经将jersey融合到javase中,在javax.ws.rs.*包中。
与struts类似,它同样可以和hibernate,spring框架整合。
由于struts2+hibernate+spring整合在市场的占有率太高,所以很少一部分人去关注jersey。
所以网上有关于jersey的介绍很少。但是它确实是一个非常不错的框架。对于请求式服务,对于get,delete请求,你甚至只需要给出一个uri即可完成操作。
举个简单的例子:如果你想获得服务器数据库中的所有数据;
那么你可以在浏览器或者利用ajax的get方法,将路径设置好;
例如:localhost:8080/student(项目名称)/studentinfo(项目服务总体前缀)/student(处理student对象的签注)/getstudentinfo(最后前缀)。
你可以选择get获取的数据的返回类型:json,xml,text_html(string)..获取之后,你可以通过js将这些数据塞到html或者jsp页面上。
jersey是jax-rs(jsr311)开源参考实现用于构建 restful web service,它包含三个部分:
核心服务器(core server) :通过提供jsr 311中标准化的注释和api标准化,可以用直观的方式开发restful web服务。
核心客户端(core client) :jersey客户端api能够帮助开发者与restful服务轻松通信;
集成(integration) :jersey还提供可以轻松继承spring、guice、apache abdera的库。
在本次开发中使用jersey2.0,并且仅使用了核心服务器。
设置jersey环境
maven
<!--jersey--> <dependency> <groupid>org.glassfish.jersey.containers</groupid> <artifactid>jersey-container-servlet-core</artifactid> <version>2.0</version> </dependency> <!--jaxb api--> <dependency> <groupid>javax.xml.ws</groupid> <artifactid>jaxws-api</artifactid> <version>2.1</version> </dependency> <!-- json支持 --> <dependency> <groupid>org.codehaus.jackson</groupid> <artifactid>jackson-core-asl</artifactid> <version>1.9.12</version> </dependency> <dependency> <groupid>org.codehaus.jackson</groupid> <artifactid>jackson-mapper-asl</artifactid> <version>1.9.12</version> </dependency> <dependency> <groupid>org.codehaus.jackson</groupid> <artifactid>jackson-jaxrs</artifactid> <version>1.9.12</version> </dependency>
引入jar文件方式
从jersey开发包中将以下库复制的web-inf下的库目录:
1 服务器:jersey-server.jar 、jersey-container-servlet-core.jar、jersey-container-servlet.jar、javax.ws.rs-api-2.0.jar
2 客户端:jersey-client.jar
3 common:jersey-common.jar
4 json支持:在jersey2.0中需要使用 jackson1.9 才能支持json。
hello world
以下将展示一个hello world
第一步: 编写一个名为helloresource的资源,它接受http get请求并响应“hello jersey”
@path("/hello") public class helloresource { @get @produces(mediatype.text_plain) public string sayhello() { return "hello jersey"; } }
第二步: 编写jax-rs application
public class apiapplication extends resourceconfig { public apiapplication() { //加载resource register(helloresource.class); //注册数据转换器 register(jacksonjsonprovider.class); // logging. register(loggingfilter.class); } }
第三步: 在web.xml文件中定义servelt调度程序,目的是将所有rest请求发送到jersey容器。除了声明jersey servlet外,还需定义一个初始化参数,指定jax-rs application。
<!--用于定义 restful web service 接口--> <servlet> <servlet-name>jerseyservlet</servlet-name> <servlet-class>org.glassfish.jersey.servlet.servletcontainer</servlet-class> <init-param> <param-name>javax.ws.rs.application</param-name> <param-value>cn.com.mink.resource.apiapplication</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>jerseyservlet</servlet-name> <url-pattern>/services/*</url-pattern> </servlet-mapping>
在命令终端中输入以下命令,将会看到“hello jersey”。
curl http://host:port/services/hello
或者在浏览器中输入以下url,将会看到“hello jersey”
http://host:port/services/hello
使用
资源
root resource and sub-resource
资源是组成restful服务的关键部分,可以使用http方法(如:get、post、put和delete)操作资源。在jax-rx中,资源通过pojo实现,使用 @path 注释组成其标识符。资源可以有子资源,父资源是资源集合,子资源是成员资源。
在以下样例代码中,
resources是"/services" uri组成是集合资源,userresource是“/services/user” uri组成的成员资源;
@path("/services") public class resources { @path("/user") public userresource getuserresource() { ... } @path("/book") public bookresource getbookresource() { ... } }
userresource是“/user” uri组成的集合资源,getuser是“/user/{username}” uri组成的资源方法
@path("/user") public class userresource { @get @path("{username"}) @produces("application/json") public user getuser(@pathparam("username") string username) { ... } }
http methods
http方法映射到资源的crud(创建、读取、更新和删除)操作,基本模式如下:
http get :读取/列出/检索单个或资源集合。
http post :新建资源。
http put :更新现有资源或资源集合。
http delete :删除资源或资源集合。
@produces
@produces 注释用来指定将要返回给client端的数据标识类型(mime)。@produces 可以作为class注释,也可以作为方法注释,方法的 @produces 注释将会覆盖class的注释。
1 指定一个mime类型
@produces("application/json")
2 指定多个mime类型
@produces({"application/json","application/xml"})
@consumes
@consumes 与 @produces 相反,用来指定可以接受client发送过来的mime类型,同样可以用于class或者method,也可以指定多个mime类型,一般用于 @put ,@post 。
参数(parameter annotations)
parameter annotations用于获取client发送的数据。本文只介绍常用的注解,更多详见 jersey用户手册
@pathparam
使用 @pathparam 可以获取uri中指定规则的参数,比如:
@get @path("{username"}) @produces(mediatype.application_json) public user getuser(@pathparam("username") string username) { ... }
当浏览器请求 http://localhost/user/jack 时,username值为jack。
@queryparam
@queryparam 用于获取get请求中的查询参数,如:
@get @path("/user") @produces("text/plain") public user getuser(@queryparam("name") string name, @queryparam("age") int age) { ... }
当浏览器请求 http://host:port/user?name=rose&age=25 时,name值为rose,age值为25。如果需要为参数设置默认值,可以使用 @defaultvalue ,如:
@get @path("/user") @produces("text/plain") public user getuser(@queryparam("name") string name, @defaultvalue("26") @queryparam("age") int age) { ... }
当浏览器请求 http://host:port/user?name=rose 时,name值为rose,age值为26。
@formparam
@formparam ,顾名思义,从post请求的表单参数中获取数据。如:
@post @consumes("application/x-www-form-urlencoded") public void post(@formparam("name") string name) { // store the message }
@beanparam
当请求参数很多时,比如客户端提交一个修改用户的put请求,请求中包含很多项用户信息。这时可以用 @beanparam 。
@post @consumes("application/x-www-form-urlencoded") public void update(@beanparam user user) { // store the user data }
user bean定义如下:
@xmlrootelement(name = "user") public class user { @pathparam("username) private string username; @formparam("name") private string name; @formparam("telephone") private string telephone; @formparam("email") private string email; public string getusername() { return username; } public void setusername(string username) { this.username = username; } ... }
使用map
在一个大型的server中,因为参数的多变,参数结构的调整都会因为以上几种方式而遇到问题,这时可以考虑使用 @context 注释,并获取uriinfo实例,如下:
@get public string get(@context uriinfo ui) { multivaluedmap<string, string> queryparams = ui.getqueryparameters(); multivaluedmap<string, string> pathparams = ui.getpathparameters(); }
同样还可以通过 @context 注释获取 servletconfig 、 servletcontext 、httpservletrequest 、 httpservletresponse 和 httpheaders 等,如下:
@path("/") public class resource { @context httpservletrequest req; @context servletconfig servletconfig; @context servletcontext servletcontext; @get public string get(@context httpheaders hh) { multivaluedmap<string, string> headerparams = hh.getrequestheaders(); map<string, cookie> pathparams = hh.getcookies(); } }
jersey返回json和xml
jax-rs支持使用jaxb(java api for xml binding)将javabean绑定到xml或json,反之亦然。javabean必须使用 @xmlrootelement 标注,没有@xmlelement 注释的字段将包含一个名称与之相同的xml元素,如下:
@xmlrootelement public class optionresult { @xmlelement(name = "code") private string result; private string errormsg; public string getresult() { return result; } public void setresult(string result) { this.result = result; } public string geterrormsg() { return errormsg; } public void seterrormsg(string errormsg) { this.errormsg = errormsg; } }
然后在rest服务中使用:
@path("/user") public class userresource { @post @produces("application/json") public optionresult create(@beanparam user user) { ... } }
最后,要注册数据转换器,该转换器会自动将javabean转换为json数据:
public class apiapplication extends resourceconfig { public apiapplication() { //加载model register(optionresult.class); //加载与optionresult同一个packge的model //packages(optionresult.class.getpackage().getname()); //加载resource register(userresource.class); //注册数据转换器 register(jacksonjsonprovider.class); // logging. register(loggingfilter.class); } }
说明 :返回xml数据的原理相同,仅仅是数据转换器不同,只需要在apiapplication中同时注册xml数据转换器即可,详见 jersey用户手册
问题总结
ajax请求(post、put和delete)无法将数据提交到jersey容器
问题阐述
在短信平台的开发中,数据的crud全部使用ajax技术完成,因此必须使用post、put和delete请求。此三种请求的content-type均为“application/x-www-form-urlencoded”,使用utf-8编码会变成“application/x-www-form-urlencoded; utf-8”。在使用firefox的tamperdata扩展调试程序的过程中发现,当content-type为“application/x-www-form-urlencoded”时,jersey容器能够通过 @formparam 注解获取到提交的数据,而content-type为“application/x-www-form-urlencoded; utf-8”时便获取不到。
解决方案
最终我使用java filter和jersey requestfilter解决了问题。首先在java filter中使用utf8将request中的数据编码,然后在jersey requestfilter中将request对象中的content-type修改为“application/x-www-form-urlencoded”。如:
public void dofilter(servletrequest request, servletresponse response, filterchain chain) throws ioexception, servletexception { httpservletrequest req = (httpservletrequest)request; req.setcharacterencoding("utf-8"); } public class requestfilter implements containerrequestfilter { @override public void filter(containerrequestcontext context) throws ioexception { string headerstring = context.getheaderstring("content-type"); if (headerstring != null) { //如果content-type以"application/x-www-form-urlencoded"开头,则处理 if (headerstring.startswith(mediatype.application_form_urlencoded)) context.getheaders().putsingle("content-type", mediatype.application_form_urlencoded); } } }
最后在web.xml中注册java filter(要注册在jersey容器之前),在apiapplication中注册jersey requestfilter,如下:
public class apiapplication extends resourceconfig { public apiapplication() { register(requestfilter.class); } }
说明 :在修复此问题后,在github的jersey源代码仓库中看到已经有人发现并修复了此问题,在下个jersey正式版本中应该不会再出现这样的问题,详见 此discussion
以上就是深入了解java jersey的详细内容,更多关于java jersey的资料请关注其它相关文章!
上一篇: 吃什么食物对贫血有好处
下一篇: 详解JAVA中接口的定义和接口的实现