Struts1.x工作原理概述

一、Struts 的体系结构


 

二、Struts 的流程


 

三、具体原理

1、 Struts的核心是ActionServlet,它本质上就是一个Servlet,在Web.xml中配置ActionServlet为自动启动,指明Struts的配置文件所在位置,并指明Struts中工作条件

<servlet>

      <servlet-name>struts</servlet-name>

      <servlet-class>

          org.apache.struts.action.ActionServlet

      </servlet-class>

      <init-param>

          <param-name>config</param-name>

//如果有多个配置文件,以逗号分隔

          <param-value>/WEB-INF/struts-config.xml</param-value>

      </init-param>

      <load-on-startup>0</load-on-startup>

   </servlet>

   <servlet-mapping>

      <servlet-name>struts</servlet-name>

      <url-pattern>*.do</url-pattern>

   </servlet-mapping>

2、 当服务器容器(Tomcat)启动时,自动加载ActionServlet,并执行init()方法,init方法会用Sax解析Web.xml中指定的Struts配置文件(struts-config.xml),读取里面的action、form-bean、forward、exception及资源文件和插件信息,并将其保存到Struts相应的MAP缓存中。

<struts-config>

   <data-sources/>

   <form-beans>

      <form-beanname="insertForm"type="com.form.InsertForm"></form-bean>

      <form-beanname="updateForm"type="com.form.UpdateForm"></form-bean>

      <form-beanname="searchForm"type="com.form.SearchForm"></form-bean>

   </form-beans>

   <global-exceptions/>

   <global-forwards/>

   <action-mappings>

      <actionpath="/insert"name="insertForm"

          type="com.action.InsertAction"input="/insert.jsp"scope="request"

          validate="true">

          <forwardname="search"path="/search.do"></forward>

      </action>

      <actionpath="/update"name="updateForm"

          type="com.action.UpdateAction"input="/update.jsp"scope="request"

          validate="true">

          <forwardname="search"path="/search.do"></forward>

      </action>

      <actionpath="/search"name="searchForm"

          type="com.action.SearchAction"input="/search.jsp"scope="request"

          validate="true">

          <forwardname="search"path="/search.jsp"></forward>

      </action>

      <actionpath="/delete"type="com.action.DeleteAction"

          input="/search.jsp"scope="request"validate="true">

          <forwardname="search"path="/search.do"></forward>

      </action>

   </action-mappings>

   <message-resources

      parameter="com.yourcompany.struts.ApplicationResources"/>

   <plug-inclassName="org.apache.struts.validator.ValidatorPlugIn">

      <set-propertyproperty="pathnames"

          value="/WEB-INF/validator-rules.xml,

                                                 /WEB-INF/validation.xml"/>

   </plug-in>

</struts-config>

3、 在客户端发来请求以后,Tomcat会检测请求的URL,如果以.do结尾,则交于Struts进行处理:Struts首先分析出请求Action的名称,然后在Action的MAP缓存中找到action的path属性与其对应的action信息,查看name属性是否指向form-bean,如果没有则跳转到第4步。如果有则在form-bean的MAP缓存中找到form-bean的name属性与此action的name属性相匹配的form-bean信息,通过form-bean的type属性找到此form-bean的实体类,利用反射机制得到此实体类的所有以set开头的属性并从URL请求参数中得到相对应的参数名称,调用实体类的set方法将其参数值注入到实体类的属性中。注入完成后检测此action信息的validte属性,如果为真,则执行form-bean的validte方法,如果验证不通过,则返回到action的input属性所指向的页面,如果通过则跳转到第4步

4、 查看此action的parameter、type方法,以确认调用Action的默认方法还是自定义方法进行业务处理,返回ActionForward对象,将响应结果返回给前台
 

<li>商品名称:  <html:text property="bean.name" styleClass="input-text" /></li>   比如这种属性也可以直接加入到其中,ProductForm中的bean.name属性,bean为product,至于为什么可以在这样,RTFSC,

 Object target = bean;
