- 浏览: 1679459 次
- 性别:
- 来自: 杭州699号
文章分类
最新评论
-
莫莫摸:
为什么不用dubbo
RCP数据传输模型回顾 -
大胡子爸爸:
String, Class 都实现了Serializable接 ...
RPC框架几行代码就够了 -
lss598018587:
谢谢大神分享,比起新手看复杂的dubbo框架还不如看大神的这一 ...
RPC框架几行代码就够了 -
15606915740:
你好,请问一下。<dubbo:consumer filt ...
Dubbo文档 -
joqk12345:
...
一些设计上的基本常识
现在基本上所有的MVC框架都叫喧着支持RESTful(http://zh.wikipedia.org/wiki/REST),
最近写的Struts(for)RCP(http://struts4rcp.googlecode.com)也来凑下热闹,
这里讲下基本思路,作个参考。
REST的一些要求,如:
1. 客户端和服务器结构
2. 连接协议具有无状态性
3. 能够利用Cache机制增进性能
4. 层次化的系统
5. Code On Demand - Javascript
通过RCP/RIA和HTTP协议本身就可以达到,就不多说了,
主要关注REST的设计风格,如:
1. 资源是由URI来指定。
2. 对资源的操作包括获取、创建、修改和删除资源,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。
3. 通过操作资源的表形来操作资源。
4. 资源的表现形式则是XML或者HTML,取决于是读者是机器还是人,消费web服务的客户软件还是web浏览器。当然也可以是任何其他的格式。
下面一一论述以上四点的实现:
1. URI数据映射
鉴于RESTful要从URI上取值,并注入到相应属性,这就需要一种方式,来声明哪一截数据应该注入到哪个属性,
在参考了多个RESTful框架后,决定采用常见的"/catalogs/{categoryId}/books/{bookId}"风格声明URI数据提取方式,如:
2. 方法分派
关于方法的对应关系,有很多做法,如:
(1) 函数名与请求类型保持一致,如:
但感觉这样,函数名对业务开发人员不友好。
(2) 取一个更直观的名称与之对应,如:
上面四个方法分别对应POST,PUT,DELETE,GET四个HTTP请求方法。
(3) 不限制名称,用标注在函数上进行标识,如:
(4) 配置文件声明,如:
最终觉得第2种方案比较简单友好, 并且客户端便于创建对等接口, 标注和配置也可以考虑支持。
还有一个问题是,ResourceAction应不应该提供list, find等函数,用于列表和查找,如:
这些已经不是同一个资源了,而是同一类型的资源,如果分开应该是:
如果定义在一起,@Path就需要声明多个资源路径,
如:@Path({"/users/{id}", "/users"})
另一个相似的问题是,ResourceAction应不应该提供add, edit方法,用于跳转到新增页面和编辑页面,如:
如:@Path({"/users/{id}","/users","/users/add","/users/{id}/edit"})
当然,可以用命名约定来减少路径的个数,问题在于add和edit已经超出(甚至违背了)RESTful风格,
因为RESTful要求客户端Code On Demand,要求在客户端缓存和管理状态,
像新增页面应该在客户端直接处理,而编辑页面实际上是调用get方法取值填充,只是非RIA的Web应用需要这种间接页面,
如果用RESTful风格第4点“资源多重表述”来解决,可能更合理,
edit只是资源"/users/{id}"的一种GET展示形式,也就是客户端设置"Accept"信息头为"edit",
但这样存在一个问题,浏览器不能友好的输入请求头信息。
另外,add是否需要作为特殊值,以避免冲突,因为可能某个用户的ID就是add,当然,如果ID都是数字就没问题。
再者,根据RFC2616(http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)的规定:
9.1.2 Idempotent Methods
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent.
要求除POST以外的方法都具有幂等性(idempotence),
也就是调用这些方法n次与调用1次的结果一致,
比如,你删除一个资源8次,和删除这个资源1次没什么区别,
还要求OPTIONS和TRACE方法无副作用(side effects),
也就是不修改任何状态(包括数据库数据与对象属性),
调用这些方法n次与调用0次结果一致,
按照RESTful的要求,GET方法也应该是无副作用的,
这些与契约式设计(Design By Contract)的“区分命令与查询”原则是一致的。
但框架在这方面没法做太多限制,只能在文档中声明并告知业务开发人员。
3. 客户端操作方式
要保证的语义是:客户端看起来是在操作资源表形本身。
(1) 客户端
首先,客户端需要一个代表资源的接口,它的所有函数都是操作该资源本身,如:
然后,通过工厂获取此接口,如:
另外,可以考虑增加一个批量资源接口,如:
同样,可以使用工厂获取此接口,如:
(2) AJAX客户端
尽量保持与RCP客户端一致,如:
(3) Web页面
4. 资源多重表述
也就是客户端,可以通过修改"Accept"请求头信息,来要求服务器端返回不同类型的数据结果,如:
Accept: text/json 返回JSON数据
Accept: text/xml 返回XML数据
Accept: text/html 返回HTML页面
Accept: text/wml 返回WML页面
这个可以通过读取根据请求头信息来切换序列化器实现,首先需要留有策略接口,如:
然后写一个Restful的实现,如:
上面提到过结果类型放在"Accept"信息头中有个问题,就是不便输入,对于B/S应用的浏览器来说,不太友好,所以Struts2等通过URL扩展名来识别,如:"/user/1.html","/user/1.wml",这样做超接会方便些,但却违反了RESTful语义。
很多细节还没考虑清楚,先写到这了,等正式加入框架,再写个帮助文档。
我个人认为用 标注 和 配置文件 灵活性更大些, 比如: get()、find()、read()等都可以标注成@Get, 感觉这样隔离了实现!
是的,用标注是个好想法,JSR311就是全部用标注实现的,但我觉得REST与RPC的一个重要区别就在于它统一了“动词”,并以“名词”为中心,要的就是不“灵活”(零风格是最灵活的),虽然会对某些特殊功能实现带来麻烦,但对常见功能非常简化,而且我想实现的是MVC框架,而不是REST版的WebService(这是JSR311的目标),将REST作为控制器层实现,所以固定函数名,会比较合理些,并且可以保留对"Action"概念的支持,以处理特殊情况。
最近写的Struts(for)RCP(http://struts4rcp.googlecode.com)也来凑下热闹,
这里讲下基本思路,作个参考。
REST的一些要求,如:
1. 客户端和服务器结构
2. 连接协议具有无状态性
3. 能够利用Cache机制增进性能
4. 层次化的系统
5. Code On Demand - Javascript
通过RCP/RIA和HTTP协议本身就可以达到,就不多说了,
主要关注REST的设计风格,如:
1. 资源是由URI来指定。
2. 对资源的操作包括获取、创建、修改和删除资源,这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。
3. 通过操作资源的表形来操作资源。
4. 资源的表现形式则是XML或者HTML,取决于是读者是机器还是人,消费web服务的客户软件还是web浏览器。当然也可以是任何其他的格式。
下面一一论述以上四点的实现:
1. URI数据映射
鉴于RESTful要从URI上取值,并注入到相应属性,这就需要一种方式,来声明哪一截数据应该注入到哪个属性,
在参考了多个RESTful框架后,决定采用常见的"/catalogs/{categoryId}/books/{bookId}"风格声明URI数据提取方式,如:
@Path("/users/{id}") public class UserManageAction extends ResourceAction<User> { // ...... }
2. 方法分派
关于方法的对应关系,有很多做法,如:
(1) 函数名与请求类型保持一致,如:
@Path("/users/{id}") public class UserManageAction extends ResourceAction<User> { @Override public void post(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.create(user); } @Override public void put(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.update(user); } @Override public void delete(User user) throws Exception { userService.delete(user.getId()); } @Override public User get(User user) throws Exception { return userService.get(user.getId()); } }
但感觉这样,函数名对业务开发人员不友好。
(2) 取一个更直观的名称与之对应,如:
@Path("/users/{id}") public class UserManageAction extends ResourceAction<User> { @Override public void create(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.create(user); } @Override public void update(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.update(user); } @Override public void delete(User user) throws Exception { userService.delete(user.getId()); } @Override public User get(User user) throws Exception { return userService.get(user.getId()); } }
上面四个方法分别对应POST,PUT,DELETE,GET四个HTTP请求方法。
(3) 不限制名称,用标注在函数上进行标识,如:
@Path("/users/{id}") public class UserManageAction extends ResourceAction<User> { @Post public void createUser(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.create(user); } @Put public void updateUser(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.update(user); } @Delete public void deleteUser(User user) throws Exception { userService.delete(user.getId()); } @Get public User getUser(User user) throws Exception { return userService.get(user.getId()); } }
(4) 配置文件声明,如:
@Path("/users/{id}") public class UserManageAction extends ResourceAction<User> { public void createUser(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.create(user); } public void updateUser(User user) throws Exception { // 除了ID以外的值,通过表单传入,表单中有ID值无效(会被覆盖掉) userService.update(user); } public void deleteUser(User user) throws Exception { userService.delete(user.getId()); } public User getUser(User user) throws Exception { return userService.get(user.getId()); } }
<bean id="userManageAction" class="com.xxx.UserManageAction"> <property name="postMethodName" value="createUser"> <property name="putMethodName" value="updateUser"> <property name="deleteMethodName" value="deleteUser"> <property name="getMethodName" value="getUser"> </bean>
最终觉得第2种方案比较简单友好, 并且客户端便于创建对等接口, 标注和配置也可以考虑支持。
还有一个问题是,ResourceAction应不应该提供list, find等函数,用于列表和查找,如:
@Path("/users/{id}") public class UserManageAction extends ResourceAction<User> { // create(), update(), delete(), get() @Override public Collection<User> list() throws Exception { return userService.findAll(); } @Override public Collection<User> find(User user) throws Exception { return userService.find(user); } }
这些已经不是同一个资源了,而是同一类型的资源,如果分开应该是:
@Path("/users") public class UserListAction extends ResourceAction<Collection<User>> { @Override public Collection<User> get(User user) throws Exception { return userService.find(user); // 如果条件为空即为全部 } }
如果定义在一起,@Path就需要声明多个资源路径,
如:@Path({"/users/{id}", "/users"})
另一个相似的问题是,ResourceAction应不应该提供add, edit方法,用于跳转到新增页面和编辑页面,如:
@Path("/users/{id}") public class UserManageAction extends ResourceAction<User> { // create(), update(), delete(), get() @Override public User add() throws Exception { return new User(); } @Override public User edit(User user) throws Exception { return userService.get(user.getId()); } }
如:@Path({"/users/{id}","/users","/users/add","/users/{id}/edit"})
当然,可以用命名约定来减少路径的个数,问题在于add和edit已经超出(甚至违背了)RESTful风格,
因为RESTful要求客户端Code On Demand,要求在客户端缓存和管理状态,
像新增页面应该在客户端直接处理,而编辑页面实际上是调用get方法取值填充,只是非RIA的Web应用需要这种间接页面,
如果用RESTful风格第4点“资源多重表述”来解决,可能更合理,
edit只是资源"/users/{id}"的一种GET展示形式,也就是客户端设置"Accept"信息头为"edit",
但这样存在一个问题,浏览器不能友好的输入请求头信息。
另外,add是否需要作为特殊值,以避免冲突,因为可能某个用户的ID就是add,当然,如果ID都是数字就没问题。
再者,根据RFC2616(http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html)的规定:
RFC2616 写道
9.1.2 Idempotent Methods
Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. The methods GET, HEAD, PUT and DELETE share this property. Also, the methods OPTIONS and TRACE SHOULD NOT have side effects, and so are inherently idempotent.
要求除POST以外的方法都具有幂等性(idempotence),
也就是调用这些方法n次与调用1次的结果一致,
比如,你删除一个资源8次,和删除这个资源1次没什么区别,
还要求OPTIONS和TRACE方法无副作用(side effects),
也就是不修改任何状态(包括数据库数据与对象属性),
调用这些方法n次与调用0次结果一致,
按照RESTful的要求,GET方法也应该是无副作用的,
这些与契约式设计(Design By Contract)的“区分命令与查询”原则是一致的。
但框架在这方面没法做太多限制,只能在文档中声明并告知业务开发人员。
3. 客户端操作方式
要保证的语义是:客户端看起来是在操作资源表形本身。
(1) 客户端
首先,客户端需要一个代表资源的接口,它的所有函数都是操作该资源本身,如:
/** * RESTful远程资源接口 * @param <R> 资源类型 */ public interface Resource<R extends Serializable> { /** * 创建资源 * @param resource 资源信息(注:标识性属性值(如:ID值)无效,在服务器端接收时,将被替换为资源URI所指定的值) * @throws Exception 创建失败或网络连接出错时抛出 */ void create(R resource) throws Exception; /** * 更新资源 * @param resource 资源信息(注:标识性属性值(如:ID值)无效,在服务器端接收时,将被替换为资源URI所指定的值) * @throws Exception 更新失败或网络连接出错时抛出 */ void update(R resource) throws Exception; /** * 删除资源 * @throws Exception 删除失败或网络连接出错时抛出 */ void delete() throws Exception; /** * 获取资源 * @return 资源 * @throws Exception 获取失败或网络连接出错时抛出 */ R get() throws Exception; }
然后,通过工厂获取此接口,如:
Resource<User> userResource = Resources.getResource("/users/4271"); // URI带上ID // 或者:Resources.getResource("/users/{0}", id); // 不定长参数,替换URI中的占位符 User user = new User("liangfei", "xxx@xxx.com"); userResource.create(user); user = userResource.get(); userResource.update(user); userResource.delete();
另外,可以考虑增加一个批量资源接口,如:
/** * 批量资源接口 * @param <R> 资源类型 */ public interface BatchResource<R extends Serializable> extends Resource<R[]> { // 将从父接口中继承: // void create(R[] resources) throws Exception; // 批量创建 // void update(R[] resources) throws Exception; // 批量更新 // void delete() throws Exception; // 删除全部资源 // R[] get() throws Exception; // 获取全部资源 /** * 删除匹配的资源 * @param resource 匹配条件(如果条件复杂,可以传入资源类型的子类作为条件) * @throws Exception 删除失败或网络连接出错时抛出 */ void delete(R resource) throws Exception; /** * 获取匹配的资源 * @param resource 匹配条件(如果条件复杂,可以传入资源类型的子类作为条件) * @return 资源 * @throws Exception 获取失败或网络连接出错时抛出 */ R[] get(R resource) throws Exception; }
同样,可以使用工厂获取此接口,如:
BatchResource<User> userBatchResource = Resources.getBatchResource("/users"); // URI不带ID User[] users = userBatchResource.get();
(2) AJAX客户端
尽量保持与RCP客户端一致,如:
var userResource = Resources.getResource("/users/4271"); var user = {name:"liangfei", emial: "xxx@xxx.com"}; userResource.create(user); user = userResource.get(); userResource.update(user); userResource.delete();
(3) Web页面
<a href="/users/1">view</a> <form action="/users/1" method="post" accept="text/html"> <input type="text" name="name" /> <input type="text" name="email" /> <input type="submit" value="create"/> </form>
4. 资源多重表述
也就是客户端,可以通过修改"Accept"请求头信息,来要求服务器端返回不同类型的数据结果,如:
Accept: text/json 返回JSON数据
Accept: text/xml 返回XML数据
Accept: text/html 返回HTML页面
Accept: text/wml 返回WML页面
这个可以通过读取根据请求头信息来切换序列化器实现,首先需要留有策略接口,如:
/** * Action接收映射接口 */ public interface ActionMapper { /** * 获取序列化器 * @param request 请求信息 * @return 序列化器 */ Serializer getSerializer(HttpServletRequest request); // 当然,此接口可能还有相关的其它映射函数,如:getActionName(request)等 }
然后写一个Restful的实现,如:
public class RestfulActionMapper implements ActionMapper { private final Map<String, Serializer> serializers = new HashMap<String, Serializer>(); public RestfulActionMapper() { // 搜索或注册序列化器... serializers.put("text/json", new JsonSerializer()); serializers.put("text/xml", new XmlSerializer()); serializers.put("text/html", new JspHtmlSerializer()); serializers.put("text/wml", new JspWmlSerializer()); // serializers.put("text/html", new VelocityHtmlSerializer()); // serializers.put("text/wml", new VelocityWmlSerializer()); } @Override public Serializer getSerializer(HttpServletRequest request) { String type = request.getHeader("Accept"); return serializers.get(type); } }
上面提到过结果类型放在"Accept"信息头中有个问题,就是不便输入,对于B/S应用的浏览器来说,不太友好,所以Struts2等通过URL扩展名来识别,如:"/user/1.html","/user/1.wml",这样做超接会方便些,但却违反了RESTful语义。
很多细节还没考虑清楚,先写到这了,等正式加入框架,再写个帮助文档。
评论
5 楼
DanielYWoo
2009-01-14
目前HP的Symphony SDK和社区的Restlet和Jersey还算是比较好用,Struts和Axis2所宣称的Restful WS都很糟糕.
另外,我觉得Atom和JSON已经是Restful WS的既定事实的必须支持的两种representation了
如果是自增主键的话,add可以POST到resources上啊,这是Restful WS推荐的方式也是Atom协议要求的. Edit可以put到resources/{id}上
另外,我觉得Atom和JSON已经是Restful WS的既定事实的必须支持的两种representation了
引用
如:@Path({"/users/{id}","/users","/users/add","/users/{id}/edit"})
当然,可以用命名约定来减少路径的个数,问题在于add和edit已经超出(甚至违背了)RESTful风格,
当然,可以用命名约定来减少路径的个数,问题在于add和edit已经超出(甚至违背了)RESTful风格,
如果是自增主键的话,add可以POST到resources上啊,这是Restful WS推荐的方式也是Atom协议要求的. Edit可以put到resources/{id}上
4 楼
Jekey
2008-12-19
标记一下,最近比较忙,有空研究一下。
3 楼
javatar
2008-12-18
Beyon_javaeye 写道
我个人认为用 标注 和 配置文件 灵活性更大些, 比如: get()、find()、read()等都可以标注成@Get, 感觉这样隔离了实现!
是的,用标注是个好想法,JSR311就是全部用标注实现的,但我觉得REST与RPC的一个重要区别就在于它统一了“动词”,并以“名词”为中心,要的就是不“灵活”(零风格是最灵活的),虽然会对某些特殊功能实现带来麻烦,但对常见功能非常简化,而且我想实现的是MVC框架,而不是REST版的WebService(这是JSR311的目标),将REST作为控制器层实现,所以固定函数名,会比较合理些,并且可以保留对"Action"概念的支持,以处理特殊情况。
2 楼
Beyon_javaeye
2008-12-18
我个人认为用 标注 和 配置文件 灵活性更大些, 比如: get()、find()、read()等都可以标注成@Get, 感觉这样隔离了实现!
1 楼
javatar
2008-12-08
经过再三思考,决定使用以下接口形式:
客户端使用:
服务器端处理:
客户端使用:
// 从工厂中获取资源目录引用 (包装代理类,不与服务器交互) Resources<User> userResources = Client.getClient().getResources("/users"); // 统计资源列表 (发送"HEAD"请求) long userCount = userResources.count(); long userCount = userResources.count(new User("xxx")); // 获取资源列表 (发送"GET"请求) Resource<User>[] users = userResources.list(); Resource<User>[] users = userResources.list(new User("xxx")); // 可以使用User的子类作为过滤条件 Resource<User> userResource = users[0]; // 创建资源 (发送"POST"请求) Resource<User> userResource = userResources.create(new User("liangfei", "xxx@xxx.com")); // 从工厂中获取资源引用 (包装代理类,不与服务器交互) Resource<User> userResource = Client.getClient().getResource("/users/{0}", id); // 不定长参数,替换URI中的占位符 // 读取资源 (发送"GET"请求) User user = userResource.read(); // 更新资源 (发送"PUT"请求) userResource.update(user); // 删除资源 (发送"DELETE"请求) userResource.delete();
服务器端处理:
@Path("/users//{id}") // 双斜杠用于分隔集合资源URI和单一资源URI public class UserResourceAction extends ResourceAction<User> { // 统计资源列表 (接收集合资源的"HEAD"请求) protected long count(User user) throws Exception { if (user == null) return userService.countAllUser(); return userService.countByUser(user); } // 获取资源列表 (接收集合资源的"GET"请求) protected User[] list(User user) throws Exception { if (user == null) return userService.findAllUser().toArray(new User[0]); return userService.findByUser(user).toArray(new User[0]); } // 创建资源 (接收集合资源的"POST"请求) protected void create(User user) throws Exception { userService.saveUser(user); } // 读取资源 (接收单一资源的"GET"请求) protected User read(User user) throws Exception { return userService.loadUser(user.getId()); } // 修改资源 (接收单一资源的"PUT"请求) protected void update(User user) throws Exception { userService.updateUser(user); } // 删除资源 (接收单一资源的"DELETE"请求) protected void delete(User user) throws Exception { userService.removeUser(user.getId()); } }
发表评论
-
能力成长模型
2012-05-09 00:28 22662最近看了温伯格1986年出版的《技术领导之路》, 很老的书,讲 ... -
以HTTL为例讲讲模块分包&领域模型&扩展框架
2011-10-09 20:08 16438注:该博客内容已加入 ... -
使用Map参数的Webx3扩展
2011-08-28 02:10 5850因Webx3是开源的,所以把这个简单的Webx3扩展发在博客上 ... -
Netty内存泄露
2011-08-02 20:09 24860转于自己在公司的Blog: ... -
Grizzly和Netty以及Mina简单性能对比
2011-07-17 02:48 29609转于自己在公司的Blog: http://pt.alibaba ... -
RPC框架几行代码就够了
2011-07-14 00:34 89477转于自己在公司的Blog: http://pt.alibaba ... -
魔鬼在细节中
2011-05-24 14:50 32255转于自己在公司的Blog: ... -
Dubbo扩展点重构
2011-05-12 22:09 38757转于自己在公司的Blog: http://pt.alibaba ... -
配置设计
2011-03-09 23:41 23427转于自己在公司的Blog: ... -
[转]HTML5设计原理
2011-03-09 22:57 7647Jeremy Keith在 Fronteers 2010 ... -
Hessian序列化不设SerializerFactory性能问题
2010-12-27 11:38 6377转于自己在公司的Blog: http://pt.alibaba ... -
动态代理方案性能对比
2010-11-17 21:38 45595转于自己在公司的Blog: http://pt.alibaba ... -
防痴呆设计
2010-11-05 18:58 17502转于自己在公司的Blog: ... -
负载均衡扩展接口重构
2010-11-05 18:53 8627转于自己在公司的Blog: ... -
分布式服务框架常被质疑的价值
2010-11-05 18:52 5675转于自己在公司的Blog: http://pt.alibaba ... -
Hessian3.2.1在序列化32.5k字符串时的问题
2010-11-05 18:49 7107转于自己在公司的Blog: http://pt.alibaba ... -
一些设计上的基本常识
2010-07-05 19:28 27423转于自己在公司的Blog: ... -
谈谈扩充式扩展与增量式扩展
2010-06-12 19:46 18944转于自己在公司的Blog: http://pt.alibaba ... -
Scaling Architecture
2010-02-25 10:31 4051Scaling Second Life: http://p ... -
EBay SOA
2010-02-23 18:23 4734EBay SOA PPT
相关推荐
一个Delphi实现的HttpServer,支持RESTful风格路由
本来是想在GitHub找一个符合自己App的网络请求库,结果就是要么不支持缓存或者不支持RESTful API 请求, 又或者带缓存的又不支持过滤某一些参数字段(否则无法得到缓存),带着这样的需求之下就有了 “HJNetwork” 这...
对应博客中的spring3.0支持restful的demo源代码,由于容量原因我把lib下面的包给去掉了。如果有需要lib下面用的jar包的话就给我留言,留个email,我看到后就发过去。
使用C++实现 Https Server 支持 restful json,可以放在实际开发中使用
本资源是一个 Wowza 支持 RESTful web ...关于如何让 wowza 能够支持 RESTful api 的步骤请参考博客《让你的 wowza 服务器提供 RESTful web 服务》,地址是:http://blog.csdn.net/defonds/article/details/30490271。
restful接口示例代码restful接口示例代码restful接口示例代码restful接口示例代码
基于springmvc3.2.x +tomcat8.0 ,使用ajax 发送restful请求处理数据
restful工具支持最新版本
并且支持RESTful API GET、POST、PUT、DELETE、PATCH的请求。同时使用YYCache做了强大的缓存策略。 拥有 AFNetwork 大部分常用功能,包括网络状态监听等,提供类方法和实例方法调用。 非常好的扩展性,开放出了...
.NET作为客户端,如何调用WEBAPI RESTFUL的服务端 .NET如何开发RESTFUL服务端
做开发restful ws的项目,学习资料少,很多东西不明白,一路走来很感慨,现在小有收获,希望有同样任务的人能够从中受益。资源中包含了五六本关于restful开发的电子书。
C# 一个简单的 Restful 服务端和 Restful 客户端 Demo
Restful C# 服务端篇之实现RestFul Service开发(简单实用)
通常,一个RESTful Web Service将定义基本资源URI、它所支持的表示/响应MIME,以及它所支持的操作。 本文将介绍如何使用Spring创建Java实现的服务器端RESTful Web Services。这个例子将使用浏览器、curl和Fire...
Spring CXF Restful 实例
restful2个例子
RESTFUL接口文档模板,样式好看的接口文档模板,docx格式
restful restful所需要的jar包 ========================================= Restlet, a RESTful Web framework for Java ========================================= http://www.restlet.org -------------------...
支持简单的GET/POST/PUT/DELETE四种常用请求方式,支持请求历史记录已经文件上传等功能。 忒:根据请求的历史记录还可以生成优雅的接口api文档 源码地址:https://gitee.com/xxxxx/xxxxxx(详情见附件)
使用axios自动发送请求,支持筛选, 自定义操作列, 让 RESTful 风格的 CRUD 更简单