RESTful风格的支持实践

简介:

RESTful方式的访问确实即方便又易用,确实是非常不错的一种架构模式。前面一直嘴馋了好长时间,但是由于时间及人员关系,一直没有启动,刚开年,时间也有了,人员也到位了,没啥说的,开工!


本人的习惯,在开工之前,先去学习、研究、了解别人是怎么做的,在看了大量的文档及Roy Thomas Fielding博士的论文还有大量的实践之后,对于它是个啥,解决了啥等等有了比较充分的认识,接现来就是实现了。


程序员同学的第一想法是采用Spring中的RESTful方案来进行解决,这个当然马上被我否掉,原因是这个会导致对SpringMVC的依赖,第二会导致所有的实现都和RESTful进行硬绑定,如果有一天,出来另外一种XXXful的支持,程序员们必须要通过修改代码才能实现,这个与本人提倡的一次开发到处使用有冲突,而且会让程序员知道RESTful相关的实现细节,这明显会增加程序员的学习与开发成本。如果要修改Restful的访问方式,还要去修改相关源码,这个也太恶了,难以忍受。


那程序员同学的问题就来了,你说怎么做?


佛家对看事物有三个层次,第一层是看山是山 看水是水,第二层是看山不是山,看水不是水,第三层次是看山还是那山,看水还是那水。


所以对于RESTful这个东东,也是同样的问题,如果套用上面的3个层次来分析的话,大概是这样的:


第一层次:看山是山 看水是水,看到RESTful就是RESTful,于是就直接针对这个做了。当然这个层次比较低,我前面说的程序员同学就是这个思路,缺点上面我都已经讲过了。


第二个层次:看山不是山,看水不是水,看到RESTful的时候,隐隐约约看着,它根本就不是啥新东西,它就是我们常用的WEB访问的一种新的约定和规范,再说得直接一点,它就是一种门面,对原来的访问方式进行了一种新的组织而已。


第三个层次:看山还是那山,看水还是那水,这个时候再看RESTful,就知道它的实质了,它根本就不是个啥,它就是定义了一套新的访问规范而已。


它通过HTTP方法来声明访问方式,它通过ACCEPT来声明返回数据格式,它通过多层的URL路径来传一些参数。


它和具体的代码与控制层实现逻辑有1毛钱关系么??从本来来说是没有的。因此,通过上面的抽象,我们可以认为,RESTful架构实际上可以认为就是一系列的URL地址的进行转换规则,它通过预定义好的规则,把RESTful格式的请求转换成我们原来的已经开发好的一些访问地址就可以了,其它的就该咋咋地好了。


通过上面的讲解,程序员同学似乎懂了我说的意思,于是去噼里啪啦敲代码了,半天以后,代码出来了,大致如下:

规则配置

转换规则定义:


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
< rules >
    < rule pattern = "/users/{id}" >
        < mapping method = "get" accept = "text/html"
                      url = "queryUsersTiny.servicepage" ></ mapping >
        < mapping method = "post" accept = "text/html"
                      url = "addUserTiny.servicepage" ></ mapping >
        < mapping method = "put" accept = "text/html"
                      url = "updateUserTiny.servicepage" ></ mapping >
        < mapping method = "delete" accept = "text/html"
                      url = "deleteUserTiny.servicepage" ></ mapping >
        < mapping method = "get" accept = "text/json"
                      url = "queryUsersTiny.servicejson" ></ mapping >
    </ rule >
    < rule pattern = "/users/new/" >
        < mapping method = "get" accept = "text/html"
                      url = "crud/restful/operate.page" ></ mapping >
    </ rule >
    < rule pattern = "/users/edit/{id}" >
        < mapping method = "get" accept = "text/html"
                      url = "queryUserByIdTiny.servicepage" ></ mapping >
    </ rule >
    < rule pattern = "/users/{id}/classes/{name}" >
        < mapping method = "post" accept = "text/html"
                      url = "queryclasses.servicepage" ></ mapping >
    </ rule >
</ rules >
 
  < div >
 
 
  </ div >
说明:


rules下面放置一系列的url转换规则rule。

rule表示一条转换规则
pattern:属性是一条匹配表达式,表示这种类型的URL地址是归我处理的,它下面可以有占位符,来表示要提取一些值
在它下面呢,有多条的mapping 子规则,mapping 中有如下属性:
method:响应的请求方法
accept:响应的返回类型
url:真正执行的URL

管理器

管理器就是个规则仓库,里面放置了所有的规则。


?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public interface UrlRestfulManager {
     
     String URL_RESTFUL_XSTREAM = "urlrestful" ;
     
     /**
      * 增加restful配置信息
      * @param Rules
      */
     public void addRules(Rules Rules);
     /**
      * 移除restful配置信息
      * @param Rules
      */
     public void removeRules(Rules Rules);
     
     /**
      * 根据请求路径、请求的方法以及请求头的accept 组装此次请求的上下文对象
      * @param requestPath
      * @param httpMethod
      * @param accept
      * @return
      */
     public Context getContext(String requestPath, String httpMethod, String accept);
}