/* 881*/        int delim = findLastNestedIndex(name);                 //获取点字符的index,后面根据其进行属性设置。
/* 882*/        if(delim >= 0)
                {
/* 884*/            try
                    {
/* <-MISALIGNED-> */ /* 884*/                target = getPropertyUtils().getProperty(bean, name.substring(0, delim));
                    }/* 887*/            catch(NoSuchMethodException e)
                    {
/* <-MISALIGNED-> */ /* 887*/                return;
                    }
/* <-MISALIGNED-> */ /* 889*/            name = name.substring(delim + 1);
/* <-MISALIGNED-> */ /* 890*/            if(log.isTraceEnabled())
                    {
/* <-MISALIGNED-> */ /* 891*/                log.trace("    Target bean = " + target);
/* <-MISALIGNED-> */ /* 892*/                log.trace("    Target name = " + name);
                    }
                }/* 897*/        String propName = null;

 

private int findLastNestedIndex(String expression)
            {

/*1035*/        int bracketCount = 0;
/*1036*/        for(int i = expression.length() - 1; i >= 0; i--)
                {/*1037*/            char at = expression.charAt(i);
/*1038*/            switch(at)
                    {
/* <-MISALIGNED-> */ /*1035*/            default:
                        break;
/* <-MISALIGNED-> */ /*1040*/            case 46:                                  //点“.”字符
/* <-MISALIGNED-> */ /*1040*/                if(bracketCount < 1)
/* <-MISALIGNED-> */ /*1041*/                    return i;
                        break;


/*1048*/            case 40: /*1048*/            case 91: /*1048*/                bracketCount--;
                        break;

 

 


/*1054*/            case 41: /*1054*/            case 93: /*1054*/                bracketCount++;
                        break;
                    }
                }

/*1059*/        return -1;
            }

 

 

调用栈片段,红色部分为属性设置部分

