上次我们已经讲解分析了一下Struts原理,这次我们来自己构建一个简单的Struts框架,通过构建Struts框架来了解Struts是如何实现MVC的。
1、回顾Struts原理分析
不解释,接上篇博客,链接地址如下:
http://blog.csdn.net/zs15932616453/article/details/8919349
2、解析XML文件
在上篇博客中,我们已经看出Struts做的就是将MVC中的每一层进行联系,而这些联系其实就是由XML配置文件进行关联的,所以这里我们自己写的Struts框架的第一步就是XML文件的解析。我们使用Struts框架默认的名称struts-config.xml,如下图所示。
解析xml文件,我们用dom4j解析。步骤如下
1)拷贝jar包
2)编写代码,代码比较简单,不做多余解释
package control;
import java.io.InputStream;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
public class XmlConfigReader {
private static XmlConfigReader instance = new XmlConfigReader();
private XmlConfigReader() {
}
public static XmlConfigReader getInstance() {
return instance;
}
/**
* 将XML文档转换成为Document对象
* @param filepath XML文档对象路径
* @return 转换之后的Document对象
*/
public Document XML2Document(String filepath){
SAXReader reader = new SAXReader();
Document document = null;
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream(filepath);
try {
document = reader.read(in);
} catch (DocumentException e) {
e.printStackTrace();
}
return document;
}
}
注意事项:在Java程序中使用dom4j解析xml文件需要注意路径问题,因为web项目发布之后,有些xml文件是不会发布到项目中的,所以就造成了一些文件无法解析在发布的时候找不到。另外web项目发布之后,一些xml文件的相对位置会发生变化,所以在项目中执行很对的xml文件解析也会出现文件未找到错误。具体内容,我们以后专门进行分析。
3、分析结构
上一步我们已经能够将xml文件进行解析,接下来我们分析一下XML文件中各个部分分别对应MVC中的那些部分和各个部分之间如何联系,这一点在上一篇中已经做了相依的解释,这里我们不做多余的解释。
MVC对应关系部分
各部分联系,参见博客,链接如下:
http://blog.csdn.net/zs15932616453/article/details/8901418
4、基础类编写。
了解了各个部分对应关系之后,我们来看一下一些基础类的代码,这些代码与真正的Struts代码基本雷同,所以我们这里不做多余的解释代码如下:
Action.java,代码如下:
package control;
importjavax.servlet.ServletRequest;
importjavax.servlet.ServletResponse;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importmodel.ActionForm;
publicclass Action {
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
ServletRequest request,
ServletResponse response)
throws Exception {
try {
return execute(
mapping,
form,
(HttpServletRequest) request,
(HttpServletResponse)response);
} catch (ClassCastException e) {
return null;
}
}
public ActionForward execute(
ActionMapping mapping,
ActionForm form,
HttpServletRequest request,
HttpServletResponse response)
throws Exception {
return null;
}
}
LoginAction.java,代码如下:
package control;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.ActionForm;
import model.LoginActionForm;
public class LoginAction extends Action {
@Override
public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {
String name=((LoginActionForm)form).getUserName();
String forward="";
//业务处理部分,我们仅作简单的判断是否是“hello”
if("hello".equals(name)){
forward="success";
}else{
forward="error";
}
return mapping.getActionForwards(forward);
}
}
ActionForward.java,代码如下:
package control;
public class ActionForward {
private String name;
private String path;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
}
ActiionMapping.java,代码如下:
package control;
import java.util.HashMap;
public class ActionMapping {
private String path;
private String type;
private String name;
private String scope;
private HashMap<String,ActionForward> actionForwardMap=new HashMap<String,ActionForward>();
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public ActionForward getActionForwards(String ActionForwardName) {
ActionForward actionforward=actionForwardMap.get(ActionForwardName);
return actionforward;
}
public void addActionForward(ActionForward actionForward) {
actionForwardMap.put(actionForward.getName(), actionForward);
}
}
ActionForm.java,代码如下:
package model;
public abstract class ActionForm {
}
LoginActionForm.java,代码如下:
package model;
public class LoginActionForm extends ActionForm {
private String userName;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
}
5、初始化
了解一些基础类之后,我们接下来重点将一些Strtus框架的核心类ActionServlet。首先我们分析Struts初始化工作,Struts初始化执行工作大致分为几个部分,我们这里只讲我们自己写的Struts都执行哪些工作,真正的Struts框架初始化是比较复杂的,我们等到以后再具体分析这些。
在ActionServlet中的init()方法中,我们主要将配置文件中的各个部分读取到Map中,代码如下:
package control;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.ActionForm;
import org.dom4j.Document;
import org.dom4j.Element;
public class ActionServlet extends HttpServlet {
private String config;
private HashMap<String,ActionMapping> actionMappingMap=new HashMap<String,ActionMapping>();
private HashMap<String,String> actionFormMap=new HashMap<String,String>();
@Override
public void init(){
//初始化配置文件
initConfig();
}
/**
* 将struts-config.xml文件中的各个部分初始化到Map中
*
*/
private void initConfig(){
//获取struts-config.xml文件位置,这里我们不错处理,取默认即可
config=getServletConfig().getInitParameter("config");
String filePath="../.."+config;
//读取XML文件,存储到document中
Document doc=XmlConfigReader.getInstance().XML2Document(filePath);
//读取配置信息到列表中,
List<?> actionFormList=doc.selectNodes("struts-config/form-beans/form-bean");
List<?> actionList=doc.selectNodes("struts-config/action-mappings/action");
List<?> actionForwardList=doc.selectNodes("struts-config/action-mappings/action/forward");
//遍历ActionForm列表,将配置信息中的ActionForm信息保存到Map中
for(int i=0;i<actionFormList.size();i++){
String actionFormName=((Element)actionFormList.get(i)).attributeValue("name");
String actionFormType=((Element)actionFormList.get(i)).attributeValue("type");
actionFormMap.put(actionFormName, actionFormType);
}
//遍历ActionMapping列表,将配置信息中的ActionMapping信息保存到Map中
for(int i=0;i<actionList.size();i++){
String actionName = ((Element)actionList.get(i)).attributeValue("name");
String actionType = ((Element)actionList.get(i)).attributeValue("type");
String actionPath = ((Element)actionList.get(i)).attributeValue("path");
String actionScope = ((Element)actionList.get(i)).attributeValue("scope");
ActionMapping actionMapping=new ActionMapping();
//将配置信息加载到ActionMapping中
actionMapping.setName(actionName);
actionMapping.setPath(actionPath);
actionMapping.setType(actionType);
actionMapping.setScope(actionScope);
//遍历ActionForward配置部分,将该部分保存到Action中
for(int j=0;j<actionForwardList.size();j++){
ActionForward actionForward=new ActionForward();
//将配置的ActionForward信息添加到ActionForwar对象中
String actionForwardName=((Element)actionForwardList.get(j)).attributeValue("name");
String actionForwardPath=((Element)actionForwardList.get(j)).attributeValue("path");
actionForward.setName(actionForwardName);
actionForward.setPath(actionForwardPath);
//将ActionFormWard对象添加到Action中
actionMapping.addActionForward(actionForward);
}
//将Action对象添加到ActionMapping中
actionMappingMap.put(actionMapping.getPath(),actionMapping);
}
}
}
6、处理客户端请求
ActionServlet初始化完成之后,我们就可以接受客户请求了,具体的执行代码如下:
package control;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import model.ActionForm;
import org.dom4j.Document;
import org.dom4j.Element;
public class ActionServlet extends HttpServlet {
private String config;
private HashMap<String,ActionMapping> actionMappingMap=new HashMap<String,ActionMapping>();
private HashMap<String,String> actionFormMap=new HashMap<String,String>();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
process(request, response);
}
protected void process(HttpServletRequest request, HttpServletResponse response)
throws IOException, ServletException {
try {
//取得URL
String url=request.getRequestURL().toString();//http://192.168.24.170:8080/StrutsTest/login.do
int start=url.lastIndexOf("/");
int end=url.lastIndexOf(".");
String actionDo=url.substring(start,end);// /login
//获取指定的ActionMapping
ActionMapping actionMapping=(ActionMapping)actionMappingMap.get(actionDo);
//实例化ActionForm
String actionFormType=actionFormMap.get(actionMapping.getName());
ActionForm actionForm=(ActionForm)Class.forName(actionFormType).newInstance();
//获取所有ActionForm中的方法名
Method[] methods=actionForm.getClass().getDeclaredMethods();
//遍历所有方法,将调用所有setter方法初始化
for(int i=0;i<methods.length;i++){
String methodName=methods[i].getName();
if(methodName.contains("set")== true){
String attributeName=methodName.toLowerCase().charAt(3)+methodName.substring(4,methodName.length());
actionForm.getClass().getMethod( methodName,new Class[]{String.class}).invoke(actionForm, new Object[]{request.getParameter(attributeName)});
}
}
//实例化Action
Action action = (Action)Class.forName(actionMapping.getType()).newInstance();
//获取指定的ActionForward对象
ActionForward actionForward=action.execute(actionMapping, actionForm, request, response);
//转发到指定的页面
request.getRequestDispatcher(actionForward.getPath()).forward(request, response);
} catch (Exception e) {
e.printStackTrace();
}
}
}
整合ActionServlet的初始化和客户端请求之后,我们自己写的Struts框架基本就编写完毕了,当然,这只是一个非常简单的实例,很多地方我们都可以进行一些优化。这里主要为了演示,我们就不做过多的工作了。
本文我们主要演示了一个自己写的Struts框架,实例比较简单,下次我们分析一下本篇文章中的XML文件读取的路径相关问题。