文档章节

Java Jersey使用總結

空谷幽兰_
 空谷幽兰_
发布于 2013/08/14 10:26
字数 2172
阅读 15854
收藏 35
点赞 9
评论 13

关于作者

  • 马隆博(Lenbo Ma),Java,Javascript
  • Blog: http://mlongbo.com
  • E-Mail:mlongbo at gmail.com
  • 创建于:2013/07/26

转载请注明出处:

http://mlongbo.com/2015/Java Jersey2使用总结/


前言

在短信平台一期工作中,为便于移动平台的开发,使用了Java Jersey框架开发RESTFul风格的Web Service接口。在使用的过程中发现了一些问题并积累了一些经验。因此,做下总结备忘,同时也希望对有需要的同仁有好的借鉴和帮助。

简介

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下的库目录:

  • 服务器:jersey-server.jar 、jersey-container-servlet-core.jar、jersey-container-servlet.jar、javax.ws.rs-api-2.0.jar

  • 客户端:jersey-client.jar

  • common:jersey-common.jar

  • 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的注释。

  • 指定一个MIME类型

@Produces("application/json")

  • 指定多个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注释获取ServletConfigServletContextHttpServletRequestHttpServletResponseHttpHeaders等,如下:

@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

后记

本人在使用Jersey的过程中发现网上有关Jersey的中文资料并不多,因此将本期开发中的使用经验总结于此,便于同样对Jersey感兴趣的同仁参考。如果你也有Jersey的开发经验并且对Jersey拥有浓厚的兴趣,欢迎与我联系并一起探讨技术,愿共同进步!


扫描二维码,关注我。 内容大多会是后端技术、前端工程、DevOps,偶尔会有一些大数据相关,会推荐一些好玩的东西。希望你会喜欢~

扫描二维码关注我

© 著作权归作者所有

共有 人打赏支持
空谷幽兰_
粉丝 23
博文 26
码字总数 17072
作品 0
海淀
程序员
加载中

评论(13)

_Leo_
_Leo_
你好,如果我需要返回一个404 状态和json消息,怎么做呢?
空谷幽兰_
空谷幽兰_

引用来自“剑龙刀客”的评论

请问我前台有一个表单元素填写的是日期格式的字符串,怎么通过@BeanParam注解转为java.util.Date对象?
直接为Date类型字段加@FormParam字段不行?
剑龙刀客
请问我前台有一个表单元素填写的是日期格式的字符串,怎么通过@BeanParam注解转为java.util.Date对象?
奥西里斯
奥西里斯
楼主,我用Application的话,注册filter,怎么配置啊?Interceptor和filter类似么?
沙发迪
沙发迪
好东西,解决了我很多问题。
沧海龙啸
沧海龙啸
是的,那个问题已经搞定了。现在有个新问题,为什么org.glassfish.jersey.media.multipart这个包不在Jersey2.4.1的jar包里?我把Jersey官网上的bundle全部加到工程里了,但是没有这个包。结果Multipart用不成。
空谷幽兰_
空谷幽兰_

引用来自“沧海龙啸”的评论

引用来自“gfdsgfdstr”的评论

引用来自“沧海龙啸”的评论

我用的服务器Liberty

没用过Liberty,报什么错?

