`
494078416
  • 浏览: 77785 次
  • 性别: Icon_minigender_1
  • 来自: 青岛
社区版块
存档分类
最新评论

Struts、Ajax、Restful、Web Service 狂想曲框架实现篇(三)

 
阅读更多

在第一篇时就说过框架要在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。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics