Struts2框架使用及分析

原文鏈接:http://blog.csdn.net/qq_22329521/article/details/74547658

第一步導包,不多說了
第二步配置struts2文件
<?xml version="1.0" encoding="utf-8" ?>
<!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"
        "http://struts.apache.org/dtds/struts-2.3.dtd">

<struts>
    
    <!--
    package:將Action配置封裝,就是可以在Package中配置很多action
            name:給包起名字,起到標識作用,隨便起,不能其包名重復
            namespace屬性:給action的訪問路徑定義一個命名空間
            extends屬性:繼承一個指定包(struts-default在struts2-core jar包下有struts-default.xml中有package struts-default)
            abstract屬性:包是否為抽象的;標識性屬性。標識該包不能獨立運行。專門被繼承
    -->
    <package name="hello" namespace="/hello" extends="struts-default">
        <!-- action 元素:配置action類
                     name屬性:決定了返回Action訪問資源名
                     class屬性:action的完整類名
                     method屬性:指定調(diào)用action中的那個方法來處理請求-->
        <action name="HelloAction" class="com.fmt.struct.HelloAction" method="hello">
            <!--result 元素:結(jié)果配置
                     name:標識結(jié)果處理的名稱:與action的返回值對應
                     type屬性:指定調(diào)用那個result類來處理結(jié)果默認使用轉(zhuǎn)發(fā)(在繼承的struts-default包中有result的配置已經(jīng)設置好了)(type提供重定向,轉(zhuǎn)發(fā),重定向action,轉(zhuǎn)發(fā)action)
                     標簽體:填寫頁面的相對路徑-->
            <result name="success" type="dispatcher">/hello.jsp</result>
        </action>
    </package>
</struts>

web.xml中配置struts2核心過濾器

<!-- struts2 核心過濾器-->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
public class HelloAction {

    public String hello(){
        System.out.println("hello");
        return "success";
    }
}

訪問http://localhost:8080/structs2/hello/HelloAction,就訪問成功了

默認配置

如果 一些必要參數(shù)沒寫,默認加載的是struts-default下的配置com.opensymphony.xwork2.ActionSupport 這個類

<struts>
        <package name="default" namespace="/default" extends="struts-default" >
            <!-- 找不到包下的action,會使用Demo2Action作為默認action處理請求 -->
            <default-action-ref name="Demo2Action"></default-action-ref>
            <!-- method屬性:execute  -->
            <!-- result的name屬性:success  -->
            <!-- result的type屬性:dispatcher 轉(zhuǎn)發(fā)  -->
            <!-- class屬性:com.opensymphony.xwork2.ActionSupport -->
            <action name="Demo2Action"   >
                <result  >/hello.jsp</result>
            </action>
        </package>
</struts>

struts常量配置

struts的基本常量是在struts2-corejar中的org.apache.struts2中的default.properties中有基本的常量

外部修改常量的三種方式

  1. 在之前struts.xml的<struts>標簽下填寫
<!--i18:國際化,解決post提交亂碼-->
    <constant name="struts.i18n.encoding" value="UTF-8"></constant>
    <!--指定訪問action時的后綴名
    如果value改為do:http://....../HelloAction.do
    -->
    <constant name="struts.action.extension" value="action,,"></constant>
    <!--是否是開發(fā)模式(更多的好處可以在default.properties文件下看)
               1,可以熱加載配置(不需要重啟服務)
               2.提供了更多的錯誤信息,方便開發(fā)時的調(diào)試
    -->
    <constant name="struts.devMode" value="true"></constant>
  1. 在src目錄下創(chuàng)建strtus.properties,然后填寫鍵值對如
struts.i18n.encoding=UTF-8
  1. 在web.xml中填寫
    <context-param>
        <param-name>struts.i18n.encoding</param-name>
        <param-value>UTF-8</param-value>
    </context-param>

加載的順序是依次加載的

如果要引入其他配置

在當前struct標簽下加入
<include file="com/fmt/struct/struts.xml"/>

動態(tài)訪問一個類

public class Demo1Action {
    public String add(){
        System.out.println("add");
        return "success";
    }
    public String delete(){
        System.out.println("delete");
        return "success";
    }
    public String change(){
        System.out.println("change");
        return "success";
    }
    public String find(){
        System.out.println("find");
        return "success";
    }
}

