欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

深入了解JAVA Jersey框架

程序员文章站 2023-10-31 13:06:34
java jersey的详情概述jersey是一个restful请求服务java框架,与常规的java编程使用的struts框架类似,它主要用于处理业务逻辑层。与springmvc 的区别:1. je...

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的资料请关注其它相关文章!