JAX-RS2
JAX-RS2标准定义的元素:
- 资源类:使用JAX-RS注解来实现相关Web资源的Java类。
- 根资源类:使用@Path注解,提供资源类树的根资源以及子资源的访问。资源类分为根资源类和子资源类,由于Jersey默认提供WADL,每个应用公布的全部资源接口可以通过WADL页面查阅。
- 请求方法标识符:请求方法标识符:使用运行期注解@HttpMethod,用来标识处理资源的HTTP请求方法。该方法将使用资源类的相应方法处理,标准的方法包括DELETE、GET、HEAD、OPTIONS、POST、PUT。
- 资源方法:资源类中定义的方法使用了请求方法标识符,用来处理相关资源的请求。
- 子资源标识符:资源类中定义的方法,用来定位相关资源的子资源。
- 子资源方法:资源类中定义的方法,用来处理相关资源的子资源的请求。
- Provider:一种JAX-RS扩展接口的实现类,扩展了JAX-RS运行期的能力。
- Filter:一种用于过滤请求和响应的Provider。
- Entity Interceptor:一种用于处理拦截消息读写的Provider。
- Invocation:一种用于配置发布HTTP请求的客户端API对象。
- WebTarget:一种使用URI标识deInvocation容器对象。
- Link:一种携带元数据的URI,包括媒体类型、关系和标题等。
1、资源路径
1.1、@ApplicationPath
该注解用于声明Jersey的全局配置类,也即整个Jersey框架的程序入口。该类需要满足下面条件:
- @ApplicationPath注解该类,并且指定该类对应的路径
- 继承 org.glassfish.jersey.server.ResourceConfig 类
- 在该类中配置Jersey的配置,例如声明资源包路径,配置拦截器等。
@ApplicationPath("/ws")
public class JerseyConfig extends ResourceConfig {
public JerseyConfig() {
//注册单个资源类
// register(DemoResource.class);
//或直接声明资源包所在位置
packages("pers.zhang.resource");
}
}
1.2、@Path
JAX-RS2定义了@Path注解来定义根资源路径,@Path接收一个字符串value参数来解析资源路径地址。属性可以是文本字符、变量或变量外加一个定制的正则表达式。
使用方式:
- 静态:直接写路径
- 动态:配置@PathParam注解动态解析
@Path("hi")
public class DemoResource {
@GET
@Produces("application/json")
public List<String> hi() {
List<String> result = new ArrayList<>();
result.add("hello world");
result.add("hello Jersey");
return result;
}
}
2、请求方法
JAX-RS2的HTTP方法注解包括:
- @GET
- @PUT
- @DELETE
- @POST
- WebDAV扩展方法
注意:JAX-RS2的HTTP方法注解可以定义在接口和POJO中,置于接口中的方法名更具抽象性和通用性。
2.1、@GET
HTTP的GET方法用于读取资源。GET方法是幂等的,因为读取同一个资源,总是得到相同的数据。GET方法也是安全的,因为读取资源不会对其状态做改动。JAX-RS2定义了@GET
注解对资源方法定义,使得该方法用于处理GET请求。
@Path("book")//定义在接口
public interface BookResource {
@GET//定义在接口
public String getWeight();
}
public class BookResourceImpl implements BookResource {
//实现类无需@GET注解
@Override
public String getWeight() {
return "150M";
}
}
//注意,加载的是实现类,而不是接口
register(BookResourceImpl.class);
测试:
@Test
public void testGet() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/book");
Response response = webTarget.request().get();
System.out.println(response.readEntity(String.class));
}
2.2、@PUT
PUT方法是一种写操作的HTTP请求。REST使用HTTP的PUT方法更新或添加资源。
PUT方法是幂等的,即多次插入或者更新同一份数据,
在服务器端对资源状态所产生的改变是相同的。PUT方法不是安全的,有写动作的HTTP方法都不是安全的。
@Path("book")//定义在接口
public interface BookResource {
@PUT
@Produces(MediaType.TEXT_PLAIN)
@Consumes(MediaType.APPLICATION_XML)
public String newBook(Book book);
}
public class BookResourceImpl implements BookResource {
@Override
public String newBook(Book book) {
return book.toString();
}
}
实体类:
@XmlRootElement
public class Book implements Serializable {
private Long id;
private String name;
private Double price;
public Book() {
}
public Book(Long id, String name, Double price) {
this.id = id;
this.name = name;
this.price = price;
}
@XmlElement(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@XmlElement(name = "price")
public Double getPrice() {
return price;
}
public void setPrice(Double price) {
this.price = price;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", price=" + price +
'}';
}
}
测试:
@Test
public void testPut() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/book");
Book book = new Book(1001l, "xxxxx", 11.11);
Entity<Book> bookEntity = Entity.entity(book, MediaType.APPLICATION_XML);
Response response = webTarget.request(MediaType.TEXT_PLAIN_TYPE).put(bookEntity);
System.out.println(response.readEntity(String.class));
}
2.3、@DELETE
DELETE方法是幂等的,即多次删除同一份数据(通常请求中传递的参数是数据的主键值),在服务器端产生的改变是相同的。JAX-RS2定义了@DELETE注解来定义相关资源方法。
@Path("book")//定义在接口
public interface BookResource {
@DELETE
public void delete(@QueryParam("bookId") long bookId);
}
public class BookResourceImpl implements BookResource {
@Override
public void delete(long bookId) {
System.out.println(bookId);
}
}
@Test
public void testDelete() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/book");
Response response = webTarget.queryParam("bookId", "1001").request().delete();
System.out.println(response.getStatus());
}
2.4、@POST
POST方法是一种写操作的HTTP请求。RPC的所有写操作均使用POST方法,而REST只使用HTTP的POST方法添加资源。
定义为POST的REST接口用于写数据,POST方法的特性是既不幂等也不安全。由于请求会改变服务器端资源的状态,因此它是不是安全的;由于每次请求对服务器端资源状态的改变并不是相同的,因此它不是幂等的。
@Path("book")//定义在接口
public interface BookResource {
@POST
@Produces(MediaType.APPLICATION_XML)
@Consumes(MediaType.APPLICATION_XML)
public Book createBook(Book book);
}
public class BookResourceImpl implements BookResource {
@Override
public Book createBook(Book book) {
book.setId(System.currentTimeMillis());
return book;
}
}
@Test
public void testPost() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/book");
Book book = new Book();
book.setName("XXXXXX");
book.setPrice(44.44);
Entity<Book> bookEntity = Entity.entity(book, MediaType.APPLICATION_XML_TYPE);
Response response = webTarget.request(MediaType.APPLICATION_XML_TYPE).post(bookEntity);
System.out.println(response.readEntity(Book.class));
}
Book{id=1703407159663, name='XXXXXX', price=44.44}
2.5、WebDAV扩展方法
WebDAV(Web-based Distributed Authoring and Versioning,基于Web的分布式创作与版本控制)是IETF的RFC4918规范,是对HTTP1.1协议的一组扩展,该协议允许用户以协作方式编辑和管理远程Web服务器上的文件。WebDAV在HTTP方法的基础上,增加了如下方法:
- PROPFIND方法:用于原子的更改和删除一个资源的多个属性。
- PROPPATCH方法:用于原子地更改和删除一个资源的多个属性。
- MKCOL方法:用于创建目录。
- COPY方法:用于将资源从一个URI资源地址复制到另一个URI资源地址。
- MOVE方法:用于将资源从一个URI资源地址 移动到另一个URI资源地址。
- LOCK方法:用于锁定一个资源。WebDAV支持共享锁和独占锁。
- UNLOCK方法:用于解锁一个资源。
虽然WebDAV对HTTP方法做出了功能性扩展,使之提供更强大服务,但是从ROA角度讲,因为WebDAV在HTTP标准方法的基础上增加了特殊的方法名称,WebDAV破坏了统一接口的原则。因此,对是否应该在REST式的Wb服务中支持WebDAV,业内的观点并不一致。
如果遵从ROA,那么就不使用HTTP标准方法之外的方法。如果业务需求确实超出了标准方法所及,那么可以使用如下注解实现对WebDAV的支持。JAX-RS2规范没有阐述对WebDAV提供支持的文字,但是JAX-RS2定义了@HttpMethod
注解来定义相关的资源方法。在Jersey应用中,可以使用@HttpMethod注解定义HTTP标准方法之外的方法名称来支持WebDAV,示例代码如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@HttpMethod(value = "MOVE")
@Documented
public @interface MOVE {
}
3、资源定位(参数传递)
资源地址的路径变量是用来表达逻辑上的层次结构的,资源和子资源的形式是自左至右、斜杠分割的名词。它们的关系可以是从整体到局部,比如学校到班级,城市到乡镇;也可以是从一般到具体,比如一个生物的“门、纲、目、科、属、种”的资源路径。资源地址具体可以分为5个部分,以scheme:/host:port/path?queryString
为例:
元素 | 描述 |
---|---|
scheme | 协议名称,通常是HTTP和HTTPS |
host | (DNS)主机名称或者IP地址 |
port | 服务端口 |
path | 资源地址,使用"/"符号来分割逻辑上的层次结构 |
? | 用来分割资源地址和查询字符串符号 |
queryString | 查询字符串,方法作用域信息 使用"&"符号分割查询条件 使用逗号分隔有次序的作用域信息 使用分号分隔无次序的作用域信息 |
通常使用ContextPath、ServletPath和PathInfo来细分资源地址。ContextPath是上下文名称,通常和部署服务器的配置或者REST服务的web.xml配置有关。ServletPath是Servlet的名称,与REST服务中定义的@ApplicationPath注解或者web.xml的配置有关。
JAX-RS2定义了@Path注解来定义资源地址。PathInfo是资源路径信息,与资源类、子类以及类中的方法定义的@Path注解有关。
3.1、@QueryParam
查询条件决定了方法的作用域,查询参数组成了查询条件。JAX-RS2定义了@QueryParam注解来定义查询参数。
/**
* 对应:http://localhost:8080/ws/test?start=10&size=20
*/
@GET
public void test1(@QueryParam("start")int start, @QueryParam("size") int size) {
System.out.println(start);
System.out.println(size);
}
3.2、@DefaultValue
@DefaultValue的作用是预置一个默认值,当请求中不包含此参数时使用,示例如下:
/**
* 对应:http://localhost:8080/ws/test?id=1
* @DefaultValue指定默认值100
*/
@POST
public void test2(@DefaultValue("100") @QueryParam("id") int id) {
System.out.println(id);
}
3.3、@PathParam
JAX-RS2定义了@PathParam注解来定义路径参数,每个参数对应一个子资源。
JAX-RS2定义了@Path注解来定义资源路径,@Path接收一个value参数来解析资源路径地址。该参数除了前面示例中的静态定义的方式外,也可以使用动态变量的方式,其格式为:{参数名:正则表达式}
。
1)、正则匹配
/**
* from和to定义查询区间,\d+ 正则匹配数字,- 表示连接符
* 匹配路径形如:http://localhost:8080/ws/test/111-999
*/
@GET
@Path("{from:\\d+}-{to:\\d+}")
public void test3(@PathParam("from")int from, @PathParam("to") int to) {
System.out.println(from);
System.out.println(to);
}
/**
* 匹配路径形如:http://localhost:8080/ws/test/1,2000-12,2020
*/
@GET
@Path("{beginMonth:\\d+},{beginYear:\\d+}-{endMonth:\\d+},{endYear:\\d+}")
public void test4(@PathParam("beginMonth") int beginMonth, @PathParam("beginYear") int beginYear,
@PathParam("endMonth") int endMonth, @PathParam("endYear") int endYear) {
System.out.println(beginMonth + "," + beginYear + "-" + endMonth + "," + endYear);
}
2)、路径配查询
查询参数和路径参数在一个接口中配合使用,可以更便捷地完成资源定位:
/**
* 匹配路径形如:http://localhost:8080/ws/test/tom?hometown=ChangSha
* return tom:ChangSha
*/
@GET
@Path("{user:[a-zA-Z][a-zA-Z_0-9]*}")
public String getUserInfo(@PathParam("user") String user,
@DefaultValue("BeiJing") @QueryParam("hometown") String hometown) {
return user + ":" + hometown;
}
3)、路径区间
路径区间(PathSegment)是对资源地址更灵活的支持,使资源类的一个方法可以支持更广泛的资源地址的请求。
/**
* 匹配路径形如:http://localhost:8080/ws/test/Asia/China/northeast/liaoning/shenyang/tiexi
* return Asia-China-northeast-liaoning-shenyang-tiexi
*/
@GET
@Path("{region:.+}/shenyang/{district:\\w+}")
public String getByAddress(@PathParam("region")List<PathSegment> region,
@PathParam("district") String district) {
StringBuilder result = new StringBuilder();
for (PathSegment pathSegment :region) {
result.append(pathSegment.getPath()).append("-");
}
result.append("shenyang-" + district);
return result.toString();
}
在这段代码中,getByAddress()方法用来匹配表的这些资源地址。该方法的region变量是PathSegment类型的数组,以匹配至少出现一个字符的正则表达式(+)。PathSegment如其名字所示,是路径的片段,是子资源的集合。遍历PathSegment集合,对于每一个PathSegment实例,可以通过调用其getPath()方法获取子资源名称。
/**
* 匹配路径形如:http://localhost:8080/ws/test/q/restful;name=tom;age=18;height=177
* restful是自定义前缀,可以用condition.getPath()获取。后续参数用 ; 分隔
* return name=[tom] age=[18] height=[177]
*/
@GET
@Path("q/{condition}")
public String getByCondition(@PathParam("condition") PathSegment condition) {
StringBuilder conds = new StringBuilder();
MultivaluedMap<String, String> matrixParameters = condition.getMatrixParameters();
System.out.println(matrixParameters);
Iterator<Map.Entry<String, List<String>>> it = matrixParameters.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<String, List<String>> entry = it.next();
conds.append(entry.getKey()).append("=");
conds.append(entry.getValue()).append(" ");
}
return conds.toString();
}
在这段代码中,getByCondition()方法只有一个PathSegment类型的参数condition,该参数包含了查询条件中携带的全部参数列表。举例来说,资源地址为http://localhost:8080/ws/test/q/restful;name=tom;age=18;height=177
的请求可以匹配到getByCondition()方法,其中,
MultivaluedMap类型的实例matrixParameters的值为[name=[tom],age=[18],height=[177]]
。
3.4、@MatrixParam
@MatrixParam注解通过声明方式来获取参数。
/**
* 匹配路径形如:http://localhost:8080/ws/test/q2/restful;name=tom;age=18;height=177
* return restful name=tom age=18 height=177
*/
@GET
@Path("q2/{condition}")
public String getByCondition2(@PathParam("condition") PathSegment condition,
@MatrixParam("name") String name,
@MatrixParam("age") Integer age,
@MatrixParam("height") Integer height) {
return condition.getPath() + " name=" + name + " age=" + age + " height=" + height;
}
3.5、@FormParam
JAX-RS2定义了@FormParam注解来定义表单参数,相应的REST方法用以处理请求实体媒体类型为Content-Type:application/x-www-form-urlencoded
的请求。
@Path("form")
public class FormResource {
@POST
public String newBook( @FormParam("name") String name,
@DefaultValue("22.22") @FormParam("price") Double price) {
Book book = new Book(System.currentTimeMillis(), name, price);
System.out.println(book);
return book.toString();
}
}
PostMan请求:
客户端测试:
@Test
public void testPostForm() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/form");
Form form = new Form();
form.param("name", "tom");
form.param("price", "22.22");
Response response = webTarget.request()
.post(Entity.entity(form, MediaType.APPLICATION_FORM_URLENCODED_TYPE));
System.out.println(response.readEntity(String.class));
}
Book{id=1703429235282, name='tom', price=22.22}
3.6、@Encoded
禁用对使用@QueryParam
、@PathParam
、@FormParam
或@MatrixParam
绑定的参数值的自动解码。
- 在方法上使用此注释将禁用所有参数的解码。
- 在类上使用此注释将禁用所有方法的所有参数的解码。
@POST
public String newBook( @Encoded @FormParam("name") String name,
@DefaultValue("22.22") @FormParam("price") Double price) {
Book book = new Book(System.currentTimeMillis(), name, price);
System.out.println(book);
return book.toString();
}
3.7、@BeanParam
JAX-RS2定义了@BeanParam注解用于自定义参数组合,使REST方法可以使用简洁的参数形式完成复杂的接口设计。
@GET
@Path("{region:.+}/shenyang/{district:\\w+}")
public String getByAddress(@BeanParam MyParam param) {
System.out.println(param);
return param.toString();
}
//自定义复杂参数Bean
public class MyParam {
//将HTTP标头的值绑定到资源方法参数
@HeaderParam("accept")
private String accept;
@PathParam("region")
private String region;
@PathParam("district")
private String district;
@QueryParam("station")
private String station;
@QueryParam("vehicle")
private String vehicle;
public String getAccept() {
return accept;
}
public void setAccept(String accept) {
this.accept = accept;
}
public String getRegion() {
return region;
}
public void setRegion(String region) {
this.region = region;
}
public String getDistrict() {
return district;
}
public void setDistrict(String district) {
this.district = district;
}
public String getStation() {
return station;
}
public void setStation(String station) {
this.station = station;
}
public String getVehicle() {
return vehicle;
}
public void setVehicle(String vehicle) {
this.vehicle = vehicle;
}
@Override
public String toString() {
return "MyParam{" +
"accept='" + accept + '\'' +
", region='" + region + '\'' +
", district='" + district + '\'' +
", station='" + station + '\'' +
", vehicle='" + vehicle + '\'' +
'}';
}
}
PostMan测试:
客户端测试:
@Test
public void testMyParam() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/form");
Response response = webTarget.path("China").path("shenyang").path("tiexi")
.queryParam("station", "Workers+Village").queryParam("vehicle", "bus")
.request().get();
System.out.println(response.readEntity(String.class));
}
MyParam{accept='text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2', region='China', district='tiexi', station='Workers+Village', vehicle='bus'}
3.8、@CookieParam
JAX-RS2定义了@CookieParam注解用以匹配Cookie中的键值对信息。
@GET
public String getHeaderParams(@CookieParam("longitude") String longitude,
@CookieParam("latitude") String latitude,
@CookieParam("population") double population,
@CookieParam("area") int area) {
return longitude + "," + latitude + " population=" + population + ",area=" + area;
}
PostMan测试:
客户端测试:
@Test
public void testCookieParam() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/form");
Response response = webTarget.request().cookie("longitude", "111.11")
.cookie("latitude", "22.22")
.cookie("population", "33.33")
.cookie("area", "10")
.get();
System.out.println(response.readEntity(String.class));
}
111.11,22.22 population=33.33,area=10
3.9、@Context
JAX-RS2定义了@Context注解来解析上下文参数,JAX-RS2中有多种元素可以通过@Context注解作为上下文参数使用。
@POST
public void getContext(@Context Application application,
@Context Request request,
@Context Providers providers,
@Context UriInfo uriInfo,
@Context HttpHeaders headers) {
MultivaluedMap<String, String> pathParameters = uriInfo.getPathParameters();
MultivaluedMap<String, String> queryParameters = uriInfo.getQueryParameters();
List<PathSegment> pathSegments = uriInfo.getPathSegments();
MultivaluedMap<String, String> requestHeaders = headers.getRequestHeaders();
System.out.println(pathParameters);
System.out.println(queryParameters);
System.out.println(pathSegments);
System.out.println(requestHeaders);
}
{}
{}
[form]
{user-agent=[PostmanRuntime/7.29.0], accept=[*/*], cache-control=[no-cache], postman-token=[2da6d4f7-7441-42bc-b38e-28416fbd5d1d], host=[127.0.0.1:8080], accept-encoding=[gzip, deflate, br], connection=[keep-alive], cookie=[area=10; latitude=22.22; longitude=111.11; population=33.33], content-length=[0]}
4、内容协商
客户端/浏览器通过使用HTTP Accept
、Accept-Charset
、Accept-Language
和Accept-Encoding
头来定义接收头的信息,将其所期待的格式或MME类型告知服务器,服务器根据协商算法,返回客户端/浏览器可接受的数据信息。内容协商不只是数据格式协商,还包括语言、编码、字符集等信息。
- Accept用于数据类型协商;
- Accept-Language用于语言协商;
- Accept–Charset用于字符集协商;
- Accept-Encoding用于压缩算法协商。
JAX-RS2对内容协商的支持,是通过@Produces
实现的,其他协商没有从架构上提供支持,可以通过编码从请求头中获取信息并处理。
4.1、@Produces
注解@Produces
用于定义方法的响应实体的数据类型,可以定义一个
或多个
,同时可以为每种类型定义质量因素(qualityfactor)
。质量因素是取值范围从0到1的小数值
。如果不定义质量因素,那么该类型的质量因素默认为1
。
1)、媒体类型不同的两个同等方法
@Path("conneg")
public class ConnegResource {
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_XML)//响应媒体类型为XML
public Book getJaxbBook(@PathParam("id") Long id) {
return new Book(id, "xml", 22.22);
}
@GET
@Path("{id}")
@Produces(MediaType.APPLICATION_JSON)//响应媒体类型为JSON
public Book getJsonBook(@PathParam("id") Long id) {
return new Book(id, "json", 22.22);
}
}
在这段代码中,getJaxbBook()
和getJsonBook()
是同等质量因素、资源地址相同的两个GET方法,一个定义响应实体格式为XML,一个定义响应实体格式为JSON。
那么对同一个资源的访问,JAX-RS2该如何选择处理方法呢?
- 如果请求中明确定义可接受的数据类型为两者之一,处理方法应该是定义相应数据类型的方法。
- 如果两者都定义了,处理方法应该是质量因素高的方法。
- 如果两者都定义,而且数据类型的质量因素是相等
的或者没有定义Accept,XML的方法会被优先选择
。
没有定义Accept的情况,优先使用XML方法:
客户端明确表述格式的质量因素JSON高于XML,会选择JSON方法:
@Test
public void testConneg() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/conneg");
Response response = webTarget.path("1")
.request()
.header("Accept", "application/xml;q=0.1,application/json;q=0.2")
.get();
System.out.println(response.readEntity(String.class));
}
{"id":1,"name":"json","price":22.22}
2)、一个方法中的多个媒体类型
@GET
@Path("book/{id}")
@Produces({"application/json; qs=.9", "application/xml; qs=.5"})
public Book getBook(@PathParam("id") Long id) {
return new Book(id, "XXX", 22.22);
}
在这段代码中,getBook()方法定义了XML和JSON两种表述数据类型,XML的质量因素是0.5(0可以省略),JSON的是0.9。
如果客户端没有定义Accept
,则使用服务端定义中质量因素更高的(JSON)媒体类型:
如果客户端请求中,明确接收的数据类型是两者之一,则响应实体使用客户端指定的类型:
@Test
public void testConneg2() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/conneg");
Response response = webTarget.path("1")
.request()
.header("Accept", "application/xml")
.get();
System.out.println(response.readEntity(String.class));
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><book><id>1</id><name>xml</name><price>22.22</price></book>
如果客户端请求中,两者都定义但JSON的质量因素小于XML,则优先按照客户端的喜好选择响应实体的数据类型,即选择XML格式:
@Test
public void testConneg3() {
Client client = ClientBuilder.newClient();
WebTarget webTarget = client.target("http://127.0.0.1:8080/ws/conneg");
Response response = webTarget.path("1")
.request()
.header("Accept", "application/xml;q=0.5,application/json;q=0.2")
.get();
System.out.println(response.readEntity(String.class));
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><book><id>1</id><name>xml</name><price>22.22</price></book>
4.2、@Consumers
注解@Consumes
用于定义方法的请求实体的数据类型,和@Produces不同的是,@Consumes的数据类型的定义只用于JAX-RS2匹配请求处理的方法,不做内容协商使用
。
如果匹配不到,服务器会返回HTTP状态码415(Unsupported Media Type)
。
@POST
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
public Book getBook(Book book) {
System.out.println(book);
return book;
}
如果请求体为JSON格式,则返回HTTP状态码415: