struts原理(手写原理)

首先要说明一点的是,本人最近也是刚刚学习struts框架,接触的不是很深,有一些解释不妥当之处,还望大家能够批评指正……
其实呢,struts最重要的就是控制器,而控制器利用的就是dom4j 的xml解析方式来实现action和jsp的前后台数据交互。手写struts原理首先你要在工程里引入dom4j的jar包,
这里写图片描述
上图就是我在自己的工程里加入的jar包
好了,,准备工作大致就这些了。
现在我们利用一个简单的jsp页面和action的数据交互来说一些这个原理,:
简单的写一个jsp页面来进行数据的传入:
login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <base href="<%=basePath%>">

    <title>My JSP 'login.jsp' starting page</title>

    <meta http-equiv="pragma" content="no-cache">
    <meta http-equiv="cache-control" content="no-cache">
    <meta http-equiv="expires" content="0">    
    <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
    <meta http-equiv="description" content="This is my page">
    <!--
    <link rel="stylesheet" type="text/css" href="styles.css">
    -->

  </head>

  <body>
      //简单的form表单,用于提交用户名和密码
      //注意这里form表单的action提交的地址:login.action
    <form action="login.action" method="post">
        username:<input name="username" /><br />
        uesrpass:<input name="userpass" /><br />
        <input type="submit" value="登录" />
    </form>
  </body>
</html>

这样通过form表单就把用户登陆的数据提交到后台的login.action中了
那么现在我就写一下我们后台action中的处理jsp传过来的数据,
login.jsp代码如下:

package com.ruide.action;

public class LoginAction {
    //声明jsp中提交的数据类型以及变量名,
    private String username;
    private String userpass;
    //提供对应的get和set方法
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getUserpass() {
        return userpass;
    }
    public void setUserpass(String userpass) {
        this.userpass = userpass;
    }
    //进行一次规定 我们规定 所有的action的处理请求的方法
    //都叫execute()
    //返回值为String 类型
    public String execute(){
        System.out.println("我的loginaction,我执行了...");

        System.out.println("我是execute方法,我的用户名"+username+"我的密码是"+userpass);
        return "bb";
    }
}

在struts框架中,jsp与action之间的交互远远没有表面上那么简单的,它还需要中间还很多的数据操作,这就是我们要提到的重点,struts运行原理
好了,,现在我们要开始进行重中之重的操作了

大家都知道struts框架都有struts.xml配置文件,在我的这个工程呢,,我通过刚才上文中写的action配置了一个struts.xml文件,代码如下:

<?xml version="1.0" encoding="UTF-8"?>
//struts.xml的根目录
<struts>
    //第二级目录,package,struts是通过包来管理action的
    <package name="my">
        //具体的action类
        <action name="login" class="com.ruide.action.LoginAction">
            //action中execute方法返回的String类型的字符串结果
            //aa bb action中我写的execute方法返回的字符串结果
            <result name="aa">success.jsp</result>
            <result name="bb" type="redirect">login.jsp</result>
        </action>
    </package>
</struts>

下面就是struts框架的核心的东西了, controler类,这个类里面的代码是我们struts框架的核心,重中之重*:*

controler这个类里面利用了dom4j解析来对struts.xml配置文件进行解析,在init方法中利用dom4j解析了struts.xml文件,将struts.xml中所有的标签以及标签属性,标签里面的内容都解析出来,然后根据标签的级别和ActionMessage.java/ActionMapping.java/ResultMessage.java的对应关系将解析出来的信息封装在这几个类中,然后就是dofilter方法,在这里呢,我们用了反射机制(通过类名字找到相应的类),
然后呢通过下面的两行代码创建类对象(不需要new)

Class object=Class.forName(classname);
Object obj=object.newInstance();

找到类之后拿到类中的属性:

Field fs[]=object.getDeclaredFields();

然后将类中的得到的属性数组,用增强for循环得到每一个属性的属性名以及属性值,然后得到相应的set方法,然后把得到的属性值封装到创建的obj对象中,

for (Field f:fs) {
    String paramname=f.getName();
    String paramvalue=request.getParameter(paramname);
    System.out.println(paramname+"="+paramvalue);
    String methodname="set"+
    paramname.substring(0,1).toUpperCase()
    +paramname.substring(1);
    System.out.println(methodname);
    Method m=object.getDeclaredMethod(methodname,String.class);
    m.invoke(obj, paramvalue);
}

最后呢,找到action中的execute方法执行,最后返回result:

//execute方法执行
Method execute=object.getDeclaredMethod("execute");
Object objresult=execute.invoke(obj);
String result=objresult.toString();
System.out.println("要转发的结果为"+result);
//处理转发问题...
ResultMessage rm=am.getResults().get(result);
System.out.println("要转发的类型为");
System.out.println(rm.getResulttype());
System.out.println("转发的路径为"+rm.getResultpath());
if (rm.getResulttype()==null) {//请求转发                                                           
    request.getRequestDispatcher(rm.getResultpath()).forward(request, response);
}else{

    response.sendRedirect(rm.getResultpath());
}

controler.java代码如下:

