首页 > 代码库 > Struct—自定义一个简单的mystruct

Struct—自定义一个简单的mystruct

传统mvc开发总结:

         1. 跳转代码写死,不灵活

         2. 每次都去写servlet,web.xml中配置servlet!

                   (配置目的: 请求, Servlet处理类)

一个简单的struct案例,描述如下

登陆、注册

         登陆成功     首页

   登入失败     登入页

注册成功      登陆页

 

整理如下

技术分享

 


 项目列表如下

技术分享

 

代码实现

前台页面登入页:

<form action="${pageContext.request.contextPath }/login.action" name="frmLogin"  method="post">
   	   用户名: <input type="text" name="name"> <br/>
   	   密码: <input type="text" name="pwd"> <br/>
   	   <input type="submit" value="http://www.mamicode.com/登陆"> <br/>
   	</form>

注册页:

<form action="${pageContext.request.contextPath }/register.action" name="frmRegister"  method="post">
   	   用户名: <input type="text" name="name"> <br/>
   	    密码: <input type="text" name="pwd"> <br/>
   	   <input type="submit" value="http://www.mamicode.com/注册"> <br/>
</form>

首页

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head> 
    <title>index</title>
  </head>
  
  <body>
    欢迎你的到来,${sessionScope.userInfo.name }
  </body>
</html>

  

 

后台处理代码

1、假设有一个用户类

package com.gqx.entity;

public class User {

	private String name;
	private String pwd;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getPwd() {
		return pwd;
	}
	public void setPwd(String pwd) {
		this.pwd = pwd;
	}
	
}

2、还有一个UserDao类,处理用户的登入问题与注册问题,然后则是还有一个业务逻辑层service

package com.gqx.dao;

import com.gqx.entity.User;
public class UserDao {

	// 模拟登陆
	public User login(User user){
		if ("gqxing".equals(user.getName()) && "888".equals(user.getPwd()) ){
			// 登陆成功
			return user;
		}
		// 登陆失败
		return null;
	}
	
	// 模拟注册
	public void register(User user) {
		System.out.println("注册成功:用户," + user.getName());
	}
}

service

package com.gqx.service;

import com.gqx.dao.UserDao;
import com.gqx.entity.User;




public class UserService {
	private UserDao dao=new UserDao();
	// 模拟登陆
	public User login(User user){
			return dao.login(user);
		
	}
	
	// 模拟注册
	public void register(User user) {
		dao.register(user);
	}
}

3、mystruct.xml文件,对整个页面跳转的逻辑的配置,每一action对应的result表示要跳转的页面的信息和处理他的相关类

<?xml version="1.0" encoding="UTF-8"?>
<mystruct>
	<package>
		<!-- 配置请求路径,与处理action类的关系 -->
		<!-- 
			1. 请求路径与处理Action的关系
			     /login = LoginAction                          login
			      success = /index.jsp                     登陆成功(重定向)
			      loginFaild  = /login.jsp                 登陆失败
		 -->
		<action name="login" class="com.gqx.framework.action.LoginAction" method="login" >
			<result name="loginSuccess" type="redirect">/index.jsp</result>
			<result name="loginFailed">/login.jsp</result>	<!-- 默认是转发 -->
		</action>
		
		<action name="register" class="com.gqx.framework.action.RegisterAction" method="register">
			<result name="registerSuccess">/login.jsp</result>
		</action>
	</package>
</mystruct>

4、写两个类分别用来处理登入和注册响应这两个事件(注册事件和登入事件)。注意这不和servlet相同,这里返回的是一种状态(对应着前面的struct配置的xml文件中要跳转的页面)。

LoginAction类

package com.gqx.framework.action;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gqx.entity.User;
import com.gqx.service.UserService;
/**
 * Action表示动作类 
 * 1. 一个servlet对应一个action 
 * 2. action中负责处理具体的请求
 */
public class LoginAction {

	/**
	 * 处理登陆请求
	 */
	public Object login(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		Object uri = null;

		// 1. 获取请求数据,封装
		String name = request.getParameter("name");
		String pwd = request.getParameter("pwd");
		User user = new User();
		user.setName(name);
		user.setPwd(pwd);

		// 2. 调用Service
		UserService userService = new UserService();
		User userInfo = userService.login(user);
		// 3. 跳转
		if (userInfo == null) {
			// 登陆失败
			uri="loginFailed";	//login.jsp
		} else {
			// 登陆成功
			request.getSession().setAttribute("userInfo", userInfo);
			// 首页
			uri ="loginSuccess";		//index.jsp
		}
		return uri;
	}
}

RegisterAction类

package com.gqx.framework.action;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gqx.entity.User;
import com.gqx.service.UserService;

