Struts2框架使用及分析

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

第一步导包,不多说了
第二步配置struts2文件




    
    
    
        
        
            
            /hello.jsp
        
    

web.xml中配置struts2核心过滤器


    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    
    
        struts2
        /*
    
public class HelloAction {

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

访问http://localhost:8080/structs2/hello/HelloAction,就访问成功了

默认配置

如果 一些必要参数没写,默认加载的是struts-default下的配置com.opensymphony.xwork2.ActionSupport 这个类


        
            
            
            
            
            
            
            
                /hello.jsp
            
        

struts常量配置

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

外部修改常量的三种方式

  1. 在之前struts.xml的标签下填写

    
    
    
    
    
  1. 在src目录下创建strtus.properties,然后填写键值对如
struts.i18n.encoding=UTF-8
  1. 在web.xml中填写
    
        struts.i18n.encoding
        UTF-8
    

加载的顺序是依次加载的

如果要引入其他配置

在当前struct标签下加入

动态访问一个类

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";
    }
}

根据url访问的话配置

配置一


       
        

            /hello.jsp
        
         

            /hello.jsp
        
        ....
    

//上诉的配置显然比较累赘

配置二
    
    
    
        

            /hello.jsp
        
    
访问的url 为http://......//Demo1Action!delete
 http://......//Demo1Action!add
 ...

//上面注意点是带!感叹号的 这种也是不怎么用的的,搜索引擎在搜索的时候可能因为你这路径的特点,不会收录下啦

配置3:通配符
 

        
        

            /hello.jsp
        
    
为http://......//Demo1Action_delete  http://......//Demo1Action_add

ServetApi

获取request 这些的方式
public class DemoAction extends ActionSupport {


    @Override
    public String execute() throws Exception {

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

        return super.execute();
    }

    public String execute1() throws Exception {

        //原生的request(这些内部实际还是从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();
    }
}

如果不希望每个方法都手动调用获取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;
    }
}
直接实现接口接可以了

原因在于 我们配置了的action 继承与struts-default
然后在struts-default


Struts2框架使用及分析_第1张图片
这里写图片描述

其中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实现了这个接口,默认调用
        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);
        }   
          .....   

获取参数

  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.这种参数提交方式很奇怪 。

  1. 模型驱动
//http://localhost:8080/structs2/api/xxx?name=tom&age=123
public class DemoAction extends ActionSupport implements ModelDriven{
  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的缩写,全称为对象图导航语言,是一种功能强大的表达式语言,它通过简单一致的语法,可以任意存取对象的属性或者调用对象的方法,能够遍历整个对象的结构图,实现对象属性类型的转换等功能。

OGNL表达式的计算是围绕OGNL上下文进行的。

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

        HashMap 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);



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


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


        //调用静态方法
        String name6=(String)Ognl.getValue("@com.fmt.Utils@echo('hello world')",context,ognlContext.getRoot());
        System.out.println(name6);

        //调用静态方法
        Double pi=(Double)Ognl.getValue("@@PI",context,ognlContext.getRoot());
        System.out.println(pi);

        //创建对象
        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);

        //创建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)表达式实际上是使用,实现了ValueStack接口的类OgnlValueStack.它是ValueStack的默认实现类.

public interface ValueStack {
    ....

    Map 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对象和其他相关对象.
  2. struts2把ValueStack对象保存在名为:struts.valueStack的request域中.即ValueStack作用域为request.当action创建的时候,ValueStack就创建了,action被销毁的时候,ValueStack就销毁了
  3. ValueStack中的数据分两部分存放:root(栈结构,CompoundRoot)和context(map形式,OgnlContext)

分析流程

Struts2框架使用及分析_第2张图片
enter image description here

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

    
    
        struts2
        org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
    
    
        struts2
        /*
    
//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);
                //创建actionContext上下文(ActionContext,其实通过ThreadlLocal线程内部维护所以不会出现不同action,共享的问题)
                this.prepare.createActionContext(request, response);
                this.prepare.assignDispatcherToThread();
                        //这是request的包装类StrutsRequestWrapper,重写了getAttribute的方法(先从request取,如果没有再次value stack的栈取,最后从actioncntext取)
                request = this.prepare.wrapRequest(request);
                                //创建ActionMaping对象(是当前请求信息映射为一个对象)(ActionMaping的创建是通过ActionMapper的getMapping方法,而ActionMapper的默认实现是DefaultActionMapper可以从这个类的getMaping方法中查看,答题是解析url构建mappig对象) 
                ActionMapping mapping = this.prepare.findActionMapping(request, response, true);
                //如果解析出来是null 则不会调用action,直接放行
                if(mapping == null) {
                    boolean handled = this.execute.executeStaticResourceRequest(request, response);
                    if(!handled) {
                        chain.doFilter(request, response);
                    }
                } else {
                           //执行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 {
           // 创建了ValueStack 
            ValueStack stack = ((ValueStackFactory)this.dispatcher.getContainer().getInstance(ValueStackFactory.class)).createValueStack();
                     //ValueStack 中context放置了一地参数 进入createContextMap内部一对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;
    }
//执行 this.execute.executeAction(request, response, mapping); 最终进入
public void serviceAction(HttpServletRequest request, HttpServletResponse response, ActionMapping mapping) throws ServletException {
        Map 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();
//此次根据actinMapping的action信息构建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 {
                //代理执行(ActionProxy实现类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 实现类为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()) {
                                 //依次获取拦截器 然后执行拦截器的intercept方法 然后我们看下struts-default.xml文件中的       下的拦截器
                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();
            }

           //同上根据返回走返回的一对拦截器
            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);
            }

....

拦截器使用

//使用拦截器的方式  实现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中配置

  
            
                
                
                
                
                    
                    
                          
                    add,delete
                    
                    change
                    
                    
                    
                
            
       
            

            
                
                    
                /showjs.jsp
        
    

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

你可能感兴趣的:(Struts2框架使用及分析)