根據(jù)url訪問的話配置

配置一
<package name="dynamic" namespace="/dynamic" extends="struts-default">

       
        <action name="Demo1Action_add" class="com.fmt.b_dynamic.Demo1Action"
                method="add">

            <result name="success" type="dispatcher">/hello.jsp</result>
        </action>
         <action name="Demo1Action_delete" class="com.fmt.b_dynamic.Demo1Action"
                method="delete">

            <result name="success" type="dispatcher">/hello.jsp</result>
        </action>
        ....
    </package>

//上訴的配置顯然比較累贅

配置二
    <!--配置動態(tài)方法調(diào)用常量
        默認是關(guān)閉的,需要重啟
    -->
    <constant name="struts.enable.DynamicMethodInvocation" value="true"></constant>
    <package name="dynamic" namespace="/dynamic" extends="struts-default">
        <action name="Demo1Action" class="com.fmt.b_dynamic.Demo1Action"
                >

            <result name="success" type="dispatcher">/hello.jsp</result>
        </action>
    </package>
訪問的url 為http://......//Demo1Action!delete
 http://......//Demo1Action!add
 ...

//上面注意點是帶!感嘆號的 這種也是不怎么用的的,搜索引擎在搜索的時候可能因為你這路徑的特點,不會收錄下啦

配置3:通配符
 <package name="dynamic" namespace="/dynamic" extends="struts-default">

        <!--動態(tài)調(diào)用方式,使用通配符的樣子-->
        <action name="Demo1Action_*" class="com.fmt.b_dynamic.Demo1Action"
                method="{1}">

            <result name="success" type="dispatcher">/hello.jsp</result>
        </action>
    </package>
為http://......//Demo1Action_delete  http://......//Demo1Action_add

ServetApi

獲取request 這些的方式
public class DemoAction extends ActionSupport {


    @Override
    public String execute() throws Exception {

        //session域
        Map<String, Object> session = ActionContext.getContext().getSession();
        session.put("name","session");
        //application
        Map<String, Object> application = ActionContext.getContext().getApplication();
        application.put("name","application");
        /**
         *  //request域(struct2并不推薦使用原生的request域中)
            Map<String, Object>  request = (Map<String, Object>) ActionContext.getContext().get("request");
         */
        //直接使用,推薦
        ActionContext.getContext().put("name","request域");

        return super.execute();
    }

    public String execute1() throws Exception {

        //原生的request(這些內(nèi)部實際還是從ActionContext中獲取)
        javax.servlet.http.HttpServletRequest request = ServletActionContext.getRequest();

        //原生的Response
        HttpServletResponse response = ServletActionContext.getResponse();

        //原生的ServletContext
        ServletContext servletContext = ServletActionContext.getServletContext();

        //獲取session對象
        HttpSession session = request.getSession();
        return super.execute();
    }
}

如果不希望每個方法都手動調(diào)用獲取request可以采用下面方式

public class DemoAction extends ActionSupport implements ServletRequestAware{

    HttpServletRequest request;
    @Override
    public String execute() throws Exception {

    }

    @Override
    public void setServletRequest(HttpServletRequest httpServletRequest) {
         this.request=httpServletRequest;
    }
}
直接實現(xiàn)接口接可以了

原因在于 我們配置了的action 繼承與struts-default
然后在struts-default


這里寫圖片描述

其中interceptor-stack是個攔截棧,我們查看servletConfig 所對應的對象他的class是 org.apache.struts2.interceptor.ServletConfigInterceptor

public String intercept(ActionInvocation invocation) throws Exception {
        Object action = invocation.getAction();
        ActionContext context = invocation.getInvocationContext();
        HttpServletRequest request;
        //這里就是攔截器做的操作,如果我們當前這個action實現(xiàn)了這個接口,默認調(diào)用
        if(action instanceof ServletRequestAware) {
            request = (HttpServletRequest)context.get("com.opensymphony.xwork2.dispatcher.HttpServletRequest");
            ((ServletRequestAware)action).setServletRequest(request);
        }

        if(action instanceof ServletResponseAware) {
            HttpServletResponse response = (HttpServletResponse)context.get("com.opensymphony.xwork2.dispatcher.HttpServletResponse");
            ((ServletResponseAware)action).setServletResponse(response);
        }   
          .....   

獲取參數(shù)

  1. 通過成員變量獲取
    //http://localhost:8080/structs2/api/xxxx?name=tom
public class DemoAction extends ActionSupport{
 @Override
    public String execute() throws Exception {
        System.out.println(name);
        return super.execute();
    }
    public String name;
    public String getName(){
        return name;
    }
    public void setName(String name) {
        this.name = name;
    } 
    //每次訪問一個action的時候會new一個action對象出來
    public DemoAction() {
    System.out.println("init");
    }
}
  
  1. 封裝一個對象來獲取
//http://localhost:8080/structs2/xxx?mUser.name=tom&mUser.age=123
public class User {
    public String name;
    public int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

public class DemoAction extends ActionSupport{
public User mUser
 @Override
    public String execute() throws Exception {
        System.out.println(mUser.toString());
        return super.execute();
    }
        public User getmUser() {
        return mUser;
    }

   public void setmUser(User mUser) {
        this.mUser = mUser;
    }
}

但是帶mUser.這種參數(shù)提交方式很奇怪 。

  1. 模型驅(qū)動
//http://localhost:8080/structs2/api/xxx?name=tom&age=123
public class DemoAction extends ActionSupport implements ModelDriven<User>{
  public User mUser=new User();
  public String execute() throws Exception {
        System.out.println(mUser.toString());
        return super.execute();
    }
  @Override
    public User getModel() {
        return mUser;
    }
   
}

OGNL語法

OGNL是Object-Graph Navigation Language的縮寫,全稱為對象圖導航語言,是一種功能強大的表達式語言,它通過簡單一致的語法,可以任意存取對象的屬性或者調(diào)用對象的方法,能夠遍歷整個對象的結(jié)構(gòu)圖,實現(xiàn)對象屬性類型的轉(zhuǎn)換等功能。

OGNL表達式的計算是圍繞OGNL上下文進行的。

  @Test
    public void fun1() throws OgnlException {
        User rootUser=new User("root",12);

        HashMap<String, User> context = new HashMap<>();

        context.put("user1",new User("root1",13));

        context.put("user2",new User("root2",14));
        OgnlContext ognlContext = new OgnlContext();

        ognlContext.setRoot(rootUser);
        ognlContext.setValues(context);

        //取出root中user對象的name屬性
        String name= (String) Ognl.getValue("name",context,ognlContext.getRoot());
        Integer age= (Integer) Ognl.getValue("age",context,ognlContext.getRoot());
       System.out.println(name+"age="+age);

       //#是從context中取值user1位鍵
        String name1= (String) Ognl.getValue("#user1.name",context,ognlContext.getRoot());
        Integer age1= (Integer) Ognl.getValue("#user1.age",context,ognlContext.getRoot());
        System.out.println(name1+"age="+age1);


        //修改Root中的值
        String name2= (String) Ognl.getValue("name='jack'",context,ognlContext.getRoot());
        Integer age2= (Integer) Ognl.getValue("age",context,ognlContext.getRoot());
        System.out.println(name2+"age="+age2);

        //修改Root中的值
        String name3= (String) Ognl.getValue("#user1.name='tom'",context,ognlContext.getRoot());
        Integer age3= (Integer) Ognl.getValue("#user1.age",context,ognlContext.getRoot());
        System.out.println(name3+"age="+age3);



        //調(diào)用root中的對象方法
        Ognl.getValue("setName('lilei')",context,ognlContext.getRoot());
        String name4= (String) Ognl.getValue("getName()",context,ognlContext.getRoot());
        System.out.println(name4);


        //調(diào)用map中的對象方法
        String name5= (String) Ognl.getValue("#user1.setName('11'),#user1.getName()",context,ognlContext.getRoot());
        System.out.println(name5);


        //調(diào)用靜態(tài)方法
        String name6=(String)Ognl.getValue("@com.fmt.Utils@echo('hello world')",context,ognlContext.getRoot());
        System.out.println(name6);

        //調(diào)用靜態(tài)方法
        Double pi=(Double)Ognl.getValue("@@PI",context,ognlContext.getRoot());
        System.out.println(pi);

        //創(chuàng)建對象
        Integer size= (Integer) Ognl.getValue("{'1','2','3','4'}.size()",context,ognlContext.getRoot());
        System.out.println(size);
        Character number= (Character) Ognl.getValue("{'1','2','3','4'}[2]",context,ognlContext.getRoot());
        System.out.println(number);
        Character number1= (Character) Ognl.getValue("{'1','2','3','4'}.get(2)",context,ognlContext.getRoot());
        System.out.println(number1);

        //創(chuàng)建map
        Integer map_size= (Integer) Ognl.getValue("#{'name':'tom','age':18}.size()",context,ognlContext.getRoot());
        System.out.println(map_size);
    }

ValueStack

ValueStack是一個接口,在struts2中使用OGNL(Object-Graph Navigation Language)表達式實際上是使用,實現(xiàn)了ValueStack接口的類OgnlValueStack.它是ValueStack的默認實現(xiàn)類.

public interface ValueStack {
    ....

    Map<String, Object> getContext();
    ...
    CompoundRoot getRoot();
    ...
}

public class CompoundRoot extends ArrayList {
    public CompoundRoot() {
    }

    public CompoundRoot(List list) {
        super(list);
    }

    public CompoundRoot cutStack(int index) {
        return new CompoundRoot(this.subList(index, this.size()));
    }

    public Object peek() {
        return this.get(0);
    }

    public Object pop() {
        return this.remove(0);
    }

    public void push(Object o) {
        this.add(0, o);
    }
}
  1. ValueStack貫穿整個action的生命周期,每一個action實例都擁有一個ValueStack對象,其中保存了當前action對象和其他相關(guān)對象.
  2. struts2把ValueStack對象保存在名為:struts.valueStack的request域中.即ValueStack作用域為request.當action創(chuàng)建的時候,ValueStack就創(chuàng)建了,action被銷毀的時候,ValueStack就銷毀了
  3. ValueStack中的數(shù)據(jù)分兩部分存放:root(棧結(jié)構(gòu),CompoundRoot)和context(map形式,OgnlContext)

分析流程

enter image description here

首先是web.xml 中配置了攔截器,攔截了請求到StrutsPrepareAndExecuteFilter

    <!-- struts2 核心過濾器-->
    <filter>
        <filter-name>struts2</filter-name>
        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>struts2</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
//StrutsPrepareAndExecuteFilter
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest)req;
        HttpServletResponse response = (HttpServletResponse)res;

        try {
            if(this.excludedPatterns != null && this.prepare.isUrlExcluded(request, this.excludedPatterns)) {
                chain.doFilter(request, response);
            } else {
                //設置編碼和國際化
                this.prepare.setEncodingAndLocale(request, response);
                //創(chuàng)建actionContext上下文(ActionContext,其實通過ThreadlLocal線程內(nèi)部維護所以不會出現(xiàn)不同action,共享的問題)
                this.prepare.createActionContext(request, response);
                this.prepare.assignDispatcherToThread();
                        //這是request的包裝類StrutsRequestWrapper,重寫了getAttribute的方法(先從request取,如果沒有再次value stack的棧取,最后從actioncntext取)
                request = this.prepare.wrapRequest(request);
                                //創(chuàng)建ActionMaping對象(是當前請求信息映射為一個對象)(ActionMaping的創(chuàng)建是通過ActionMapper的getMapping方法,而ActionMapper的默認實現(xiàn)是DefaultActionMapper可以從這個類的getMaping方法中查看,答題是解析url構(gòu)建mappig對象) 
                ActionMapping mapping = this.prepare.findActionMapping(request, response, true);
                //如果解析出來是null 則不會調(diào)用action,直接放行
                if(mapping == null) {
                    boolean handled = this.execute.executeStaticResourceRequest(request, response);
                    if(!handled) {
                        chain.doFilter(request, response);
                    }
                } else {
                           //執(zhí)行action
                    this.execute.executeAction(request, response, mapping);
                }
            }
        } finally {
            this.prepare.cleanupRequest(request);
        }

    }

  public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        Integer counter = Integer.valueOf(1);
        Integer oldCounter = (Integer)request.getAttribute("__cleanup_recursion_counter");
        if(oldCounter != null) {
            counter = Integer.valueOf(oldCounter.intValue() + 1);
        }
         //從本地的ThreadLocal中獲取
        ActionContext oldContext = ActionContext.getContext();
        ActionContext ctx;
        if(oldContext != null) {
            ctx = new ActionContext(new HashMap(oldContext.getContextMap()));
        } else {
           // 創(chuàng)建了ValueStack 
            ValueStack stack = ((ValueStackFactory)this.dispatcher.getContainer().getInstance(ValueStackFactory.class)).createValueStack();
                     //ValueStack 中context放置了一地參數(shù) 進入createContextMap內(nèi)部一對map,有application,params,session等
            stack.getContext().putAll(this.dispatcher.createContextMap(request, response, (ActionMapping)null));
            //返回ActionContext實際還是ValuesStack中的context的
            ctx = new ActionContext(stack.getContext());
        }

        request.setAttribute("__cleanup_recursion_counter", counter);
        ActionContext.setContext(ctx);
        return ctx;
    }
//執(zhí)行 this.execute.executeAction(request, response, mapping); 最終進入
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
        Map<String, Object> extraContext = this.createContextMap(request, response, mapping);
        ValueStack stack = (ValueStack)request.getAttribute("struts.valueStack");
        boolean nullStack = stack == null;
        if(nullStack) {
            ActionContext ctx = ActionContext.getContext();
            if(ctx != null) {
                stack = ctx.getValueStack();
            }
        }

        if(stack != null) {
            extraContext.put("com.opensymphony.xwork2.util.ValueStack.ValueStack", this.valueStackFactory.createValueStack(stack));
        }

        String timerKey = "Handling request from Dispatcher";

        try {
            UtilTimerStack.push(timerKey);
            String namespace = mapping.getNamespace();
            String name = mapping.getName();
            String method = mapping.getMethod();
//此次根據(jù)actinMapping的action信息構(gòu)建action的代理  
            ActionProxy proxy = ((ActionProxyFactory)this.getContainer().getInstance(ActionProxyFactory.class)).createActionProxy(namespace, name, method, extraContext, true, false);
            request.setAttribute("struts.valueStack", proxy.getInvocation().getStack());
            if(mapping.getResult() != null) {
                Result result = mapping.getResult();
                result.execute(proxy.getInvocation());
            } else {
                //代理執(zhí)行(ActionProxy實現(xiàn)類StrutsActionProxy)
                proxy.execute();
            }

            if(!nullStack) {
                request.setAttribute("struts.valueStack", stack);
            }
        } catch (ConfigurationException var17) {
            this.logConfigurationException(request, var17);
            this.sendError(request, response, 404, var17);
        } catch (Exception var18) {
            if(!this.handleException && !this.devMode) {
                throw new ServletException(var18);
            }

            this.sendError(request, response, 500, var18);
        } finally {
            UtilTimerStack.pop(timerKey);
        }

    }
  //StrutsActionProxy
   public String execute() throws Exception {
        ActionContext previous = ActionContext.getContext();
        ActionContext.setContext(this.invocation.getInvocationContext());

        String var2;
        try { 
        //當前的invocation 實現(xiàn)類為DefaultActionInvocation
            var2 = this.invocation.invoke();
        } finally {
            if(this.cleanupContext) {
                ActionContext.setContext(previous);
            }

        }

        return var2;
    }
 //DefaultActionInvocation
     public String invoke() throws Exception {
        String profileKey = "invoke: ";

        String var21;
        try {
            UtilTimerStack.push(profileKey);
            if(this.executed) {
                throw new IllegalStateException("Action has already executed");
            }
             //攔截器組這里使用if 和 interceptor.getInterceptor().intercept(this);是遞歸的操作
            if(this.interceptors.hasNext()) {
                                 //依次獲取攔截器 然后執(zhí)行攔截器的intercept方法 然后我們看下struts-default.xml文件中的      <interceptor-stack name="defaultStack"> 下的攔截器
                InterceptorMapping interceptor = (InterceptorMapping)this.interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);

                try {
                    this.resultCode = interceptor.getInterceptor().intercept(this);
                } finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
                   //之前的攔截器完成,進入我們的action
                this.resultCode = this.invokeActionOnly();
            }

           //同上根據(jù)返回走返回的一對攔截器
            if(!this.executed) {
                if(this.preResultListeners != null) {
                    Iterator i$ = this.preResultListeners.iterator();
                    
                    while(i$.hasNext()) {
                        Object preResultListener = (PreResultListener)i$.next();
                        PreResultListener listener = (PreResultListener)preResultListener;
                        String _profileKey = "preResultListener: ";

                        try {
                            UtilTimerStack.push(_profileKey);
                            listener.beforeResult(this, this.resultCode);
                        } finally {
                            UtilTimerStack.pop(_profileKey);
                        }
                    }
                }

                if(this.proxy.getExecuteResult()) {
                    this.executeResult();
                }

                this.executed = true;
            }

            var21 = this.resultCode;
        } finally {
            UtilTimerStack.pop(profileKey);
        }

        return var21;
    }

 protected String invokeAction(Object action, ActionConfig actionConfig) throws Exception {
        String methodName = this.proxy.getMethod();
        。。。
        //ognl表達式直接掉方法
        methodResult = this.ognlUtil.getValue(methodName + "()", this.getStack().getContext(), action);
        。。。
     String var22 = this.saveResult(actionConfig, methodResult);
     return var22;
    }
已exception 是    defaultStack攔截器組下第一個攔截器 對應的class是com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor

    public String intercept(ActionInvocation invocation) throws Exception {
        String result;
        try {
        //這里的invocation.invoke();就是上面過來的this,形成遞歸
            result = invocation.invoke();
        } catch (Exception var7) {
            if(this.isLogEnabled()) {
                this.handleLogging(var7);
            }

....

攔截器使用

//使用攔截器的方式  實現(xiàn)Interceptor,繼承AbstractInterceptor 以及繼承MethodFilterInterceptor,三種這邊直接使用第三種
public class MyIntercept3  extends MethodFilterInterceptor{
    @Override
    protected String doIntercept(ActionInvocation actionInvocation) throws Exception {
        System.out.println("處理前");
        //放行
        actionInvocation.invoke();
        System.out.println("處理后");
        // return 的意義在于如果你不放行直接返回給result如果放行成功,這個return就沒有意義
        return "success";
    }
}

xml中配置

  <package name="hello" namespace="/hello" extends="struts-default">
            <interceptors>
                <!--注冊攔截器-->
                <interceptor name="MyInter3" class="com.fmt.intercept.MyIntercept3"></interceptor>
                <!--注冊攔截棧-->
                <interceptor-stack name="mystack" >
                    <!-- 自定義攔截器-->
                    <interceptor-ref name="MyInter3">
                          <!--指定那些方法不攔截-->
                    <param name="excludeMethods">add,delete</param>
                    <!--指定那些方法 攔截-->
                    <param name="includeMethods">change</param>
                    </interceptor-ref>
                    <!--引用默認的20個攔截器-->
                    <interceptor-ref name="defaultStack"></interceptor-ref>
                </interceptor-stack>
            </interceptors>
       
            <default-interceptor-ref name="mystack">

            </default-interceptor-ref>
                <action name="HelloAction" class="com.fmt.struct.HelloAction" method="hello">
                    <interceptor-ref name="mystack"></interceptor-ref>
                <result name="success">/showjs.jsp</result>
        </action>
    </package>

參考文章
http://blog.csdn.net/tjcyjd/article/details/6850203
http://501565246-qq-com.iteye.com/blog/1748513

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,106評論 6 542
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,441評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,211評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,736評論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,475評論 6 412
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,834評論 1 328
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,829評論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 43,009評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,559評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 41,306評論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,516評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,038評論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,728評論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,132評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,443評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,249評論 3 399
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,484評論 2 379

推薦閱讀更多精彩內(nèi)容

  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產(chǎn)品,是在 struts1和WebWork的...
    inke閱讀 2,269評論 0 50
  • 1.什么是框架 什么是框架,框架從何而來,為什么使用框架? 1).框架(framework)——半成品: 1.是一...
    賈里閱讀 2,951評論 0 0
  • action中如何接受頁面?zhèn)鬟^來的參數(shù) 第一種情況:(同名參數(shù)) 例如:通過頁面要把id=1 name=tom a...
    清楓_小天閱讀 2,997評論 1 22
  • 1、struts2工作流程 Struts 2框架本身大致可以分為3個部分: 核心控制器FilterDispatch...
    重山楊閱讀 1,532評論 0 38
  • 有沒有那么一首歌,深深的藏在你的心里。可能很久不會去聽它,但是只要前奏一想起,你就會深深的陷入回憶。 看慣了身邊各...
    周詩汶閱讀 519評論 11 2