利用java反射模拟struts2工作(二)

本文详细阐述了基于Struts2框架实现MVC模式的过程,包括配置文件编写、Servlet控制层、请求处理、Webwork.xml文件加载、方法调用、结果处理及返回策略等关键步骤。介绍了如何通过Servlet作为控制层,解析URL请求,定位Model层,以及如何通过设计模式如状态模式来灵活处理视图层的数据返回。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

继[url=http://z276356445t.iteye.com/blog/1051368]上一篇[/url]文章模拟struts2的工作机制,上一篇主要是对配置文件的编写以及解析,接着是使用servlet来控制对action的访问以及result返回的处理。由servlet来充当Control层,首先来看一下web.xml的配置。

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<servlet>
<servlet-name>baseServlet</servlet-name>
<servlet-class>blog.base.servlet.BaseServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>baseServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<login-config>
<auth-method>BASIC</auth-method>
</login-config>
</web-app>


再来看一下对url请求处理。

/**
*
*/
package blog.base.servlet;

/**
* @author 张廷 2011-4-19下午04:54:41
*
*/
public class UrlParameter {
private String reqURI;
private String action;
private String method;

public UrlParameter(String _reqURI) {
reqURI = _reqURI;
urlHandler();
}

public void urlHandler() {
// 取得请求的action
String reqAction = reqURI.substring(reqURI.lastIndexOf('/') + 1, reqURI.length());
// 如果有指定访问的方法这样处理
if (reqAction.indexOf('!') >= 0) {
action = reqAction.substring(0, reqAction.indexOf('!'));
method = reqAction.substring(reqAction.indexOf('!') + 1, reqAction.indexOf(".action"));
} else {
action = reqAction.substring(0, reqAction.indexOf(".action"));
method = "";
}
}

public String getAction() {
return action;
}

public String getMethod() {
return method;
}
}

UrlParameter.java 主要是将url请求中需要访问的action、method做了一个简单处理,再通过处理后的action、method来定位相应的Model层。
接下来是BaseConfig.java完成了什么工作。

/**
*
*/
package blog.base.servlet;

import java.util.Map;

import org.apache.log4j.Logger;

import blog.base.util.WebWorkXmlParser;
import blog.base.webwork.config.WebworkXmlConfig;

/**
* @author 张廷 2011-4-18下午09:16:05
*
*/
public class BaseConfig {

private Logger logger = Logger.getLogger(this.getClass());


/**
* 装载webwork.xml配置文件
*
* @param path
* @return
*/
public Map<String, WebworkXmlConfig> loadWebworkXmlConfig(String configLocation) {
Map<String, WebworkXmlConfig> map = null;
try {
map = WebWorkXmlParser.readActions(configLocation);
} catch (Exception e) {
logger.error(e.getMessage(), e);
e.printStackTrace();
}
return map;
}

/**
* 获取访问的方法
*
* @param urlParameter
* @param webworkXmlConfig
* @return
*/
public String getMethod(UrlParameter urlParameter, WebworkXmlConfig webworkXmlConfig) {
if ("".equals(urlParameter.getMethod()))
return webworkXmlConfig.getActionConfig().getMethod();
else
return urlParameter.getMethod();
}
}

此类主要是处理webwork.xml文件的装载,以及取得被访问的真实方法名。接下来看一下servlet如何来控制action的访问以及View层的访问。

/**
*
*/
package blog.base.servlet;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.Map;

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

import org.apache.log4j.Logger;

import blog.base.state.result.ResultManager;
import blog.base.webwork.config.WebworkXmlConfig;

/**
* @author 张廷 2011-5-26下午02:45:10
*
*/
public class BaseServlet extends HttpServlet {

private static final long serialVersionUID = -7616647500213995842L;

private Logger logger = Logger.getLogger(this.getClass());

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
execute(req, resp);
}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
execute(req, resp);
}

private synchronized void execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 设置HTTP响应与请求编码方式
setEncoding(req, resp);
BaseConfig baseConfig = new BaseConfig();
// 装载webwork.xml文件
Map<String, WebworkXmlConfig> config = baseConfig.loadWebworkXmlConfig("webwork.xml");
// 获取用户访问的URI
UrlParameter urlParameter = new UrlParameter(req.getRequestURI());
// 取出需要访问的action相关配置信息
WebworkXmlConfig webworkXmlConfig = config.get(urlParameter.getAction());
logger.info(" visited action is " + urlParameter.getAction());
Object handler = webworkXmlConfig.getActionConfig().getActionClass();
Method method = null;
try {
method = handler.getClass().getMethod(baseConfig.getMethod(urlParameter, webworkXmlConfig), new Class[] { HttpServletRequest.class, HttpServletResponse.class });
String result = (String) method.invoke(handler, new Object[] { req, resp });
ResultManager rm = new ResultManager();
rm.doWork(req, resp, webworkXmlConfig, result);
} catch (Exception e) {
logger.error("not fount method " + baseConfig.getMethod(urlParameter, webworkXmlConfig), e);
e.printStackTrace();
}
}

/**
* 设置HTTP响应与请求编码方式
*
* @param req
* @param resp
*/
private void setEncoding(HttpServletRequest req, HttpServletResponse resp) {
try {
req.setCharacterEncoding("utf-8");
resp.setCharacterEncoding("utf-8");
} catch (UnsupportedEncodingException e) {
logger.warn(e.getMessage(), e);
e.printStackTrace();
}
}

}