public class RegisterAction {
	/*
	 * 处理注册事件
	 */
	public Object register(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 1. 获取请求数据,封装
		String name = request.getParameter("name");
		String pwd = request.getParameter("pwd");
		User user = new User();
		user.setName(name);
		user.setPwd(pwd);

		// 2. 调用Service
		UserService userService = new UserService();
		userService.register(user);
		return "registerSuccess"; //login.jsp

	}
}

5、为了能更好的解析mystruct.xml文件,这里写了几个javabean去封装这个xml文件的信息

首先是对result(<result name="loginSuccess" type="redirect">/index.jsp</result>)的信息封装类

package com.gqx.framework.bean;
/**
 * 封装结果视图
 * <result name="loginSuccess" type="redirect">/index.jsp</result>
 * @author Administrator
 *
 */
public class Result {
	private String name; //封装结果的标记
	private String type;	//封装跳转类型,默认为“redirect”—重定向
	private String page;	//封装跳转的页面
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getType() {
		return type;
	}
	public void setType(String type) {
		this.type = type;
	}
	public String getPage() {
		return page;
	}
	public void setPage(String page) {
		this.page = page;
	}
}

然后是action节点的封装

package com.gqx.framework.bean;

import java.util.Map;

/**
 * 封装action节点
 * <action name="login" class="com.gqx.framework.action.LoginAction" method="login" >
			<result name="loginSuccess" type="redirect">/index.jsp</result>
			<result name="loginFailed">/login.jsp</result>	<!-- 默认是转发 -->
 *		</action>
 */
public class ActionMapping {

		private String name;	//封装路径名称
		private String className;	//封装action的类全名
		private String method;	//封装处理方法
		private Map<String, Result> result;	//封装视图集合
		public String getName() {
			return name;
		}
		public void setName(String name) {
			this.name = name;
		}
		public String getClassName() {
			return className;
		}
		public void setClassName(String className) {
			this.className = className;
		}
		public String getMethod() {
			return method;
		}
		public void setMethod(String method) {
			this.method = method;
		}
		public Map<String, Result> getResult() {
			return result;
		}
		public void setResult(Map<String, Result> result) {
			this.result = result;
		}
		
}

最后一个则是对整个action的管理,即管理着mystruct的类,在这里去解析xml文件(这里用到了dom4j的jar包)同时将解析的信息封装到action中去,在这里的构造方法中传入了init()函数(该函数用于封装action信息),然后通过本类去操控需求

package com.gqx.framework.bean;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.management.RuntimeErrorException;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * 加载配置文件,封装整个mystruct.xml
 * @author Administrator
 *
 */

public class ActionMappingManager {
	//保存action的集合(根据action的name去拿result)
	Map<String	, ActionMapping> allAction;
	
	//由于init方法无法被外界被调用(private修饰),这里要写一个无参的构造方法去调用
	public ActionMappingManager() {
		// TODO Auto-generated constructor stub
		allAction=new HashMap<String, ActionMapping>();
		//初始化
		this.init();
	}
	
	/**
	 * 根据请求路径名称,返回action映射对象
	 * 即有action的name返回一个由actionMapping包装的如下结构
	 * <action name="login" class="com.gqx.framework.action.LoginAction" method="login" >
			<result name="loginSuccess" type="redirect">/index.jsp</result>
			<result name="loginFailed">/login.jsp</result>	<!-- 默认是转发 -->
		</action>
	 */
	/**
	 * 
	 * @param actionName	当前返回路径
	 * @return	返回配置文件中代表action节点的actionMapping对象
	 */
	public ActionMapping getActionMapping(String actionName) {
		// TODO Auto-generated method stub
		if (actionName == null) {
			throw new RuntimeException("传入参数不能为空!");
		}
		ActionMapping actionMapping=allAction.get(actionName);
		if (actionMapping==null) {
			throw new RuntimeException("路径在mystruct中找不到!请检查。");
		}
		return actionMapping;
	}
	