package com.ruide.struts;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
//写了一个实现filter接口的类,
public class Controler implements Filter {
    //重写destory方法
    public void destroy() {
    }
    //实现init方法
    public void init(FilterConfig filterConfig) throws ServletException {
        //在init方法中 解析配置文件struts.xml
        //一个action 就对应了一个actionmessage
        //多个action应该存放到一个hashmap集合中
        InputStream in=this.getClass().getClassLoader().getResourceAsStream("struts.xml");
        SAXReader reader=new SAXReader();
        Document doc=null;

        try {
            doc=reader.read(in);
        } catch (DocumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        Element root=doc.getRootElement();
        Element pack=root.element("package");
        List<Element> actions=pack.elements("action");
        for (Element action:actions) {
            String actionname=action.attributeValue("name");
            System.out.println(actionname);
            String classname=action.attributeValue("class");
            System.out.println(classname);
            ActionMessage am=new ActionMessage();
            am.setClassname(classname);
            List<Element> results=action.elements("result");
            for (Element result:results) {
                String resultname=result.attributeValue("name");
                System.out.println(resultname);
                String resulttype=result.attributeValue("type");
                System.out.println(resulttype);
                String resultpath=result.getText();
                System.out.println(resultpath);
                //type  redirect null dispatcher
                ResultMessage rm=new ResultMessage();
                rm.setResultpath(resultpath);
                rm.setResulttype(resulttype);//null 请求转发 redirect 重定向
                am.getResults().put(resultname, rm);
            }
            ActionMapping.actions.put(actionname, am);

        }

    }
    //实现dofilter方法
    public void doFilter(ServletRequest req, ServletResponse resp,
            FilterChain chain) throws IOException, ServletException {
        //过滤器  过滤所有的后缀名为.action的请求
        HttpServletRequest request=(HttpServletRequest) req;
        HttpServletResponse response=(HttpServletResponse) resp;

        String uri=request.getRequestURI();
        uri=uri.substring(uri.lastIndexOf("/")+1);
        String actionname=uri.substring(0,uri.indexOf("."));
        ActionMessage am=ActionMapping.actions.get(actionname);
        String classname=am.getClassname();
        //反射得到类对象
        try {
            Class object=Class.forName(classname);
            Object obj=object.newInstance();

            //解析到类了
            //能不能拿到属性
            Field fs[]=object.getDeclaredFields();
            for (Field f:fs) {
                String paramname=f.getName();
                String paramvalue=request.getParameter(paramname);
                System.out.println(paramname+"="+paramvalue);
                String methodname="set"+paramname.substring(0,1).toUpperCase()+paramname.substring(1);
                System.out.println(methodname);
                Method m=object.getDeclaredMethod(methodname,String.class);
                m.invoke(obj, paramvalue);
            }

            //execute方法执行
            Method execute=object.getDeclaredMethod("execute");
            Object objresult=execute.invoke(obj);
            String result=objresult.toString();
            System.out.println("要转发的结果为"+result);
            //处理转发问题...
            ResultMessage rm=am.getResults().get(result);
            System.out.println("要转发的类型为");
            System.out.println(rm.getResulttype());
            System.out.println("转发的路径为"+rm.getResultpath());
            if (rm.getResulttype()==null) {//请求转发
                request.getRequestDispatcher(rm.getResultpath()).forward(request, response);
            }else{
                response.sendRedirect(rm.getResultpath());
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

在controler中提到的几个类,,(ResultMessage.java 、ActionMessage.java、 ActionMapping.java)还没有写,现在补上:

ActionMapping.java代码:

package com.ruide.struts;

import java.util.HashMap;
import java.util.Map;

public class ActionMapping {

    //map集合,存放了action名字和ActionMessage的对应关系
    public static Map<String, ActionMessage> actions=new HashMap<String, ActionMessage>();



}

ActionMessage.java代码:

package com.ruide.struts;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//action 名字 和类名字 和它的结果路径 要对应起来
public class ActionMessage {
    //action对应的类的名字
    private String classname;
    //结果名字 对应着一个ResultMessage
    private Map<String,ResultMessage> results=new HashMap<String,ResultMessage>();

    public String getClassname() {
        return classname;
    }
    public void setClassname(String classname) {
        this.classname = classname;
    }
    public Map<String, ResultMessage> getResults() {
        return results;
    }
    public void setResults(Map<String, ResultMessage> results) {
        this.results = results;
    }




}

ResultsetMessage.java代码:

package com.ruide.struts;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

//action 名字 和类名字 和它的结果路径 要对应起来
public class ActionMessage {
    //action对应的类的名字
    private String classname;
    //结果名字 对应着一个ResultMessage
    private Map<String,ResultMessage> results=new HashMap<String,ResultMessage>();

    public String getClassname() {
        return classname;
    }
    public void setClassname(String classname) {
        this.classname = classname;
    }
    public Map<String, ResultMessage> getResults() {
        return results;
    }
    public void setResults(Map<String, ResultMessage> results) {
        this.results = results;
    }




}

以上呢,就是struts原理的大体内容,,至少我是这么理解的。欢迎大家批评指正。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值