JAVA RESTful WebService实战笔记(二)
资源定位之注解相关简介
@QueryParam注解
JAX-RS2定义了@QueryParam注解来定义查询参数,如下表所示
接口描述 | 资源地址 |
---|---|
分页查询列表数据 | /query-resource/test?start=24&size=10 |
排序并分页查询列表收 | /query-resource/test?limit=5&sort=program |
查询单项数据 | /query-resource/test?id=9 |
1、分页查询
/**** @param start 起始条目 参数都使用了final进行限制* 符合Checkstyle风格 即输入参数只作为逻辑算法的依据使用* 其本身并不会再找个过程中被修改* @param size 查询的条目* @return*/@Path("/page") //page?start=0&size=10 访问@GET@Consumes(MediaType.APPLICATION_JSON) //指定请求返回的响应体为JSON@Produces(MediaType.APPLICATION_JSON)public User getByPaging(@QueryParam("start") final int start,@QueryParam("size") final int size){return null;}
2、排序查询
/*** @param limit 分页查询条目* @param sortName 排序规则* @return*/@Path("/order") //order?limit=10&sort=web 访问@GET@Consumes(MediaType.APPLICATION_JSON) //指定请求返回的响应体为JSON@Produces(MediaType.APPLICATION_JSON)public User getByOrder(@QueryParam("limit") final int limit,@QueryParam("sort") final int sortName){return null;}
3、单项查询
/*** @param segId * @return*/@Path("/query") //order?id=10 访问@GET@Consumes(MediaType.APPLICATION_JSON) //指定请求返回的响应体为JSON@Produces(MediaType.APPLICATION_JSON)public User getByQuery(@QueryParam("id") final int segId){return null;}
@PathParam注解
JAX-RS2定义@PathParam注解来定义路径参数—-每个参数对应一个子资源,示例列表如下:
接口描述 | 资源地址 |
---|---|
基本路径参数 | /path-resource/Eric |
J结合查询参数 | /path-resource/Eric?hometown=Luoma |
带有标点符号的资源路径 |
/path-resource/199-1999 /path-resource/01,2012-12,2014 |
子资源变长的资源路径 |
/path-resource/Asia/china/northeast/liaoning/shenyang/huanggu //path-resource/q/restful;program=java;type=web /path-resource/q2/restful;program=java;type=web |
1、@Path注解
JAX-RS2定义@Path注解来定义资源路径,@Path接收一个value参数来解析资源路径地址,可以使用静态定义的方式外,也可以使用动态变量的方式,格式:{参数名称:正则表达式},例如资源地址:/path-resource、199-1999.参考示例如下
@Path("{from:\\d+}-{to:\\d+}") //order?id=10 访问@GET@Consumes(MediaType.APPLICATION_JSON) //指定请求返回的响应体为JSON@Produces(MediaType.APPLICATION_JSON)public User getByCondition(@QueryParam("from") final Integer from, @PathParam("to") final Integer to) {return null;}
在来一个复杂的例子:/path-resource、01,2012-12,2014(引入了逗号(,))
@Path("{beginMonth:\\d+},{beginYear:\\d+}-{endMonth:\\d+},{endYear:\\d+}")
2、正则表达式
3、路径配查询
查询参数和路径参数在一个接口中配合使用,可以更便捷的完成资源定位。
/*** /path-resource/Eric?hometown=Luoma ** @param user Eric* @param hometown Luoma* @return*/@Path("{user:[a-zA-Z][a-zA-Z_0-9]*}") //order?id=10 访问@GET@Consumes(MediaType.APPLICATION_JSON) //指定请求返回的响应体为JSON@Produces(MediaType.APPLICATION_JSON)public User getUserInfo(@QueryParam("user") final String user,@DefaultValue("Shen Yang") @QueryParam("hometown") final String hometown) {return null;}
4、路径区间
路径区间(PathSegment)是对资源地址更加灵活的支持,使资源类的一个方法可以支持更加广泛的资源地址的请求,例如下面的例子
/path-resource/Asia/china/northeast/liaoning/shenyang/huanggu
/path-resource/Asia/china/northeast/liaoning/shenyang/tiexi
/path-resource/china/liaoning/shenyang
如上所示的资源地址中含有固定子资源(shenyang),和动态子资源两部分,对于动态匹配变长的子资源地址,PathSegment类型的参数结合正则表达式将大显身手,如下:
@Path("{region:.+}/shenyang/{district:\\w+}") //order?id=10 访问@GET@Consumes(MediaType.APPLICATION_JSON) //指定请求返回的响应体为JSON@Produces(MediaType.APPLICATION_JSON)public User getByAddress(@PathParam("region")final List<PathSegment> region,@PathParam("district") final String district) {final StringBuilder result = new StringBuilder();for (PathSegment pathSegment : region) {result.append(pathSegment.getPath()).append("-");}result.append("shenyang-" + district);return null;}
@MatrixParam注解
通过@MatrixParam注解来逐一的定义参数,即通过声明方式来获取,示例代码如下:
///path-resource/q2/program=java;type=web@Path("q2/{condition}") //order?id=10 访问@GET@Consumes(MediaType.APPLICATION_JSON) //指定请求返回的响应体为JSON@Produces(MediaType.APPLICATION_JSON)public User getByCondition(@PathParam("condition") final PathSegment condition,@MatrixParam("program") final String program,@MatrixParam("type") final String type) {return null;}
@FormParam注解
JAX-RS2定义了@FormParam注解来定义表单参数,相应的REST方法用以处理请求实体媒体类型为Content-Type:application/x-www-form-urlencoded的请求,示例代码如下:
@Path("form-resource)
public class FormResource{@Postpublic String newPassword(@DefaultValue("ruolan") @FormParam(FromResource.USER) final String user,@Encoded @FormParam(FormParam.PW) final String password,@Encoded @FormParam(FormParam.NPW) final String newPassword,@FormParam(FormParam.VNPW) final String verification{})
}
上述代码中,newPassword()方法是@FormParam注解定义了user等4个参数,这些参数是容器请求中获取并且匹配的,测试代码示例如下:
@Testpublic void testPost(){final Form form = new Form();form.param(FormResource.USER,"ruolan");form.param(FormResource.PW,"北京");form.param(FormResource.NPW,"上海");form.param(FormResource.VNPW,"上海");final String result = target.("form-resource").request().post(Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE),String.class);FormTest.LOGGER.debug(result);Assert.assertEquals("encoded should let id to disable decoding","ruolan:%E5%8C%97%E4%BA%AC:%E4%B8%8A%E6%B5%B7:上海",result);}
注意:
- @Encoded注解用以标识禁用自动解码,示例中的测试结果中%E4%B8%8A%E6%B5%B7是newPassword()方法中的参数值”上海”的编码值,当对newPassword使用@Encoded注解,REST方法得到的参数值就不会被编码
- @DefaultValue注解,用以为客户端没有为其提供值的参数 提供默认的参数
@BeanParam注解
JAX-RS2定义了@BeanParam注解用于自定义参数组合,使REST方法可以使用简洁的参数形式完成复杂的接口设计
public String getByAddress(@BeanParam Jaxrs2GuideParam param) {
//关注点2:参数组合
public class Jaxrs2GuideParam {@HeaderParam("accept")private String acceptParam;@PathParam("region")private String regionParam;@PathParam("district")private String districtParam;@QueryParam("station")private String stationParam;@QueryParam("vehicle")private String vehicleParam;public void testBeanParam() {
...final WebTarget queryTarget = target(path).path("China").path("northeast").path("shenyang").path("tiexi")
.queryParam("station", "Workers Village").queryParam("vehicle", "bus");result = queryTarget.request().get().readEntity(String.class);//关注点3:查询结果断言 Assert.assertEquals("China/northeast:tiexi:Workers Village:bus", result);
}
//关注点4:复杂的查询请求
http://localhost:9998/ctx-resource/China/shenyang/tiexi?station=Workers+Village&vehicle=bus
在这段代码中,getByAddress()方法只用了一个使用@BeanParam注解定义的Jaxrs2GuideParam类型的参数,见关注点1;Jaxrs2GuideParam类定义了一系列REST方法会用到的参数类型,包括示例中使用的查询参数”station”和路径参数”region”等,从而使得getByAddress()方法可以匹配更为复杂的资源路径,见关注点2;在变长子资源的例子基础上,增加了查询条件,但测试方法testBeanParam()发起的请求的资源地址见关注点4;可以看出这是一个较为复杂的查询请求。其中路径部分包括China/shenyang/tiexi
,查询条件包括station=Workers+Village和vehicle=bus。
这些条件均在Jaxrs2GuideParam类中可以匹配,因此从关注点3的测试断言中可以看出,该请求响应的预期结果是
"China/northeast:tiexi:Workers Village:bus"。
@CookieParam注解
JAX-RS2定义了@CookieParam注解用以匹配Cookie中的键值对信息,示例如下。
@GET
public String getHeaderParams(@CookieParam("longitude") final String longitude,@CookieParam("latitude") final String latitude,@CookieParam("population") final double population,@CookieParam("area") final int area) {//关注点1:资源方法入参 return longitude + "," + latitude + " population=" + population + ",area=" + area;
@Test
public void testContexts() {final Builder request = target(path).request();request.cookie("longitude", "123.38");request.cookie("latitude", "41.8");request.cookie("population", "822.8");request.cookie("area", "12948");result = request.get().readEntity(String.class);//关注点2:测试结果断言 Assert.assertEquals("123.38,41.8 population=822.8,area=12948", result);
}
在这段代码中,getHeaderParams()方法包含4个使用@CookieParam注解定义的参数,用于匹配Cookie的字段,见关注点1;在测试方法testContexts中,客户端Builder实例填充了相应的cookie键值对信息,其断言是对cookie字段值的验证,见关注点2。
@Context注解
JAX-RS2定义了@Context注解来解析上下文参数,JAX-RS2中有多种元素可以通过@Context注解作为上下文参数使用,示例代码如下。
pathMap = uriInfo.getPathParameters();
final MultivaluedMapqueryMap = uriInfo.getQueryParameters();
final ListsegmentList = uriInfo.getPathSegments();
final MultivaluedMapheaderMap = headers.getRequestHeaders();" data-snippet-id="ext.a3f662d96e4890cd0110b0e0facd3b54" data-snippet-saved="false" data-codota-status="done">
public String getByAddress(@Context final Application application,@Context final Request request,@Context final javax.ws.rs.ext.Providers provider,@Context final UriInfo uriInfo,@Context final HttpHeaders headers){
在这段代码中,分别定义了Application、Request、Providers、UriInfo和HttpHeaders等5种类型的上下文实例。从这些实例中可以获取请求过程中的重要参数信息,示例代码如下。
final MultivaluedMap<String, String> pathMap = uriInfo.getPathParameters();
final MultivaluedMap<String, String> queryMap = uriInfo.getQueryParameters();
final List<PathSegment> segmentList = uriInfo.getPathSegments();
final MultivaluedMap<String, String> headerMap = headers.getRequestHeaders();
在这段代码中,UriInfo类是路径信息的上下文,从中可以获取路径参数集合getPath-Parameters()和查询参数集合getQueryParameters()。类似地,我们可以从HttpHeaders类中获取头信息集合getRequestHeaders()。这些业务逻辑处理中常用的辅助信息的获取,要通过@Context注解定义方法的参数或者类的字段来实现。
处理响应
REST的响应处理结果应包括响应头中HTTP状态码,响应实体中媒体参数类型和返回值类型,以及异常情况处理。JAX-RS2支持4中返回值类型的响应,分别是无返回值、返回Response类实例、返回GenericEntity类实例和返回自定义类的实例.
VOID(无返回值类型)
在返回值类型中是void的响应,其响应实体为空,HTTP状态码是204。例子代码如下:
@DELETE@Path("{s}")public void deleteTest(@PathParam("s") final String s){}
因为delete操作不需要返回值关于资源标书的信息,因此该方法没有返回值.(疑问点,如果需要通知客户端是否删除成功了没有呢??????)
RESPONSE(Response返回值类型)
在Response的响应中,响应实体为Response类的entity()方法定义的实体实例。如果该内容为空,则HTTP状态码是204,否则HTTP状态码为200 OK,示例代码如下:
@POST@Path("c")public Response getResponse(final String s){return Response.ok().entity("char[] : " + s ).build();}
在上述的代码中,Response首先定义了HTTP的状态码为OK,然后填充实体信息,最后调用build()方法构建Response实例
GenericEntity(GenericEntity返回值类型)
通用实体类型作为返回值的情况并不是很常用。其形式是构造一个统一的实体实例并将其返回,实体实例作为第一个参数,该实体类型作为第二个参数,示例代码如下:
@POST@Path("b")public String getGenericEntity(final byte[] bytes) {return "byte[] : " + new String(bytes);}public GenericEntity<String> getGenericTest(final byte[] bytes){//构建GenericEntity实例return new GenericEntity<>("byte[] : " + new String(bytes),String.class );}
自定义类型
JDK中的类(例如File,String等)都可以作为返回值类型,更常用的是返回自定义的POJO类型。示例代码如下:
@POST@Path("f")public File getFile(final File f) throws FileNotFoundException, IOException {BufferedReader br = new BufferedReader(new FileReader(f));String s;do {s = br.readLine();} while (s != null);return f;}@POST@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})@Produces(MediaType.APPLICATION_XML)public User getEntity(User user){return user;}@POST@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})@Produces(MediaType.APPLICATION_XML)public User getEntity(JAXBElement<User> user){User user1 = user.getValue();return user1;}
处理异常
处理状态码
状态码 | 含义 |
---|---|
200 OK | 服务器正常响应 |
201 Created | 创建新实体,响应头Location指定访问该实体的URL |
202 Accepted | 服务器接受请求,处理尚未完成。可用于异步处理机制 |
204 No Content | 服务器正常响应,但是响应实体为空 |
301 Moved Permanently | 请求资源的地址发生永久变动,响应头Location指定新的URL |
302 Found | 请求资源的额地址发生临时变动 |
304 Not Modified | 客户端缓存资源依然有效 |
400 Bad Request | 请求信息出现语法错误 |
401 Unauthorized | 请求资源无法授权给未验证错误 |
403 Frobidden | 请求资源未授权当前用户 |
404 Not Found | 请求资源不存在 |
405 Method Not Allowed | 请求方法不匹配 |
406 Not Acceptable | 请求资源的媒体类型不匹配 |
500 Internale Server Error | 服务器内部错误,意外终止响应 |
501 Not Implemented | 服务器不支持当前请求 |
内容协商
@Produces注解
@Produces注解用于定义方法的响应实体的数据类型,可以定义一个或者多个,同事可以为每种类型定义质量因素(qualityfactor)。质量因素是取值范围从0到1的小数值。如果不定义质量因素,那么该类型的质量因素默认为1
@GET@Path("{id}")@Produces(MediaType.APPLICATION_XML)public User getJaxUser(@PathParam("id") final int userId) {return new User(userId);}@GET@Path("{id}")@Produces(MediaType.APPLICATION_JSON)public User getJsonUser(@PathParam("id") final int userId) {return new User(userId);}/*** 以下的代码中 定义了xml和json两种表述数据类型,xml的质量因素是0.5 json的质量因素是0.9**/@GET@Path("book/{id}")@Produces({"application/json;qs=0.9","application/xml;qs=0.6"})public User getUser(@PathParam("id") final int userId) {return new User(userId);}
如果客户端的请求中,明确接收的数据类型是两者之一,响应实体使用指定类型.如果没有定义或者两者都定义且JSON的质量因素大雨或者等于XML,则返回JSON,还有一种用例就是,两者都定义但是json的质量因素小于XML,内容协商的结果按照客户端的喜好选择相应实体的数据类型(xml格式)
@Consumes注解
@Consumes注解用于定义方法的请求实体的数据类型,和@Produces不同的是,@Consumes注解的数据类型的定义只用于JAX-RS2匹配请求处理的方法,不做内容协商使用,如果匹配不到,服务器会返回HTTP状态码415(Unsupported Meia Type),示例代码如下:
@POST@Consumes({MediaType.APPLICATION_XML,MediaType.APPLICATION_JSON})@Produces(MediaType.APPLICATION_XML)public User getEntity(User user){final Builder request = Target(path).request();final User result = request.post(Entity.entity(user,MediaType.APPLICATION_XML), User.class);return user;}
@Consumes媒体类型为XML格式和JSON格式,那么在客户端的请求中,如果请求实体的数据类型定义是两者之一,该方法会被选择为处理请求的方法,否则查找是否有定义为相应数据类型的方法,如果没有抛出javax.ws.rs.NotSupportedException异常,则使用该方法处理请求。
JAVA RESTful WebService实战笔记(二)相关推荐
- Java基础--基础语法笔记(二)--Switch的用法
直接步入主题,接着记录学习java的一些重要笔记.对于一些比较简单的内容,就不会详细的去进行记录. Switch的用法 格式一: switch (表达式) {case 条件1:语句1;break;ca ...
- Java并发编程实战笔记2:对象的组合
设计线程安全的类 在设计现车让安全类的过程之中,需要包含以下三步: 找出构成对象状态的所有变量 找出约束状态变量的不变性条件 建立对象状态的并发访问策略 实例封闭 通过封闭机制与合适的加锁策略结合起来 ...
- java并发编程实战(二)
java并发编程中常常会用到两种容器来存放一些数据,这些数据需要保证能在多线程下正常访问.常见的容器分为两类:同步容器和并发容器.在java并发编程实战一书中的第五章也有讲解. 什么是同步容器以及优劣 ...
- java 8实战 异步社区_服!看完阿里大牛手写的Java异步编程实战笔记,我惊呆了...
这份笔记涵盖了Java中常见的异步编程场景,包括单JVM内的异步编程.跨主机通过网络通信的远程过程调用的异步调用与异步处理,以及Web请求的异步处理等. 在讲解Java中每种异步编程技术时都附有案例, ...
- Java 微信小程序笔记 二、 微信支付退款案例
一.前期准备工作: 上篇博客配置的一些参数和文件Jar包 都要用到 微信支付需要小程序和商户绑定 APP绑定微信商户平台获取商户id(mchID). 证书(商户后台下载). 支付签名密钥(商户后台设置 ...
- Jersey构建Java RestFul Webservice基础学习教程
1.用Jersey构建RESTful服务1–HelloWorld http://www.waylau.com/jersey-restful-helloworld/ 2.用Jersey构建RESTful ...
- 神经网络与深度学习——TensorFlow2.0实战(笔记)(二)(Anaconda软件使用)
Python的运行模式 交互模式 打开命令行窗口 键入 python,激活python交互模式,出现Python提示符 >>> 在提示符 >>> 处, 写入Pyth ...
- Java并发编程实战笔记
如果当多个线程访问同一个可变的状态变量时没有使用合适的同步,那么程序就会出现错误.有三种方式可以修复这个问题: i.不在线程之间共享该状态变量 ii.将状态变量修改为不可变的变量 iii.在访问状态变 ...
- Java并发编程实战笔记—— 并发编程1
1.如何创建并运行java线程 创建一个线程可以继承java的Thread类,或者实现Runnabe接口. public class thread {static class MyThread1 ex ...
最新文章
- 什么才是真正的L3自动驾驶?
- 后MATLAB时代的七种开源替代,一种堪称完美!
- 芯片史上最大收购案!「博通」拟斥资1000亿美元收购「高通」
- 郁金香2013网授汇编逆向与外挂 [ 91课,全 ]
- struts2重定向
- 建立学生选课表 mysql 语句_MySQL常用SQL语句(Python实现学生、课程、选课表增删改查)...
- apache mediawiki 安装_如何在CentOS 7上安装MediaWiki
- java 二进制 文件比较_Java中对文件的读写操作之比较
- magento 问题解答 FQA
- Oracle On Linux
- 中国电信陆良军:2020年5G手机终端规模达1.7亿
- fetch oracle 12c下载,十二、Oracle Fetch子句
- 新版傻妞对接QQ完整版(10月24日)
- php mysql注入测试工具_PHP+MYSQL 【注入漏洞】攻防测试
- 利用OpenGL模拟太阳系
- 使用ffmpeg合并多个视频文件
- RT_thread空闲线程及两个常用的钩子函数
- linux鼠标晃动出现,鼠标指针抖动的原因及其解决方法【详解】
- SQLZOOL练习题答案和解析 第2关 SELECT from World
- ftp文件缓存服务器,ftp服务器上的缓存在哪