Jersey作为最开始的REST的参考,有很多项目偏好使用Jersey构建RestFul服务。CXF同样也能够构建REST服务,但是CXF最开始是作为实现SOAP的框架,比较完善,同时也相对重载,在REST构建上可能性能不如Jersey。
我最开始构建时是在原使用CXF的WebService工程中,想到这样需要引入的jar包相对较少(在使用CXF构建REST引入了一些CXF之外的包,如javax.ws.rs-api-2.1.jar,包含了@GET、@QueryParam等暴露服务时需要使用的注解)
1.使用Jersey1.x构建REST服务引入的Jersey包,如图:
在启动时没有报错,但是访问报错了:java.lang.AbstractMethodError: javax.ws.rs.core.UriBuilder.uri(Ljava/lang/String;)Ljavax/ws/rs/core/
经百度发现是UriBuilder类在javax.ws.rs-api-2.1.jar和jersey-bundle-{version}.jar中都有,而且路径都是javax.ws.rs.core,因此导致类加载冲突。解决方案,去掉javax.ws.rs-api-2.1.jar,重新启动项目,访问正常
Jersey1.x版本和2.x版本的变化较大,1.x版本的类路径基本是com.sun开头,而2.x版本以glassfish开头org.glassfish开头
注册服务
Jersey的服务注册主要有2种方式:
(1)按包去注册,使用默认的资源加载器加载,在定义Jersey的Servlet时param-name指定为jersey.config.server.provider.packages,而param-value为资源包的路径
(2)注册资源类,使用自定义的资源加载器加载,param-name为javax.ws.rs.Application,param-value为资源类路径
疑问:2种注册服务的方式各有什么优劣势和使用场景呢?实际项目中更推荐使用哪种方式?
2.使用Jersey2构建REST服务(不使用Spring)
手动引入jar包,经实测,这些包都不能少
web.xml配置
com.weijie.resource
资源类
package com.weijie.resource;
import com.weijie.service.impl.ExportExcel;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.FormParam;
import javax.ws.rs.core.MediaType;
import com.weijie.pojo.Test;
@Path("/resource")
public class Resource {
@GET
@Path("hello")
@Produces(MediaType.TEXT_PLAIN)
public String sayHello(@QueryParam("str")String str)
{
return new ExportExcel().hello(str);
}
@GET
@Path("test")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public String test(@QueryParam("name")String name,@QueryParam("value")String value)
{
String str ="This is " + name +",value is " + value;
return str;
}
@POST
@Path("form")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)//APPLICATION_FORM_URLENCODED
@Produces(MediaType.APPLICATION_JSON)
public Test writeSomething(@FormParam("value1")String value1,@FormParam("value2")String value2)
{
Test test =new Test();
test.setName(value1);
test.setValue(value2);
test.setNum((int)(Math.random()*100));
System.out.println(test.getNum());
return test;
}
@POST
@Path("form1")
@Consumes(MediaType.APPLICATION_JSON)//APPLICATION_FORM_URLENCODED
@Produces(MediaType.APPLICATION_JSON)
public Test writeSomething1(Test test)//使用@FormParam会报错,因为Jersey默认接受application/x-www-form-urlencoded参数
{
Test result =new Test();
result.setName(test.getName()+"1");
result.setValue(test.getValue()+"1");
result.setNum(test.getNum()+(int)(Math.random()*100));
return result;
}
}
POJO类
package com.weijie.pojo;
import java.io.Serializable;
public class Test implements Serializable{
/**
*
*/
private static final long serialVersionUID = 3486448853755783061L;
private String name;
private String value;
private int num;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
}
测试WADL,结构http://IP:port/项目名/Jersey的Servlet拦截的uri/application.wadl,最后面的application.wadl是不变的
Spring5.x+Jersey构建REST服务
web.xml
bean的配置(spring.xml)
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd">
POJO类
package com.weijie.pojo.export;
import java.io.Serializable;
public class ExportVO implements Serializable{
/**
*
*/
private static final long serialVersionUID = -2793236307669513041L;
private String appid;
private String report;
private String owner;
private Params[] params;
public String getAppid() {
return appid;
}
public void setAppid(String appid) {
this.appid = appid;
}
public String getReport() {
return report;
}
public void setReport(String report) {
this.report = report;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public Params[] getParams()
{
return params;
}
public void setParams(Params[] params)
{
this.params =params;
}
public static class Params implements Serializable
{
/**
*
*/
private static final long serialVersionUID = -3276814523885247312L;
private String key;
private Object value;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
}
这里使用了一个静态内部类,用于相对复杂一点的对象,可用于接受数组参数,针对一些场景需要识别自适应参数,方便扩展。对于参数较多的场景,也可以使用这种方式。
资源类:
package com.weijie.resource;
import com.weijie.service.api.IExportExcel;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
import javax.ws.rs.QueryParam;
import com.weijie.pojo.export.ExportVO;
import javax.ws.rs.FormParam;
//@Component
@Path("/resource")
public class ExportResource {
@Autowired
private IExportExcel export;
@Path("/hello")
@GET
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public String hello(@QueryParam("str")String str)
{
return export.hello(str);
}
@Path("/export")
@POST
@Consumes(MediaType.APPLICATION_JSON)//.APPLICATION_JSON
@Produces(MediaType.APPLICATION_JSON)
public String export(ExportVO expVO)
{
return export.export(expVO);
}
@Path("/export1")
@POST
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)//.APPLICATION_JSON
@Produces(MediaType.APPLICATION_JSON)
public String export1(@FormParam("appid")String appid,@FormParam("report")String report, @FormParam("owner")String owner)
{
ExportVO expVO =new ExportVO();
expVO.setAppid(appid);
expVO.setReport(report);
expVO.setOwner(owner);
return export.export(expVO);
}
}
接口:
package com.weijie.service.api;
import com.weijie.pojo.export.ExportVO;
public interface IExportExcel {
public String hello(String str);
public String export(ExportVO expVO);
}
实现类:
package com.weijie.service.impl;
import com.weijie.service.api.IExportExcel;
import com.weijie.pojo.export.ExportVO;
public class ExportExcel implements IExportExcel{
public String hello(String str)
{
return "hello "+str;
}
public String export(ExportVO expVO)
{
StringBuilder sb =new StringBuilder();
sb.append("appid:"+ expVO.getAppid()).append(",export:"+expVO.getReport()).append(",owner:"+expVO.getOwner());
return sb.toString()+Math.random()*100;
}
}
总结:Jersey是REST的参考实现,Jersey2相对于Jersey1在项目结构上有较大的变化。Jersey默认生成WADL