Product.setName(String) line: 1258 
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57 
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
Method.invoke(Object, Object...) line: 606 
PropertyUtilsBean.invokeMethod(Method, Object, Object[]) line: 1773 
PropertyUtilsBean.setSimpleProperty(Object, String, Object) line: 1759 
PropertyUtilsBean.setNestedProperty(Object, String, Object) line: 1648 
PropertyUtilsBean.setProperty(Object, String, Object) line: 1677 
BeanUtilsBean.setProperty(Object, String, Object) line: 1022 
BeanUtilsBean.populate(Object, Map) line: 811 
BeanUtils.populate(Object, Map) line: 298 
RequestUtils.populate(Object, String, String, HttpServletRequest) line: 493 
RequestProcessor.processPopulate(HttpServletRequest, HttpServletResponse, ActionForm, ActionMapping) line: 805 
RequestProcessor.process(HttpServletRequest, HttpServletResponse) line: 203 
ActionServlet.process(HttpServletRequest, HttpServletResponse) line: 1194 
ActionServlet.doPost(HttpServletRequest, HttpServletResponse) line: 432 
ActionServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 637 
ActionServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 717 

ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 290 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
OrgFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 204 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
LoginFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 133 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
SQLFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 52 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
FgPageFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 111 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
SiteMeshFilter(ContentBufferingFilter).bufferAndPostProcess(FilterChain, HttpServletRequest, HttpServletResponse, Selector) line: 169 
SiteMeshFilter(ContentBufferingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 126 
MyConfigurableSiteMeshFilter(ConfigurableSiteMeshFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 163 
MyConfigurableSiteMeshFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 81 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
AccountRightChooseFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 98 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
StoreLoginFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 104 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
SetCharacterEncodingFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 142 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 235 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 206 
StandardWrapperValve.invoke(Request, Response) line: 233 
StandardContextValve.invoke(Request, Response) line: 191 
StandardHostValve.invoke(Request, Response) line: 127 
ErrorReportValve.invoke(Request, Response) line: 103 
StandardEngineValve.invoke(Request, Response) line: 109 
CoyoteAdapter.service(Request, Response) line: 293 
Http11AprProcessor.process(long) line: 879 
Http11AprProtocol$Http11ConnectionHandler.process(long) line: 600 
AprEndpoint$Worker.run() line: 1703 
Thread.run() line: 745 

 

五、SpringMVC中也支持表单对象,调用栈如下,

Product.setProductId(String) line: 13 
NativeMethodAccessorImpl.invoke0(Method, Object, Object[]) line: not available [native method] 
NativeMethodAccessorImpl.invoke(Object, Object[]) line: 57 
DelegatingMethodAccessorImpl.invoke(Object, Object[]) line: 43 
Method.invoke(Object, Object...) line: 606 
BeanWrapperImpl$BeanPropertyHandler.setValue(Object, Object) line: 344 
BeanWrapperImpl(AbstractNestablePropertyAccessor).setPropertyValue(AbstractNestablePropertyAccessor$PropertyTokenHolder, PropertyValue) line: 454 
BeanWrapperImpl(AbstractNestablePropertyAccessor).setPropertyValue(PropertyValue) line: 280 
BeanWrapperImpl(AbstractPropertyAccessor).setPropertyValues(PropertyValues, boolean, boolean) line: 95 
ExtendedServletRequestDataBinder(DataBinder).applyPropertyValues(MutablePropertyValues) line: 810 
ExtendedServletRequestDataBinder(DataBinder).doBind(MutablePropertyValues) line: 706 
ExtendedServletRequestDataBinder(WebDataBinder).doBind(MutablePropertyValues) line: 189 
ExtendedServletRequestDataBinder(ServletRequestDataBinder).bind(ServletRequest) line: 106 
ServletModelAttributeMethodProcessor.bindRequestParameters(WebDataBinder, NativeWebRequest) line: 150 
ServletModelAttributeMethodProcessor(ModelAttributeMethodProcessor).resolveArgument(MethodParameter, ModelAndViewContainer, NativeWebRequest, WebDataBinderFactory) line: 110 
HandlerMethodArgumentResolverComposite.resolveArgument(MethodParameter, ModelAndViewContainer, NativeWebRequest, WebDataBinderFactory) line: 78 
ServletInvocableHandlerMethod(InvocableHandlerMethod).getMethodArgumentValues(NativeWebRequest, ModelAndViewContainer, Object...) line: 162 
ServletInvocableHandlerMethod(InvocableHandlerMethod).invokeForRequest(NativeWebRequest, ModelAndViewContainer, Object...) line: 129 
ServletInvocableHandlerMethod.invokeAndHandle(ServletWebRequest, ModelAndViewContainer, Object...) line: 111 
RequestMappingHandlerAdapter.invokeHandlerMethod(HttpServletRequest, HttpServletResponse, HandlerMethod) line: 806 
RequestMappingHandlerAdapter.handleInternal(HttpServletRequest, HttpServletResponse, HandlerMethod) line: 729 
RequestMappingHandlerAdapter(AbstractHandlerMethodAdapter).handle(HttpServletRequest, HttpServletResponse, Object) line: 85 
DispatcherServlet.doDispatch(HttpServletRequest, HttpServletResponse) line: 959 
DispatcherServlet.doService(HttpServletRequest, HttpServletResponse) line: 893 
DispatcherServlet(FrameworkServlet).processRequest(HttpServletRequest, HttpServletResponse) line: 970 
DispatcherServlet(FrameworkServlet).doPost(HttpServletRequest, HttpServletResponse) line: 872 
DispatcherServlet(HttpServlet).service(HttpServletRequest, HttpServletResponse) line: 641 
DispatcherServlet(FrameworkServlet).service(HttpServletRequest, HttpServletResponse) line: 846 
DispatcherServlet(HttpServlet).service(ServletRequest, ServletResponse) line: 722 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 305 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 330 
FilterSecurityInterceptor.invoke(FilterInvocation) line: 118 
FilterSecurityInterceptor.doFilter(ServletRequest, ServletResponse, FilterChain) line: 84 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
ExceptionTranslationFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 113 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
SessionManagementFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 103 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
AnonymousAuthenticationFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 113 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
SecurityContextHolderAwareRequestFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 154 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
RequestCacheAwareFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 45 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
ZGUsernamePasswordAuthenticationFilter(AbstractAuthenticationProcessingFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 199 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
LogoutFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 110 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
WebAsyncManagerIntegrationFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 50 
WebAsyncManagerIntegrationFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
SecurityContextPersistenceFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 87 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
HeicheAPIFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 43 
FilterChainProxy$VirtualFilterChain.doFilter(ServletRequest, ServletResponse) line: 342 
FilterChainProxy.doFilterInternal(ServletRequest, ServletResponse, FilterChain) line: 192 
FilterChainProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 160 
DelegatingFilterProxy.invokeDelegate(Filter, ServletRequest, ServletResponse, FilterChain) line: 346 
DelegatingFilterProxy.doFilter(ServletRequest, ServletResponse, FilterChain) line: 262 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210 
CharacterEncodingFilter.doFilterInternal(HttpServletRequest, HttpServletResponse, FilterChain) line: 85 
CharacterEncodingFilter(OncePerRequestFilter).doFilter(ServletRequest, ServletResponse, FilterChain) line: 107 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210 
BasePathFilter.doFilter(ServletRequest, ServletResponse, FilterChain) line: 38 
ApplicationFilterChain.internalDoFilter(ServletRequest, ServletResponse) line: 243 
ApplicationFilterChain.doFilter(ServletRequest, ServletResponse) line: 210 
StandardWrapperValve.invoke(Request, Response) line: 222 
StandardContextValve.invoke(Request, Response) line: 123 
NonLoginAuthenticator(AuthenticatorBase).invoke(Request, Response) line: 472 
StandardHostValve.invoke(Request, Response) line: 168 
ErrorReportValve.invoke(Request, Response) line: 99 
AccessLogValve.invoke(Request, Response) line: 929 
StandardEngineValve.invoke(Request, Response) line: 118 
CoyoteAdapter.service(Request, Response) line: 407 
Http11AprProcessor(AbstractHttp11Processor<S>).process(SocketWrapper<S>) line: 1002 
Http11AprProtocol$Http11ConnectionHandler(AbstractProtocol$AbstractConnectionHandler<S,P>).process(SocketWrapper<S>, SocketStatus) line: 585 
AprEndpoint$SocketProcessor.run() line: 1813 
ThreadPoolExecutor(ThreadPoolExecutor).runWorker(ThreadPoolExecutor$Worker) line: 1145 
ThreadPoolExecutor$Worker.run() line: 615 
TaskThread(Thread).run() line: 745 

 

表单对象中的属性会set进对应的对象,如下代码

public class Product {
 private String productId;
 private int quantity;
 private double listPrice;
 private double unitPrice;
 private boolean status;
 public String getProductId() {
  return productId;
 }
 public void setProductId(String productId) {
  this.productId = productId;
 }
 public int getQuantity() {
  return quantity;
 }
 public void setQuantity(int quantity) {
  this.quantity = quantity;
 }
 public double getListPrice() {
  return listPrice;
 }
 public void setListPrice(double listPrice) {
  this.listPrice = listPrice;
 }
 public double getUnitPrice() {
  return unitPrice;
 }
 public void setUnitPrice(double unitPrice) {
  this.unitPrice = unitPrice;
 }
 public boolean isStatus() {
  return status;
 }
 public void setStatus(boolean status) {
  this.status = status;
 }
}

 

/**
  * 
  * @param product
  * @return
  * @throws JsonProcessingException
  */
 @RequestMapping("product/edit")
 @ResponseBody
 public Map<String, Object> productEdit(Product product)
   throws JsonProcessingException {
  return this.storeService.updateStoreProduct(JSONUtils
    .writeValueAsString(product));

 }

 

<form action="store/product/edit" method="post" accept-charset="gbk">
   <input name="productId" type="hidden" value="${p.productId}">
   
    <div class="card_cont seller">
     <div class="add_list_ul">
      <div class="login_int radio">
       <div class="fl">商品状态</div>
       <label><span class="fl">上架</span> <input name="status"
        value="true" type="radio" [#if p.status]checked="checked"
        [/#if] name="State" class="radio_1" required="required">
       </label> <label><span class="fl">下架</span> <input name="status"
        value="false" type="radio" [#if !p.status]checked="checked"
        [/#if] name="State" class="radio_1" required="required">
       </label>
       <!--  <p class="red">提示:促销中的商品不能下架</p> -->
      </div>

      <div class="seller_list short">
       <span>市场价格</span> <input type="text" value="${p.listPrice?c}" name="listPrice"
        placeholder="请输入市场价格" required="required">
        <i class="radio_1 "></i>
       <p class="fl">元</p>
      </div>
      <div class="seller_list short">
       <span>商城价格</span> <input type="text" value="${p.unitPrice?c}" name="unitPrice"
        placeholder="请输入商城价格" required="required" max="${p.listPrice?c}" data-msg-max=" ">
        <i class="radio_1"></i>
       <p class="fl">元</p>
      </div>

      <div class="seller_list short">
       <span>库存</span> <input type="number" name="quantity"value="${p.quantity?c}"
        placeholder="请输入库存" required="required">
        <i class="radio_1"></i>
       <p class="fl"></p>
      </div>

     </div>
    </div>
   </form>

 

六、在url中也可以使用

<p><a href="<%=CONTEXT%>/store/manager/product/reserveProductAdd.do?actionType=edit&bean.id=<%=result.getId()%>&type=<%=result.getType()%>&listtype=sales&viewpage=sales" class="edit_link"><span>编辑</a></p>

 

其中bean.id也会被设置到bean(product)对象的id属性,后面可以根据id获取整个product对象。列入如下代码

/**
  * 编辑操作,根据对象id获取该对象的Bean放入到Form中,并且返回到编辑信息页面.<br/>
  * 该方法需要在Form对象的Bean中设置Id,既在jsp中传递参数bean.id=value
  * 
  * @param mapping
  * @param form
  * @param request
  * @param response
  * @return
  */
 public ActionForward performEdit(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response) {
  try {
   if (debug) {
    System.out.println("Start the performEdit Method");
   }
   PubForm pForm = (PubForm) form;
   performView(mapping, form, request, response);
   pForm.setPageType(pForm.PAGETYPE_EDIT);
   if (debug) {
    System.out.println("End the performEdit Method");
   }
  } catch (Exception e) {
   generalError(request, e);
   e.printStackTrace();
   return mapping.findForward(FAIL);
  }
  return mapping.findForward(EDIT);
 }

 

经过上述设置就会把bean对象加进form中,后面的操作就可以使用其中的bean对象了。

/**
  * 商品编辑
  */
 public ActionForward performEdit(ActionMapping mapping, ActionForm form,
   HttpServletRequest request, HttpServletResponse response) {

  super.performEdit(mapping, form, request, response);
  ProductForm pform = (ProductForm) form;
  Product product = (Product) pform.getBean();

  // 获取商品主分类
  if (product != null && !StringUtil.isEmpty(product.getId())) {
   ProductCategory mainCategory = ProductHelper
     .getProductMainCategory(product.getId());
   if (mainCategory != null) {
    product.setMainCategory(mainCategory.getId());
   }

   iProductService.putTemplateParam(request, product);

  }

  
  。。。。。。
 }