?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class UrlRestfulFileProcessor extends AbstractFileProcessor {
 
     private static final String RESTFUL_EXT_FILENAME = ".restful.xml" ;
 
     private UrlRestfulManager urlRestfulManager;
 
     public boolean isMatch(FileObject fileObject) {
         return fileObject.getFileName().toLowerCase()
                 .endsWith(RESTFUL_EXT_FILENAME);
     }
 
     public void setUrlRestfulManager(UrlRestfulManager urlRestfulManager) {
         this .urlRestfulManager = urlRestfulManager;
     }
 
     public void process() {
         XStream stream = XStreamFactory
                 .getXStream(UrlRestfulManager.URL_RESTFUL_XSTREAM);
         for (FileObject fileObject : deleteList) {
             logger.logMessage(LogLevel.INFO, "正在移除restful文件[{0}]" ,
                     fileObject.getAbsolutePath());
             Rules Rules = (Rules) caches.get(fileObject
                     .getAbsolutePath());
             if (Rules != null ) {
                 urlRestfulManager.removeRules(Rules);
                 caches.remove(fileObject.getAbsolutePath());
             }
             logger.logMessage(LogLevel.INFO, "移除restful文件[{0}]结束" ,
                     fileObject.getAbsolutePath());
         }
         for (FileObject fileObject : changeList) {
             logger.logMessage(LogLevel.INFO, "正在加载restful文件[{0}]" ,
                     fileObject.getAbsolutePath());
             Rules Rules = (Rules) stream.fromXML(fileObject
                     .getInputStream());
             Rules oldRules = (Rules) caches.get(fileObject
                     .getAbsolutePath());
             if (oldRules != null ) {
                 urlRestfulManager.removeRules(oldRules);
             }
             urlRestfulManager.addRules(Rules);
             caches.put(fileObject.getAbsolutePath(), Rules);
             logger.logMessage(LogLevel.INFO, "加载restful文件[{0}]结束" ,
                     fileObject.getAbsolutePath());
         }
     }
}

这个类用于匹配所有的RESTful规则文件并添加到管理器。

这样就可以进行良好的模块化,把各模块中的配置文件统一加载起来,统一使用。易于开发,自动集成。

URL重写处理

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public class RestfulStyleSubstitutionHandler implements
         RewriteSubstitutionHandler {
 
     private static final String Accept = "Accept" ;
     private static final String HTTP_METHOD_KEY = "X-HTTP-METHOD-OVERRIDE" ;
 
     private UrlRestfulManager urlRestfulManager;
 
     public void setUrlRestfulManager(UrlRestfulManager urlRestfulManager) {
         this .urlRestfulManager = urlRestfulManager;
     }
 
     /**
      * 先获取原来的请求路径与UrlRestful的配置进行匹配,把匹配的值放到上下文中,最后重新设置请求的路径。
      */
     public void postSubstitution(RewriteSubstitutionContext context) {
         String originalPath = context.getPath();
         String httpMethod = getHttpMethod(context);
         String requestAccept = context.getParserWebContext().get(Accept);
         Context restfulContext = urlRestfulManager
                 .getContext(originalPath, httpMethod, requestAccept);
         if (restfulContext != null ) {
             ParameterParser parameterParser = context.getParameters();
             setParameter(parameterParser, restfulContext.getVariableMap());
             context.setPath(restfulContext.getMappingUrl());
         }
 
     }
 
     private String getHttpMethod(RewriteSubstitutionContext context) {
         WebContext webContext = context.getParserWebContext();
         String httpMethod = webContext.get(HTTP_METHOD_KEY);
         if (StringUtil.isBlank(httpMethod)) {
             httpMethod = webContext.getRequest().getMethod();
         }
         return httpMethod;
     }
 
     private void setParameter(ParameterParser parameterParser,
                               Map<String, String> variableMap) {
         if (!CollectionUtil.isEmpty(variableMap)) {
             for (String key : variableMap.keySet()) {
                 String value = variableMap.get(key);
                 if (!StringUtil.isBlank(value)) {
                     String[] parameterValues = value.split( "," );
                     if (parameterValues.length > 1 ) {
                         parameterParser.setObjects(key, parameterValues);
                     } else {
                         parameterParser.setObject(key, value);
                     }
                 }
             }
         }
     }
}
这里的逻辑很简单,得到访问路径然后到管理器中查找看是否有对应的,如果有则进行rewrite处理。

这里有个处理逻辑是:X-HTTP-METHOD-OVERRIDE参数,这个参数可以通过放在HEADER、REQUEST等地方来声明请求类型,如果这个值有,则采用声明的方法,否则用HTTP请求的方法来进行处理,这就允许通过一个POST方法来处理所有的请求方式。推荐采用放在HEADER来进行声明的。

代码行统计

连接口带配置带实现,总结代码行数480行(ValueParser现在还未使用)。

总结

