`
jljlpch
  • 浏览: 323953 次
  • 性别: Icon_minigender_1
  • 来自: 南昌
社区版块
存档分类
最新评论

stripes actionresolve (一)

阅读更多

3.5解析ActionResolver


我们已经了解stripes的生命周期,如何通过配置把可配置的组件组合在一起,又了解了如何通过interceptor把这些组件串起来。现在我们应该了解每步每个组件都做了什么,首先我们要了解是ActionResolver,也就stripes如何通过url path去映射到相对应的action。在DispatcherServlet中第一步生命阶段就是resolveActionBean(ctx);这个方法的主体在:DispatcherHelper.java中:

public static Resolution resolveActionBean(final ExecutionContext ctx) throws Exception {
        return  ctx.wrap( new Interceptor() {
            public Resolution intercept(ExecutionContext ctx) throws Exception {
                // Look up the ActionBean and set it on the context
                ActionBeanContext context = ctx.getActionBeanContext();
                ActionBean bean = StripesFilter.getConfiguration()
.getActionResolver().getActionBean(context);
           //把找到actionbean实例保存在ExcuteContext中。
    ctx.setActionBean(bean);
       // 把找到actionbean实例保存在request中actionBean中,以供在页面或后面的// 程序直接调用actionbean实例
                HttpServletRequest request = context.getRequest();                request.setAttribute(StripesConstants.REQ_ATTR_ACTION_BEAN, bean);
                return null;           }        });    }

 

 上面最重要的一部分是       ActionBean bean = StripesFilter.getConfiguration().getActionResolver().getActionBean(context);       这是通过configuration找到配置或默认的ActionResolverStripes默认是NameBasedActionResolver;它继承于AnnotatedClassActionResolver。它的实质是采用annotation映射。由而我们要定制ActionResolver,最好是继承于AnnotatedClassActionResolver。由于ActionResolver是可配置组件,在stripes启动时,就会生成ActionResolver的子类的实例并运行它们的init(Configuraton)方法。我们先来看一下NameBasedActionResolver.getActionBean(context),这个方法继承于AnnotatedClassActionResolver;
public ActionBean getActionBean(ActionBeanContext context) throws StripesServletException {       
        HttpServletRequest request = context.getRequest();
        String path = getRequestedPath(request);
     //调用本类的getActionBean(context, path)方法,但是此时实例是、、//NameBasedActionResolver,而此实例中又有重写的同名方法,只能是运行子类的方法了。
    ActionBean bean = getActionBean(context, path);
     //把找到actionbean实例放在request中的__stripes_resolved_action。
   request.setAttribute(RESOLVED_ACTION, getUrlBindingFromPath(path));
        return bean;
    }
@Override public ActionBean getActionBean(ActionBeanContext
 context, String urlBinding) throws StripesServletException {
     try {    return super.getActionBean(context, urlBinding);     }
       catch (StripesServletException sse) {
        ActionBean bean = handleActionBeanNotFound(context, urlBinding);
         if (bean != null) {      bean.setContext(context);
                             return bean;           }
            else {               throw sse;            }        }    }

 

 Override父类的同名方法。它的功能是先执行父类的同名方法,如果出现了异常(即没有找到对应的actionbean)就找找看有没有最合适的jsp文件。比如请求user.action,就会找user.jsp或等等。

 

 protected ActionBean handleActionBeanNotFound(ActionBeanContext context, String urlBinding) {
        ActionBean bean = null;
        Resolution view = findView(urlBinding);
    if (view != null) {
      log.debug("Could not find an ActionBean bound to '", urlBinding, "', but found a view ","at '", view, "'. Forwarding the user there instead.");
          bean = new DefaultViewActionBean(view);       }
        return bean;    }
这个方法先执行findView(urlBinding):
protected Resolution findView(String urlBinding) {
   int lastPeriod = urlBinding.lastIndexOf('.');
 String path = urlBinding.substring(0, urlBinding.lastIndexOf("/") + 1);
        String name = (lastPeriod >= path.length()) ? urlBinding.substring(path.length(), lastPeriod)   :    urlBinding.substring(path.length());
        ServletContext ctx = StripesFilter.getConfiguration().getBootstrapPropertyResolver().getFilterConfig().getServletContext();
        try {
            // This will try /account/ViewAccount.jsp
            String jsp = path + name + ".jsp";
            if (ctx.getResource(jsp) != null) {
                return new ForwardResolution(jsp);         }

            // This will try /account/viewAccount.jsp
      name = Character.toLowerCase(name.charAt(0)) + name.substring(1);
            jsp = path + name + ".jsp";
            if (ctx.getResource(jsp) != null) {
                return new ForwardResolution(jsp);        }

            // And finally this will try /account/view_account.jsp
            StringBuilder builder = new StringBuilder();
            for (int i=0; i<name.length(); ++i) {
                char ch = name.charAt(i);
                if (Character.isUpperCase(ch)) {
                    builder.append("_");
                    builder.append(Character.toLowerCase(ch));
                }
                else {     builder.append(ch);     }   }
            jsp = path + builder.toString() + ".jsp";
            if (ctx.getResource(jsp) != null) {
                return new ForwardResolution(jsp);        }            return null;
                }  catch (MalformedURLException mue) {
            return null;        }    }}

 

这个方法很简单,就是找到合适的jsp页面如urlBinding ViewAccount.action            ViewAccount.jsp   viewAccount.jspview_account.jsp,之后就看存不存在三个jsp文件,存在就取最先存在jsp文件。现在回到handleActionBeanNotFound中,找到页面的Resolution,那接下为了上面的程序统一起来,就用这个Resolution生成一个 DefaultViewActionBean(view);
class DefaultViewActionBean implements ActionBean {
    private ActionBeanContext context;
    private Resolution view;
    public DefaultViewActionBean(Resolution view) { this.view = view; }
    public void setContext(ActionBeanContext context) { this.context = context; }
    public ActionBeanContext getContext() { return this.context; }
public Resolution view() { return view; }}

 

这个actionbean很很简单,就是DefaultViewActionBean(Resolution view) { this.view = view; }这个方法。用这个主要是为了和整体代码统一起来。 

现在我们要回到getActionBean(ActionBeanContext     String)看看:

public ActionBean getActionBean(ActionBeanContext context, String path)
            throws StripesServletException {

       String urlBinding = getUrlBindingFromPath(path);
      Class<? extends ActionBean> beanClass = this.formBeans.get(urlBinding);
        ActionBean bean;
        if (beanClass == null) {
            throw new StripesServletException(“emit”);       }
        try {      HttpServletRequest request = context.getRequest();
            if (beanClass.isAnnotationPresent(SessionScope.class)) {
            bean = (ActionBean) request.getSession().getAttribute(path);

          if (bean == null) {
             bean = makeNewActionBean(beanClass, context);
            equest.getSession().setAttribute(path, bean);      }
             bean.setContext(context);    }
            else {
                bean = (ActionBean) request.getAttribute(path);
                if (bean == null) {
                    bean = makeNewActionBean(beanClass, context);
                    bean.setContext(context);
                    request.setAttribute(path, bean); } }
                        return bean;      }
        catch (Exception e) {  。。。。。      }   }

 

这段代码首先从路径中找到urlBinding,再从urlBinding找到对应的actionbean.这两个等会儿分析,先看一下下面的代码,下面简单,从代码我们可以看出actionbean可以通过@SessionScope保存在session中。一般情况都是在request存着。通过调用程序员实现的bean.setContext(context);把上下文传到actionbean中。接下把actionbean的实例放在requestsession)的path属性中。

回到上面的问题,如何找到urlBinding = getUrlBindingFromPath(path);

String getUrlBindingFromPath(String path) {
        String binding = null;
        while (binding == null && path != null) {
            if (this.formBeans.containsKey(path)) {
                binding = path;            }         else {
                int lastSlash = path.lastIndexOf("/");
                if (lastSlash > 0) {
                    path = path.substring(0, lastSlash);    }
                else {    path = null;   }         }     }
                return binding;    }

 

在解决这个问题之前,我们得知道path是什么样的格式,怎么来的。Path是通过getActionBean(ActionBeanContext context)中的            HttpServletRequest request = context.getRequest();        String path = getRequestedPath(request);而得到: 
:  protected String getRequestedPath(HttpServletRequest request) {    String servletPath = null, pathInfo = null;
   if (request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH) != null) {        servletPath = (String) request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH);
       pathInfo    = (String) request.getAttribute(StripesConstants.REQ_ATTR_INCLUDE_PATH_INFO);        }
        else {       servletPath = request.getServletPath();
            pathInfo    = request.getPathInfo();
        }
	
        return (servletPath == null ? "" : servletPath) + (pathInfo == null ? "" : pathInfo);   }

 

servlet规范中,把url路径为成三部分requestURI = contextPath + servletPath + pathInfo

contextPath就是我们应用系统的名称,比如第二章的例子就是register。上面的程序就是取根目录之后URL地址部分,如:/user/register.action/view。我们知道是这种结构,就不难理解上面的程序就是从this.formBeans的找到有没有符合和/user/register.action/view相同的key。没有就再看看有没有/user/register.action这个相同。没有的话就再看/user相同的key.再没有的就是null啦。

在这个方法和上面的方法中都出现this.formBeans,这是什么东西,是map没有错:

 
rivate Map<String,Class<? extends ActionBean>> formBeans =
            new HashMap<String,Class<? extends ActionBean>>();
还记得AnnotatedClassActionResolver是可配置组件呸,应该想到这个formBeans应该在init(Configuration)中设了值。确定在AnnotatedClassActionResolver的init()设了值,但是细心的会问到:这个实例不是NameBasedActionResolver的,而且它也有init(Configuration),先看NameBasedActionResolver的init()方法。
@Override
    public void init(Configuration configuration) throws Exception {
        super.init(configuration);
        addActionBean(DefaultViewActionBean.class);
}
它调用了AnnotatedClassActionResolver。之后增加了一个DefaultViewActionBean的bean。这个是为了找到与之对应的jsp页面而用的。不做分析。
public void init(Configuration configuration) throws Exception {
     is.configuration = configuration;
Set<Class<? extends ActionBean>> beans = findClasses(ActionBean.class);
    ActionClassCache.init(beans);
        for (Class<? extends ActionBean> clazz : beans) {
            addActionBean(clazz);       }
    }

 

 

这个方法先找到所有的actionbean,之后保存在缓存中。再之后分别处理每个bean.

protected <T> Set<Class<? extends T>> findClasses(Class<T> parentType) {
        ResolverUtil<T> resolver = new ResolverUtil<T>();
        resolver.setPackageFilters(getPackageFilters());
        resolver.setLocationFilters(getUrlFilters());

        if (!resolver.loadImplementationsFromContextClassloader(parentType)) {
            ServletContext context = this.configuration.getBootstrapPropertyResolver()
                    .getFilterConfig().getServletContext();

            resolver.loadImplementationsFromServletContext(parentType, context);
        }

        return resolver.getClasses();
这个功能是找到所有actionbean的子类。Stripes1.5有些变化。接下的缓存没有什么好看的,关键在于addActionBean(clazz);循环把每个actionbean及其对应的urlbinging和处理方法加入到this. formBeans中。

 

 protected void addActionBean(Class<? extends ActionBean> clazz) {
       //取得actionbean中如@ UrlBinding(“/user/register.action”)中的/user/register.action值
 String binding = getUrlBinding(clazz);
   // Only process the class if it's properly annotated
   if (binding != null) {
            this.formBeans.put(binding, clazz);
      // Construct the mapping of event->method for the class
    Map<String, Method> classMappings = new HashMap<String, Method>();
           processMethods(clazz, classMappings);
      // Put the event->method mapping for the class into the set of mappings
            this.eventMappings.put(clazz, classMappings);
            // Print out the event mappings nicely
    for (Map.Entry<String,Method> entry : classMappings.entrySet()) {
                String event   = entry.getKey();
                Method handler = entry.getValue();
                boolean isDefault = DEFAULT_HANDLER_KEY.equals(event);
                log.debug("Bound: ", clazz.getSimpleName(), ".", handler.getName(), "() ==> ",
                          binding, isDefault ? "" : "?" + event);
            }
        }
    }
在上在的代码中有两个属性: formBeans、eventMappings,formBeans保存urlbinging的路径和与之对应的actionbean关系。eventMappings保存actionbean类与它的所有的处理事件方法的关系。这样,我们就可以通过路径(urlbinging)找到类,再通过actionbean的类找到它的事件方法。Actionbean类通过分析类的@UrlBinding就可以找到,如果没有,因为actonresolver的实例是基于命名。所以String binding = getUrlBinding(clazz)中调用是子类的方法。
@Override
    public String getUrlBinding(Class<? extends ActionBean> clazz) {
        String binding = super.基于annotation的;
        // If there's no annotated binding, and the class is concrete
        if (binding == null && !Modifier.isAbstract(clazz.getModifiers())) {    binding = getUrlBinding(clazz.getName());       }
        return binding;    }
getUrlBinding先调用父类的getUrlBinding(clazz)方法。之后把actionbean的类名按一定的规则转为urlbing路径。getUrlBinding(String name)就是实现这个功能:

protected String getUrlBinding(String name) {
        // Chop off the packages up until (and including) any base package
        for (String base : getBasePackages()) {
            int i = name.indexOf("." + base + ".");
            if (i != -1) {
                name = name.substring(i + base.length() + 1);}
            else if (name.startsWith(base + ".")) {
                name = name.substring(base.length());}   }
        // If it ends in Action or Bean (or ActionBean) take that off
        if (name.endsWith("Bean")) {
            name = name.substring(0, name.length() - 4);     }
        if (name.endsWith("Action")) {
            name = name.substring(0, name.length() - 6);        }

        // Replace periods with slashes and make sure it starts with one
        name = name.replace('.', '/');
        if (!name.startsWith("/")) {
            name = "/" + name;        }

        // Lastly add the suffix
        name += getBindingSuffix();
        return name;
    }
getUrlBinding(String name)就是一些字符转换,它把如com.morik.action.RegisterAction或者RegisterActionBean,变成Register.action.

解决了路径和actionbean的映射问题。接下来的processMethods(clazz, classMappings);就是如何把actionbean和它的所有的事件方法对应起来。
  protected void processMethods(Class clazz, Map<String,Method> classMappings) {
        // Do the super class first if there is one
        Class superclass = clazz.getSuperclass();
        if (superclass != null) {
            processMethods(superclass, classMappings);
        }

        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if ( Modifier.isPublic(method.getModifiers()) ) {            
 String eventName = getHandledEvent(method);
                DefaultHandler defaultMapping = method.getAnnotation(DefaultHandler.class);
                if (eventName != null) {
                    classMappings.put(eventName, method);
                }
                if (defaultMapping != null) {
                    // Makes sure we catch the default handler
                    classMappings.put(DEFAULT_HANDLER_KEY, method);
                }
            }
        }
    }
这个一个递归方法,它实现了从actionbean所有父类开始找标识为@DefaultHandler和DefaultHandler的处理方法。对于基于命名的方法,
 public String getHandledEvent(Method handler) {
        String name = super.getHandledEvent(handler); 
        if ( name == null && !Modifier.isAbstract(handler.getModifiers())
          &&R esolution.class.isAssignableFrom(handler.getReturnType()) ) {            name = handler.getName();        }
        return name;    }

 

 

它是在解析事件方法时,如果在基于annotion没有找到,就找返回类型为Resolution的非抽象的方法同名方法。处理事件方法一般不会有参数的。 这样就actionResolver就找到与路径对应的actionbean类了,并初始化了类与处事事件方法的关系。 

 

分享到:
评论

相关推荐

    轻量级mvc框架之:stripes (一、约定大于配置)

    Stripes是一个轻量级的Java MVC框架,它的核心设计理念是“约定大于配置”,这使得开发者可以更快地构建Web应用程序,而无需过多的配置文件。在本文中,我们将深入探讨Stripes框架的基础知识,以及它如何简化开发...

    Stripes视图框架demo

    Stripes视图框架是一款轻量级的Java Web框架,它为开发者提供了构建高效、可维护的Web应用程序的工具。这个“Stripes视图框架demo”是用于演示如何使用Stripes来开发Web应用的一个实例,可以帮助初学者快速理解和...

    stripes英文文档(全部)

    Stripes 是一款用于快速开发Web程序的展示层框架,它的设计旨在简化Java Web应用开发流程。在介绍Stripes之前,我们需要了解它与传统框架(如 Struts 1、WebWork 和 Struts 2)的不同之处。传统框架通常要求开发者...

    stripes 和css 一些常用功能

    Stripes是一个Java Web应用框架,它是为了简化Java Web开发而设计的,提供了快速构建Web应用程序的能力。与传统的框架如Struts1和Struts2相比,Stripes有自己独特的优势。首先,Stripes提倡“约定优于配置”的开发...

    stripes入门

    Stripes 是一款专为简化 Java Web 开发流程而设计的开源框架,它以提高开发效率为目标,力求使开发者能够轻松快速地构建 Web 应用程序。与传统 Java Web 框架相比,Stripes 采用了更为简洁的方法论,借鉴了 Ruby on ...

    Stripes 快速入门 pdf 中文版 下载

    ActionBean是Stripes框架的核心组件之一,它负责处理用户的请求,并返回一个表示下一步操作的Resolution对象。ActionBean接口定义了一些基本的方法,如`validate`和`execute`等。 #### 3.2. 处理请求事件 通过在...

    在Stripes中下载excel表格

    #### 一、Stripes框架简介 Stripes是一个基于Java的Web应用开发框架,它采用MVC(Model-View-Controller)架构模式设计,旨在简化Web应用程序的开发流程。相较于其他Java Web框架如Spring MVC或Struts,Stripes框架...

    Folio图书馆系统UI前端框架stripes-components-master

    Stripes-Components是Folio项目的一个子模块,主要负责提供一系列预先构建的UI组件,如按钮、表单、导航栏等,这些组件遵循一致的设计风格和交互模式,可以快速搭建出符合Folio系统规范的界面。由于其基于React,...

    stripes快速入门教程

    和我们熟悉 Struts 1 和 Struts 2 类似,Stripes 同样是一种展示层框架,用于快速构建web程序。在使 用Struts 1,WebWork 和 Struts 2 等框架的时候,通常需要大量额外的 XML 配置,当一个项目达到 一定规模的的时候...

    jsp网页布局利器框架stripes-1.5.6

    Stripes是一个基于Java的轻量级MVC(Model-View-Controller)框架,它专注于简化Web应用程序的开发。在标题“jsp网页布局利器框架stripes-1.5.6”中,提到的“jsp”指的是JavaServer Pages,一种用于创建动态网页的...

    stripes mvc pdf

    #### 一、Stripes框架简介 Stripes是一款新兴的Java Web MVC(Model-View-Controller)框架,它以其简洁、高效和易用的特点受到开发者的青睐。该框架的目标是简化Java Web应用程序的开发过程,并使其更加有趣和高效...

    stripes包,内有例子程序和StripesResources.properties

    Stripes是一个轻量级的Java Web框架,它简化了创建动态、交互式的Web应用程序的过程。这个压缩包"stripes-1.5.6"包含了Stripes框架的一个版本以及相关的示例程序和配置文件,这对于学习和理解Stripes的工作原理非常...

    Stripes1.4.3

    Stripes是一个专为简化Java Web开发而设计的开源框架,其版本1.4.3是该框架的一个稳定发行版。这个框架强调了提高程序员的工作效率和代码的可维护性,通过提供直观的API和强大的特性集,使得构建动态、交互式的Web...

    stripes+spring+mybatis框架

    stripes1.5.7+spring3.1.1+MyBatis3.1.1完整框架 本工程代码已完成了Oracle,MySQL,MSSQL2005三种数据库物理分页方言,并测试可用。 本代码集成了xheditor-1.2.1在线编辑器远程抓取图片功能。 集成了excel导入...

    stripes-1.5.7-src.zip

    Stripes是一个轻量级的Java Web框架,它简化了创建动态、交互式的Web应用程序的过程。这个"stripes-1.5.7-src.zip"文件包含了Stripes框架的源代码版本1.5.7,这对于开发者来说是宝贵的资源,因为可以直接查看和理解...

    stripes+spring+mybatis项目源码下载

    本项目——"stripes+spring+mybatis项目源码下载",便是一个将条纹(Stripes)、Spring和MyBatis三大框架融合的实例,旨在实现一个简洁的网上宠物商店应用。接下来,我们将深入探讨这三个技术的核心概念以及它们在...

    SQL Stripes 2.8.0.900

    SQL Stripes是一个数据库管理和开发工具,版本号2.8.0.900代表了该软件的一个特定更新迭代。在数据库领域,版本号通常表示软件的功能改进、性能优化或者错误修复。以下是关于SQL Stripes 2.8.0.900的一些关键知识点...

    Wordpress Blue Stripes模板

    Wordpress Blue Stripes模板是一款专为WordPress平台设计的网站模板,以其独特的蓝色条纹风格而得名。这款模板适用于各种类型的网站,无论是个人博客、小型企业还是电子商务平台,都能通过其简洁而专业的设计提升...

Global site tag (gtag.js) - Google Analytics