首先要说明一点的是,本人最近也是刚刚学习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+"/";
%>
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'login.jsp' starting pagetitle>
<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">
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文件,代码如下:
//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.jspresult>
<result name="bb" type="redirect">login.jspresult>
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 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 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 actions=new HashMap();
}
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 results=new HashMap();
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
public Map getResults() {
return results;
}
public void setResults(Map 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 results=new HashMap();
public String getClassname() {
return classname;
}
public void setClassname(String classname) {
this.classname = classname;
}
public Map getResults() {
return results;
}
public void setResults(Map results) {
this.results = results;
}
}
以上呢,就是struts原理的大体内容,,至少我是这么理解的。欢迎大家批评指正。