自此,已经完成了对Tiny框架的扩展,支持了RESTful访问方式完美支持,至于如何定义访问格式及路径层次结构规划,那是技术经理和开发人员的事情。对于已经使用Tiny框架的项目,只要增加新的依赖,然后增加配置就可以对外提供RESTful的访问支持了。

对于非Tiny项目,也可以采用上面的开发思路,来做自己的RESTful风格访问支持。

功能特点:对原有实现无任何侵入性(重定向地址要转向RESTful格式的新地址)。

上面的分析及解决方案如有不对或不妥之处,欢迎批评指正。

相关文章
|
2月前
|
存储 JSON API
深入解析RESTful API设计原则与实践
【9月更文挑战第21天】在数字化时代,后端开发不仅仅是编写代码那么简单。它关乎于如何高效地连接不同的系统和服务。RESTful API作为一套广泛采用的设计准则,提供了一种优雅的解决方案来简化网络服务的开发。本文将带你深入了解RESTful API的核心设计原则,并通过实际代码示例展示如何将这些原则应用于日常的后端开发工作中。
|
17天前
|
XML API 网络架构
深入理解RESTful API设计原则与实践
【10月更文挑战第26天】在数字化浪潮中,API(应用程序编程接口)成为连接不同软件组件的桥梁。本文将深入浅出地探讨如何根据REST(Representational State Transfer)原则设计高效、易于维护和扩展的API,同时分享一些实用的代码示例,帮助开发者构建更加健壮和用户友好的服务。
|
1月前
|
XML JSON API
深入浅出:RESTful API 设计实践与最佳应用
【9月更文挑战第32天】 在数字化时代的浪潮中,RESTful API已成为现代Web服务通信的黄金标准。本文将带您一探究竟,了解如何高效地设计和维护一个清晰、灵活且易于扩展的RESTful API。我们将从基础概念出发,逐步深入到设计原则和最佳实践,最终通过具体案例来展示如何将理论应用于实际开发中。无论您是初学者还是有经验的开发者,这篇文章都将为您提供宝贵的指导和灵感。
|
24天前
|
缓存 监控 API
微服务架构下RESTful风格api实践中,我为何抛弃了路由参数 - 用简单设计来提速
本文探讨了 RESTful API 设计中的两种路径方案:动态路径和固定路径。动态路径通过路径参数实现资源的 CRUD 操作,而固定路径则通过查询参数和不同的 HTTP 方法实现相同功能。固定路径设计提高了安全性、路由匹配速度和 API 的可维护性,但也可能增加 URL 长度并降低表达灵活性。通过对比测试,固定路径在性能上表现更优,适合微服务架构下的 API 设计。
|
2月前
|
JSON API 网络架构
掌握RESTful API设计的艺术:从理论到实践
【9月更文挑战第22天】在数字化时代,API已成为连接不同软件和服务的桥梁。本文将引导你了解如何设计高效、可扩展且易于使用的RESTful API,涵盖从基础概念到高级最佳实践的全方位知识。我们将一起探索REST原则、HTTP方法的正确应用、资源命名策略等关键元素,并配以实际代码示例,让你能够将理论转化为实际操作,构建出既符合标准又能应对复杂业务需求的API。
|
1月前
|
消息中间件 缓存 API
构建高性能RESTful API的策略与实践
构建高性能RESTful API的策略与实践
38 0
|
2月前
|
前端开发 API 数据安全/隐私保护
打造高效后端API:RESTful设计原则与实践
【9月更文挑战第4天】在数字化时代的浪潮中,后端API作为连接数据和前端的桥梁,其设计质量直接影响着应用的性能和扩展性。本文将深入探讨RESTful API的设计哲学、核心原则以及如何在实际开发中应用这些原则来构建一个高效、易于维护的后端系统。我们将通过代码示例,揭示如何将理论转化为实践,从而为开发者提供一条清晰的道路,去创造那些能够在不断变化的技术环境中茁壮成长的API。
|
3月前
|
测试技术 API 数据库
构建高效的RESTful API 实践与思考
【8月更文挑战第31天】本文将深入探讨在现代Web开发中,如何设计并实现一个高效且易于维护的RESTful API。通过实际案例分析,我们将了解API设计的基本原则、最佳实践和常见陷阱。文章旨在为开发者提供一套清晰的指导方针,帮助他们在创建API时做出明智的决策。
|
3月前
|
缓存 前端开发 API
打造高效后端API:RESTful设计原则与实践
【8月更文挑战第31天】 在数字化时代,后端API的设计至关重要。本文将深入探讨如何根据RESTful设计原则构建高效、易于维护和扩展的后端API。我们将从基础概念出发,逐步引导至高级实践,确保读者能够理解并应用这些原则,以提升API性能和开发效率。
|
3月前
|
JavaScript 前端开发 API
深入浅出:使用Node.js搭建RESTful API的实践之旅
【8月更文挑战第31天】本文将带你踏上一次Node.js的探险之旅,通过实际动手构建一个RESTful API,我们将探索Node.js的强大功能和灵活性。无论你是初学者还是有一定经验的开发者,这篇文章都将为你提供宝贵的实践经验和深刻的技术洞见。