不管客户端是以get或post类型请求都将交给execute来处理,然而execute加了synchronized 关键字,主要是为了线程安全,为什么要在execute方法中每次都装载一次webwork.xml文件呢,这样设计的目的主要是为了有时需要改变webwork.xml中的逻辑时不需要再去重启服务器这样的麻烦事儿。
看一下方法执行后的结果交给了ResultManager类来处理,在返回值的处理使用了设计模式中的状态模式来处理,由于富应用的兴起,不能只是简单的视图跳转,所以可以通过状态模式来扩展自己想以各种各样的类型来返回数据给客户端,在这我只写了两个类型处理,分别是Jsp与Json状态类型。先来看一下两个状态的顶层接口。

package blog.base.state.result;

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

import org.apache.log4j.Logger;

import blog.base.webwork.config.ResultConfig;

/**
*
* @author 张廷 2011-5-27下午07:55:13
*
*/
public interface ResultState {

public Logger logger = Logger.getLogger(ResultState.class);

/**
* 结果类型处理
*
* @param req
* @param resp
* @param actionClass
* @param rc
*/
public void operate(HttpServletRequest req, HttpServletResponse resp, Object actionClass, ResultConfig rc);
}

下面是它的两个实现类。

/**
*
*/
package blog.base.state.result;

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

import blog.base.webwork.config.ResultConfig;

/**
* @author 张廷 2011-5-27下午07:51:15
*
*/
public class JspResultState implements ResultState {
/**
* 返回结果集为Jsp类型的处理方式
*/
public void operate(HttpServletRequest req, HttpServletResponse resp, Object actionClass, ResultConfig rc) {
try {
req.getRequestDispatcher(rc.getToUrl()).forward(req, resp);
} catch (Exception e) {
logger.fatal("Can not access this page!", e);
e.printStackTrace();
}
}

}

JsonResultState.java

/**
*
*/
package blog.base.state.result;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;

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

import net.sf.json.JSONObject;
import blog.base.webwork.config.ParamConfig;
import blog.base.webwork.config.ResultConfig;

/**
* @author 张廷 2011-5-27下午07:52:50
*
*/
public class JsonResultState implements ResultState {

/**
* 返回结果集为Json类型的处理方式
*/
public void operate(HttpServletRequest req, HttpServletResponse resp, Object actionClass, ResultConfig rc) {
resp.setContentType("application/json");
PrintWriter writer = null;
try {
writer = resp.getWriter();
} catch (IOException e) {
e.printStackTrace();
}
for (ParamConfig pc : rc.getParamConfigs()) {
if ("root".equals(pc.getParamName())) {
JSONObject jsonObj = JSONObject.fromObject(getVaribleValue(actionClass, pc.getParamVarible()));
writer.print(jsonObj);
}
}
if (null != writer) {
writer.flush();
writer.close();
}
}

/**
* 取得方法的返回值
*
* @param actionClass
* @param varible
* @return
*/
private Object getVaribleValue(Object actionClass, String varible) {
Class<? extends Object> clazz = actionClass.getClass();
Object backResult = null;
try {
Method method = clazz.getMethod(getGetterMethod(varible), new Class[] {});
backResult = method.invoke(actionClass, new Object[] {});
} catch (Exception e) {
e.printStackTrace();
logger.error("not found " + getGetterMethod(varible) + " method", e);
}
return backResult;
}

/**
* 获取实例中的实例变量相应的getter方法名
*
* @param varible
* @return
*/
private String getGetterMethod(String varible) {
String firstWord = varible.substring(0, 1);
firstWord = firstWord.toUpperCase();
String methodName = "get" + firstWord + varible.substring(1, varible.length());
return methodName;
}

}

然后再来看一下ResultManager类如何来控制result类型的控制访问的。

/**
*
*/
package blog.base.state.result;

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

import blog.base.webwork.config.ResultConfig;
import blog.base.webwork.config.WebworkXmlConfig;

/**
* @author 张廷 2011-5-27下午07:11:58
*
*/
public class ResultManager {

private ResultState state;

public void doWork(HttpServletRequest req, HttpServletResponse resp, WebworkXmlConfig wxc, String result) {
String resultType = null;
ResultConfig resultConfig = null;
Object actionClass = wxc.getActionConfig().getActionClass();
// 遍历当前action下的所有result
for (ResultConfig rc : wxc.getResultConfigs()) {
if (rc.getResultName().equals(result)) {
resultType = rc.getResultType();
resultConfig = rc;
break;
}
}
// 取得返回类型,采取相应的状态类来处理逻辑
if ("".equals(resultType) || "jsp".equals(resultType))
state = new JspResultState();
else if ("json".equals(resultType)){
state = new JsonResultState();
}
state.operate(req, resp, actionClass, resultConfig);
}

}

当然想使用更多的返回结果处理,可以直接在这个类中进行扩展。
来测试一下,针对以Json类型的结果返回给客户端写一个AjaxAction类。

/**
*
*/
package test.ajax;

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

/**
*
* @author 张廷 2011-5-29下午07:51:24
*
*/
public class AjaxAction {

private User user;

public String execute(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("success!");
return "";
}

public String ajaxTest(HttpServletRequest req, HttpServletResponse resp) {
user.setAge(18);
user.setBirth("1988-12-12");
user.setSex("男");
user.setUsername("admin");
return "ajaxResponse";
}

public User getUser() {
return user;
}

public void setUser(User user) {
this.user = user;
}

}


测试结果表明json结果已经返回到客户端,在客户端自己需要下载json2.js来解析服务器端返回的json数据。
看……一个简单的MVC小框架就已经出来了,但是一个真正的MVC框架考虑的远不止这些,还有更多的工作需要去分析设计,这只是为了理解一下MVC模式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值