在第一篇时就说过框架要在URL上作文章,是的,本文就框架怎样充分利用url上作尽可能详细的说明。
做web开发的不可能对url陌生,早在web1.0时代,url作为统一资源定位符,在对web中资源的如何获得上起到巨大作用。不论用户请求的时静态页面或者是各种图片、脚本文件,通过url总能从web网站获取要访问的资源。Web2.0更是常常使用url作为get请求时参数的传递,如http://xxx.xxx.xxx/xxx.jsp?user=admin。以及近几年很火restful web service 摒弃soap而使用url传递请求参数 都说明合理利用url的可行和流行。
当然不止是使用了url就算好的实践,而是能够做到优雅的使用,保证层次分明和整体的简洁,这才算是好的方式,这也正是本框架对使用url 所追求的目标。
首先来看几个例子:
http://www.cnblogs.com/p2
http://www.xxx.com/index.do?page=2
http://www.xxx.com/product/
http://www.xxx.com/channel.do?channel=product
http://www.xxx.com/product/mobile
http://www.xxx.com/channel.do?channel=product&&subChannel=mobile
相信各位看官不用我说也能明白,这几组的实现肯定第一种实现的方式更佳。抛开它能屏蔽服务器端使用的技术这一特性不说,它还能够更好地说明动态网站的层次结构,让用户在访问时能明确知道在网站的什么位置,而不会觉得是陷入了一个迷宫。
当然上面列举的例子是网站前端所使用的url表现方式,因为表现方式可以多种多样,个人喜好不同,本框架在设计时没有给指定前端url的表现方式,而是定义接口,把这个权利留给使用的用户。框架将考虑更多 通用性的东西而不是 个性 自由的东西。
下面对框架里默认使用的url Router AMPPathRouter做详细的介绍,包括设计的思想和实现的方式。首先AMPPathRouter的用途定位为后台使用。为了理解快速的理解它的工作原理,先来和struts做一下对比。
Struts关于请求的配置:
<action name="login" class="com.lscmjx.action.LoginAction" method="login">
<result name="success">
main.jsp
</result>
<result name="failure">
login.jsp
</result>
</action>
它提交的url会是http://xxx.xxx.xxx/login,访问web服务器时会把此url传递到struts框架交给它处理,之后struts会在struts.xml中寻找login的相关的配置,像上面例子,struts会找到LoginAction的类,并且调用其login的方法。
写到这里,我请问这是最好的方式吗?当然不是,至少我在使用struts时就认为这是相当撇脚的设计。上面例子只是列举一个login方法,假如一个系统中要对后台调用的方法是100个,那岂不是就需要在struts.xml中写100个与之类似的配置。想想都头大,这样繁琐的工作,应该是由框架自己去处理,而不是人工给配置。
再来看实现相同功能的Unicorn web框架的配置。
<action class="com.mh.action.UserAction"></action>
当然提交的url肯定需要包含多一些的信息,来保证能通过url正确调用框架Action里的方法。这里提交的url方式:http://xxx.xxx.xxx/UserAction/login/
通过在url里附加调用的Action类的信息,可以省略为不同的方法都在xml里配置的麻烦。假如UserAction里有100个方法,框架也只需这一行的配置。
有了大体的认识之后,来看框架的核心部分AMPPathRouter的具体实现。
/**
* 检查url是否是此Router类要处理的,/Action/Method/Param 格式的将会被检查合格,返回true
* @param relativeUri
* @param actionMap
* @return
*/
public boolean checkUrl(String relativeUri, Map<String, ActionSupport> actionMap) {
Pattern pattern = Pattern.compile("^/\\w+/\\w+/\\S*");
Matcher matcher = pattern.matcher(relativeUri);
if(matcher.matches()) {
String actionName = relativeUri.split("/")[1];
ActionSupport actionSupport = actionMap.get(actionName);
if(null != actionSupport) {
String actionMethodName = relativeUri.split("/")[2];
Class<?> actionClass = actionSupport.getClass();
Method[] methods = actionClass.getMethods();
for(int i = 0; i < methods.length; i++) {
Method method = methods[i];
String methodName = method.getName();
if(methodName.equals(actionMethodName)) {
return true;
}
}
}
}
return false;
}
/**
* 匹配规则为:
* 1、符合/Action/method/param格式,
* 2、并且Action在actionMap中的确存在
* 3、method在此Action中存在
*/
@Override
public boolean route(String relativeUri, UrlFilter urlFilter) {
Map<String, ActionSupport> actionMap = urlFilter.getActionMap();
if(!this.checkUrl(relativeUri, actionMap)) {
return false;
}
// 拦截Action/Method/Param方式的请求,并构建ActionSupport类的属性
String[] params = relativeUri.split("/");
try {
ActionSupport actionSupport = actionMap.get(params[1]);
if(null == actionSupport) {
throw new Exception("找不到" + params[1] + "类");
}
Class<?> action = actionSupport.getClass();
Method method = action.getMethod(params[2], new Class[] {});
if(params.length > 3) {
this.boxingRequest(urlFilter.getRequest(), params[3]);
}
// 只要找到ActionSupport的子类,则初始化其所具有的属性
Object newInstance = action.newInstance();
this.initActionSupport(newInstance, urlFilter);
String result = (String) method.invoke(newInstance, new Object[] {});
if (null == result || ActionSupport.AJAX.equals(result) || ActionSupport.FORWARD.equals(result)) {
return true;
} else {
urlFilter.getResponse().sendRedirect(result);
return true;
}
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (SecurityException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* 把url中得param加入到request的attribute里
* @param request
* @param parameter
*/
private void boxingRequest(HttpServletRequest request, String parameter) {
String[] parameters = parameter.split("&");
for (int i = 0; i < parameters.length; i++) {
String param = parameters[i];
String[] key_value = param.split("=");
if(key_value.length == 2) {
request.setAttribute(key_value[0], key_value[1]);
}
}
}
/**
* 初始化ActionSupport类中所需的request、response、session、application等对象
* @param obj
* @param urlFilter
*/
private void initActionSupport(Object obj, UrlFilter urlFilter) {
ActionSupport action = (ActionSupport) obj;
action.setRequest(urlFilter.getRequest());
action.setResponse(urlFilter.getResponse());
action.setSession(urlFilter.getSession());
action.setApplication(urlFilter.getApplication());
}
这便是AMPPathRouter的全部内容,其中在把请求分发到ActionSupport的子类 并调用相关方法时 是通过反射实现,其他地方地方都是相当容易理解的。
空说无凭,把框架应用到实战中才是硬道理:
好了,下一篇介绍Action 和 json。
分享到:
相关推荐
使用RESTful Web Service实现转账业务,包括事务处理和并发控制
大神的Restful Web Service 详细介绍,Objectives By the end of this class, you should be able to: Give a working definition of RESTful Web Services actions, Enable a RESTful user in the SM operator ...
《Java RESTful Web Service实战》PDF版本下载
Building a RESTful Web Service with Spring 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权...
RESTful Web Services 中文版 高清 PDF 电子书
RESTful Web Service Primer RESTful Web Service Primer
Java RESTful Web Service实战.pdf Java RESTful Web Service实战.pdf
Restful web service cook book 中文版
Restful Web Service电子书 英文版
restful web service with sse, totourial
rest风格的web service实例,采用java语言编写完成,可为不同客户端提供CURD服务,连接数据表customer后可运行。
restful web service cookbook
本文展示了Http 协议的强大能力, 如何定义什么是Restful Web Service 架构以及以当今RPC 式Web 服务的对比,并解析了Restful web Service 架构的四个特征:可寻址性、无状态性、连通性和统一接口。
使用Spring 实现RESTful Web 服务 demo
因為剛入職 公司要求會使用struts2 restful風格,剛開始都沒聽說過restful,然後在網上找了N久的講解或demo,都沒找到,花了一週 在老大的指導下搞出來了,希望可以幫助到想學restful風格的同學們
Building a RESTful Web Service with Spring
本文展示了Http协议的强大能力,如何定义什么是Restful Web Service架构以及以当今RPC式Web服务的对比,并解析了Restful Web Service架构的四个特征:可寻址性、无状态性、连通性和统一接口.
使用Java创建RESTful Web Service
已经测试可用的,2018最新谷歌浏览器RESTful Web Service离线版包含definitions.json文件
building a restful web service