	//初始化allAction集合
	private void init() {
		// TODO Auto-generated method stub
		/****************dom4j读取配置文件**********/
		try {
			//1、得到解析器
			SAXReader reader=new SAXReader();
			//得到src/下的文件流
			InputStream insStream=this.getClass().getResourceAsStream("/mystruct.xml");
			//2、加载文件
			Document doc=reader.read(insStream);
			//3、得到根文件
			Element rootElement=doc.getRootElement();
			//4、得到package节点
			Element elem_package=rootElement.element("package");
			//5/5得到package节点下的所有action节点
			List<Element> listAction=elem_package.elements("action");
			//6、遍历action且封装
			for (Element element : listAction) {
				//6、1封装一个ActionMapping对象
				ActionMapping actionMapping=new ActionMapping();
				/**
				 * <action name="login" class="com.gqx.framework.action.LoginAction" method="login" >
						<result name="loginSuccess" type="redirect">/index.jsp</result>
						<result name="loginFailed">/login.jsp</result>	<!-- 默认是转发 -->
					</action>
				 */
				//封装action
				actionMapping.setName(element.attributeValue("name"));
				actionMapping.setClassName(element.attributeValue("class"));
				actionMapping.setMethod(element.attributeValue("method"));
				
				//封装action下的result
				Map<String, Result> results=new HashMap<String, Result>();
				//得到当前action下所有的result子节点
				Iterator<Element> iterator=element.elementIterator("result");
				while (iterator.hasNext()) {
					//当前迭代的每一result
					Element element2 = (Element) iterator.next();
					Result result =new Result();
					//封装
					result.setName(element2.attributeValue("name"));
					result.setType(element2.attributeValue("type"));
					result.setPage(element2.getTextTrim());
					//添加到results中
					results.put(result.getName(), result);
				}
				
				actionMapping.setResult(results);
				//6、2actionMapping添加到Map集合中
				allAction.put(actionMapping.getName(), actionMapping);

			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			throw new RuntimeException("xml读取失败,初始化错误!");
		}
	}
	
}

6、最后则是写全局的控制器ActionServlet,由它来管理ActionMappingManager中要跳转的页面信息,如外界通过访问http://localhost:8080/mystruct/login.jsp发来http://localhost:8080/mystruct/login.action请求,首先将其解析成login,根据这个login名字在mystruct中找到对应的class类(class="com.gqx.framework.action.LoginAction")和方法(method="login"),同时根据方法名称和参数得到类中的方法,通过反射得到调动其方法,便可得到一个返回的uri(表是状态,如:loginSuccess),然后由配置文件(管理类ActionMappingManager)依据uri来控制要跳转的相应页面。

package com.gqx.framework;

import java.io.IOException;


import java.lang.reflect.Method;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.gqx.framework.bean.ActionMapping;
import com.gqx.framework.bean.ActionMappingManager;
import com.gqx.framework.bean.Result;

public class ActionServlet extends HttpServlet {

	/**
	 * 核心控制器,此项目只有一个servlet
	 * 拦截所有的以action结尾的请求
	 */
	private static final long serialVersionUID = 1L;
	
	ActionMappingManager actionMappingManager;
	@Override
	public void init() throws ServletException {
		// TODO Auto-generated method stub
		//第一次访问时启动时候执行,希望启动的时候执行,在xml文件中配置load-on-startup在启动的是执行
		
		//配置文件的读取,在ActionMappingManage的构造方法中调用了init方法。
		actionMappingManager=new ActionMappingManager();
	}

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		try {
			//1、获取请求的uri,得到请求的路径名称【login】
			String uri=request.getRequestURI();
			
			//得到login,根据login去mystruct.xml配置文件去第2步
			String actionName=uri.substring(uri.lastIndexOf("/")+1,uri.indexOf(".action"));
			
			//	2、根据路径名称,读取配置文件,得到类的全名
			ActionMapping actionMapping=actionMappingManager.getActionMapping(actionName);
			String className=actionMapping.getClassName();
			
			//当前请求的处理方法【method="login】
			String method=actionMapping.getMethod();
			//3、通过反射创建对象,调用方法,获取方法返回的标记
			Class<?> clazz=Class.forName(className);
				//实例化,创建对象
			Object object=clazz.newInstance();
			/**
			 *   这里的参数只能是HttpServletRequest.class,不能是request.class。
			 *   因为request是一个实现类,而这里必须是以接口.class为参数
			 */
			Method m=clazz.getDeclaredMethod(method, HttpServletRequest.class,HttpServletResponse.class);
		
			//调用方法返回的标记
			String returnValue=http://www.mamicode.com/(String) m.invoke(object,request,response);"redirect".equals(type)) {
				response.sendRedirect(request.getContextPath()+page);
			}else {
				request.getRequestDispatcher(page).forward(request, response);
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}

	public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		this.doGet(request, response);
	}

}

最后则是配置这个Actionservlet在服务器的web.xml文件了

<!-- 核心控制器 -->
  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>ActionServlet</servlet-name>
    <servlet-class>com.gqx.framework.ActionServlet</servlet-class>
    <!-- 启动的时候执行servlet的初始化方法 -->
    <load-on-startup>1</load-on-startup>
  </servlet>

  <servlet-mapping>
    <servlet-name>ActionServlet</servlet-name>
    <!-- 拦截所有的action -->
    <url-pattern>*.action</url-pattern>
  </servlet-mapping>

  

最后我们登入的时候就会看到这个效果了:

技术分享

 

Struct—自定义一个简单的mystruct