[警告 ] SRVE0274W: 为路径-->/*、包装器-->ServletWrapper[JAX-RS Servlet:[/*]]、应用程序-->Copy of Cloud_Modeler 添加 servlet 映射时出错。
后来我由查看了下,Description  Path  Resource  Location  Type
The servlet class 'com.sun.jersey.spi.container.servlet.ServletContainer' cannot be resolved  /11/WebContent/WEB-INF  web.xml  Servlet: Jersey Web Application  Web Problem
从这句看,貌似是ServletContainer缺少了依赖项,所以没法解析,进而导致了前边的映射错误。

你引入的ServletContainer包不对,com.sun.jersey是2.0以前的包
沧海龙啸
沧海龙啸

引用来自“gfdsgfdstr”的评论

引用来自“沧海龙啸”的评论

我用的服务器Liberty

没用过Liberty,报什么错?

[警告 ] SRVE0274W: 为路径-->/*、包装器-->ServletWrapper[JAX-RS Servlet:[/*]]、应用程序-->Copy of Cloud_Modeler 添加 servlet 映射时出错。
后来我由查看了下,Description  Path  Resource  Location  Type
The servlet class 'com.sun.jersey.spi.container.servlet.ServletContainer' cannot be resolved  /11/WebContent/WEB-INF  web.xml  Servlet: Jersey Web Application  Web Problem
从这句看,貌似是ServletContainer缺少了依赖项,所以没法解析,进而导致了前边的映射错误。
空谷幽兰_
空谷幽兰_

引用来自“沧海龙啸”的评论

我用的服务器Liberty

没用过Liberty,报什么错?
沧海龙啸
沧海龙啸
我用的服务器Liberty
Java就业变难了?你需要对自己有点信心

伴随着IT的火热,越来越多的人进入了IT领域,这在进一步推动着IT发展的同时也极大增加了就业压力。伴随着激烈的岗位竞争,越来越多的人开始感叹工作难找,越火的行业越是如此,Java自是首当其...

糖宝_d864 ⋅ 06/08 ⋅ 0

Oracle Java Mission Control 帮助

缩写 含义 JDK Java 开发工具包 JDP Java Discovery Protocol JFR Java 飞行记录器 JMC Java Mission Control JMX Java Management Extensions JVM Java 虚拟机 MBean 托管 Bean (Java) RCP ......

光斑 ⋅ 04/27 ⋅ 0

MVN package install error javac: invalid target release: 1.8

现象: --------------------------------- [ERROR] Failure executing javac, but could not parse the error: javac: invalid target release: 1.8 Usage: javac <options> <source files>......

孟飞阳 ⋅ 05/04 ⋅ 0

sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer ⋅ 05/03 ⋅ 0

培训云计算学校,虚拟机基本结构讲解

我们要对JVM虚拟机的结构有一个感性的认知。毕竟我们不是编程人员,认知程度达不到那么深入。一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序时,一个虚拟机...

长沙千锋 ⋅ 05/17 ⋅ 0

云计算高级培训,Tomcat运维JVM 虚拟机常识

云计算高级培训,Tomcat运维JVM 虚拟机常识,作为了解JVM 虚拟机的开始。我们很有必要弄明白以下问题。 所谓虚拟机,就是一台虚拟的计算机。他是一款软件,用来执行一系列虚拟计算机指令。大...

长沙千锋 ⋅ 05/17 ⋅ 0

重磅!Java 性能监控调试工具 JMC 宣布开源

JRockit JVM 创始人之一、Oracle Java 产品组成员 Marcus Hirt 昨日在其博客上宣布,Java Mission Control(JMC)的源代码已正式开源。 JMC 是源自 JRockit JVM 的一套监控和管理工具,Oracl...

王练 ⋅ 05/07 ⋅ 6

甲骨文开源Java 性能监控调试工具 JMC

JMC (Java Mission Control) 是Oracle开源的Java 性能监控调试工具, 源自 JRockit JVM , 主要由三个组件构成:Java 进程浏览器、JMX 控制台和 Java Flight 记录器。 主要特性: Java 进程浏览...

marsdream ⋅ 05/07 ⋅ 0

Groovy 2018 Roadmap:下一步主打 lambda 和模块化

JVM 动态脚本语言 Groovy 在 5 月底发布了最新的 2.5 版本, 最大的亮点是对宏的支持,允许开发者在创建 compile-time 元编程扩展时直接使用 Groovy 语法,而不是使用内部编译器表示。 Apac...

王练 ⋅ 06/07 ⋅ 0

Oracle Java SE 8 发行版更新:限制商业或生产用途

Oracle Java SE 8 发行版更新 Oracle Java SE 8 的公开更新仍面向单独的个人使用提供,至少持续至 2020 年底。 2019 年 1 月以后发布的 Oracle Java SE 8 公开更新将不向没有商用许可证的业务...

抢小孩糖吃 ⋅ 04/18 ⋅ 39

没有更多内容

加载失败,请刷新页面

加载更多

下一页

Mahout推荐算法API详解

前言 用Mahout来构建推荐系统,是一件既简单又困难的事情。简单是因为Mahout完整地封装了“协同过滤”算法,并实现了并行化,提供非常简单的API接口;困难是因为我们不了解算法细节,很难去根...

xiaomin0322 ⋅ 19分钟前 ⋅ 0

WampServer默认web服务器根目录位置

安装WampServer之后的web服务器根目录默认位置在WampServer安装目录下的www:

临江仙卜算子 ⋅ 20分钟前 ⋅ 0

Redux的一些手法记录

Redux Redux的基本概念见另一篇文。 这里记录一下Redux在项目中的实际操作的手法。 actions 首先定义action.js,actions的type,可以另起一个action-type.js文件。 action-type.js用来存...

LinearLaw ⋅ 21分钟前 ⋅ 0

android 手势检测(左右滑动、上下滑动)

GestureDetector类可以让我们快速的处理手势事件,如点击,滑动等。 使用GestureDetector分三步: 1. 定义GestureDetector类 2. 初始化手势类,同时设置手势监听 3. 将touch事件交给gesture...

王先森oO ⋅ 35分钟前 ⋅ 0

java 方法的执行时间监控 设置超时(Future 接口)

java 方法的执行时间监控 设置超时(Future 接口) import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor......

青峰Jun19er ⋅ 40分钟前 ⋅ 0

一名开源小白的Apache成长自述

今天收到了来自Apache Vote我成为Serviceomb项目Committer的邮件,代表自己的贡献得到了充分的肯定;除了感谢团队的给力支持,我更希望将自己的成长经历——如何践行Apache Way的心得介绍给大...

微服务框架 ⋅ 42分钟前 ⋅ 0

vim介绍、颜色显示和移动光标、一般模式下复制、剪切和粘贴

1.vim 是 vi 的升级版 vim 是带有颜色显示的 mini安装的系统,一般都不带有vim [root@aminglinux-128 ~]# yum install -y vim-enhanced已加载插件:fastestmirror, langpacksLoading mir...

oschina130111 ⋅ 42分钟前 ⋅ 0

Deepin 操作系统四面楚歌

作为国内做的最好的 Linux 发行版,源自 Debian sid 的 Deepin 目前正面临重重困境,新版本不断延期,开发人员离职,bug 长期得不到修复,和 Debian/Ubuntu 的兼容性问题也面临越来越严重的挑...

六库科技 ⋅ 43分钟前 ⋅ 0

MyBatis之动态sql

我们需要知道的是,使用mybatis重点是对sql的灵活解析和处理。在原先的UserMappser.xml中,我们这样查询表中满足条件的记录 : 123 <select id="findUserList" parameterType="userQuery...

瑟青豆 ⋅ 43分钟前 ⋅ 0

这届俄罗斯世界杯的冷门那么多怎么办?

最纯粹的世界杯,最神奇的大冷门。 德国0比1被墨西哥摩擦了。 日本历史性的赢了哥伦比亚。 C罗也挑平了西班牙。 梅西被冰岛狮吼吼愣神了。 就连11次进世界杯4强的巴西也被瑞士逼平了。 天台已...

开源中国众包平台 ⋅ 44分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部