package jm.hbs.handler;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Iterator;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
/**
* 通用的前端控制器。
* 它的功能包括:
* 1、启动时扫描配置文件,并将其信息装载到内存中,供以后使用。
* 2、当一个请求到来时,ActionServlet会得到请求的Servlet Path
然后找到配置文件中处理该请求的Action类及方法。
* 3、自动创建Action的实例,并调用指定的方法。
* 4、根据方法的返回值,调用某个JSP页面。
*
* @author 刘新福
*/
public class ActionServlet extends HttpServlet {
private static final long serialVersionUID = 2859829600564511977L;
//用来保存配置文件内容的对象。
protected ActionConfigs configs = new ActionConfigs();
/**
* 解析初始化参数configs所指定的配置文件。
* 如果有多个配置文件,用逗号分开。
* 如果没有指定初始化参数,默认值为action-config.xml
*
* @throws ServletException 配置文件不能被解析时。
*/
@SuppressWarnings("unchecked")
public void init() throws ServletException {
//读取初始化参数configs
String config = getInitParameter("configs");
if (config == null) {
//设置缺省配置文件
config = "action-config.xml";
}
//处理多个配置文件的情况
if (config.indexOf(",") != -1) {
String[] configs = config.split(",");
//一次处理每个配置文件
for (int i = 0; i < configs.length; i++) {
String cfg = configs[i].trim();
//装载单个配置文件的内容到configs中。
parseConfig(cfg);
}
} else {
//处理单个配置文件
parseConfig(config);
}
System.out.println(configs.findAction("/member/login"));
}
/**
* 解析参数filename所指定的配置文件。
* 并将其内容装载到内容中。
*
* @param filename 配置文件名,相对于类路径。
* @throws ServletException 配置文件不能被解析时。
*/
@SuppressWarnings("unchecked")
private void parseConfig(String filename) throws ServletException {
//使用类装载器从类路径中打开配置文件
InputStream in = ActionConfigs.class.getClassLoader()
.getResourceAsStream(filename);
//容错处理
if (in == null) {
throw new ServletException("no file named:" + filename
+ " found in your classpath");
}
try {
//使用dom4j解析配置文件
SAXReader reader = new SAXReader();
//读取配置文件内容并构造文档对象
Document document = reader.read(in);
//获取到actions节点元素
Element root = document.getRootElement();
//迭代根节点寻找所有的action节点
for (Iterator actionIterator = root.elementIterator("action"); actionIterator
.hasNext();) {
//找到某个action节点
Element actionElement = (Element) actionIterator.next();
//将action信息保存到一个ActionConfig对象中
String path = actionElement.attributeValue("path");
String classname = actionElement.attributeValue("class");
String methodname = actionElement.attributeValue("method");
ActionConfig action = new ActionConfig();
action.setClassname(classname);
action.setMethodname(methodname);
action.setPath(path);
//解析并构造ResultConfig对象
parseResultConfigs(action, actionElement);
//将当前的Action配置保存到configs中。
configs.addAction(action);
}
} catch (Exception e) {
e.printStackTrace();
throw new ServletException(e);
} finally {
try {
in.close();
} catch (Exception e) {
}
}
}
/**
* 解析某个Action的配置内容。
* 并将其内容装载到内容中的ResultConfig对象中,
* 同时将ResultConfig加入Action中。
*
* @param actionElement Action的配置内容。
* @param action ActionConfig对象。
*
* @throws ServletException 配置文件不能被解析时。
*/
@SuppressWarnings("unchecked")
private void parseResultConfigs(ActionConfig action, Element actionElement) {
for (Iterator resultIter = actionElement.elementIterator(); resultIter
.hasNext();) {
Element resultElement = (Element) resultIter.next();
String name = resultElement.attributeValue("name");
String path = resultElement.attributeValue("path");
String redirect = resultElement.attributeValue("redirect");
ResultConfig result = new ResultConfig();
result.setName(name);
result.setPath(path);
if (redirect != null) {
result.setRedirect(Boolean.valueOf(redirect));
}
action.addResult(result);
}
}
/**
* 请求的处理方法。
* 该方法首先得到servlet path,然后去掉扩展名。
* 在configs中调用findAction(path)查找ActionConfig
* 根据ActionConfig中的信息创建Action对象,并调用
* 其方法。
* 得到方法的返回值,在actionConfig.findResult(name)
* 得到ResultConfig对象,根据其新信调用目标页面。
*
* @throws ServletException 执行操作发生错误时。
*/
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
//获取servlet path并去掉扩展名
String path = request.getServletPath();
path = path.substring(0, path.lastIndexOf("."));
//查找服务于当前请求的Action信息
ActionConfig actionConfig = configs.findAction(path);
//容错处理
if (actionConfig == null) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
"no config found for path : " + path);
return;
}
//分析Action的类名
String classname = actionConfig.getClassname();
if (classname == null) {
throw new ServletException(
"no class attribute found for path: " + path);
}
//分析要调用方法名
String methodname = actionConfig.getMethodname();
if (methodname == null) {
methodname = "execute";
}
//创建Action对象
Object actionInstance = getActionInstance(classname);
if (actionInstance == null) {
throw new ServletException("fail to create action instance for : "
+ classname);
}
//获取要调用的Method对象
Method method = getMethod(actionInstance, methodname);
if (method == null) {
throw new ServletException("fail to get method for : " + methodname);
}
String resultName = null;
try {
//调用Action对象的指定名称的方法,并接收返回值
resultName = (String) method.invoke(actionInstance, request,
response);
} catch (Exception e) {
e.printStackTrace();
throw new ServletException("error invoking method : " + methodname);
}
//根据返回值来调用页面生成响应
if (resultName != null) {
//得到要调用的页面的信息
ResultConfig resultConfig = actionConfig.findResult(resultName);
if (resultConfig != null) {
//下一个页面的路径和页面名
String nextpage = resultConfig.getPath();
if (resultConfig.isRedirect()) {
//重定向到下一个页面
response.sendRedirect(request.getContextPath() + nextpage);
} else {
//转发到下一个页面
RequestDispatcher dispatcher = getServletContext()
.getRequestDispatcher(nextpage);
dispatcher.forward(request, response);
}
}
}
}
/**
* 获取action实例的指定名称的方法对象。
* @param actionInstance action实例
* @param methodname 方法名称
* @return 给定action实例的指定名称的方法对象,如果没有返回null。
*/
@SuppressWarnings("unchecked")
protected Method getMethod(Object actionInstance, String methodname) {
Class actionClass = actionInstance.getClass();
try {
Method method = actionClass.getDeclaredMethod(methodname,
HttpServletRequest.class, HttpServletResponse.class);
return method;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* 获取Action的实例。
* @param classname action类的全名
* @return 指定类型的action实例,如果无法获得返回null。
*/
protected Object getActionInstance(String classname) {
try {
return Class.forNam
- 1
- 2
前往页