2013-01-30 09:35:49.0|分类: struts源码分析|浏览量: 1858
|
FilterDispatcher是struts2的核心控制器,每个请求都会进入FilterDispatcher对象的doFilter()方法。然后再struts.xml文件中根据action的name属性进行匹配,找到要执行的action类和方法,执行完方法返回结果。 public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
ServletContext servletContext = getServletContext();
String timerKey = "FilterDispatcher_doFilter: ";
try {
// FIXME: this should be refactored better to not duplicate work with the action invocation
ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
ActionContext ctx = new ActionContext(stack.getContext());
ActionContext.setContext(ctx);
UtilTimerStack.push(timerKey);
request = prepareDispatcherAndWrapRequest(request, response);
ActionMapping mapping;
try {//根据url取得对应的Action的配置信息 //看一下注入的DefaultActionMapper的getMapping()方法.Action的配置信息存储在 ActionMapping对象中 mapping = actionMapper.getMapping(request, dispatcher.getConfigurationManager());
} catch (Exception ex) {
log.error("error getting ActionMapping", ex);
dispatcher.sendError(request, response, servletContext, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, ex);
return;
} //如果找不到对应的action配置,则直接返回。比如你输入***.jsp等 if (mapping == null) {
// there is no action in this request, should we look for a static resource?
String resourcePath = RequestUtils.getServletPath(request);
if ("".equals(resourcePath) && null != request.getPathInfo()) {
resourcePath = request.getPathInfo();
}
if (staticResourceLoader.canHandle(resourcePath)) {
staticResourceLoader.findStaticResource(resourcePath, request, response);
} else {
// this is a normal request, let it pass through
chain.doFilter(request, response);
}
// The framework did its job here
return;
} //正式开始Action的方法 后面详细解释 dispatcher.serviceAction(request, response, servletContext, mapping);
} finally {
dispatcher.cleanUpRequest(request);
try {
ActionContextCleanUp.cleanUp(req);
} finally {
UtilTimerStack.pop(timerKey);
}
devModeOverride.remove();
}
}
由于这个doFilter()是重点,主要是3个功能: (1)encoding和Local是web页面上的重要属性,也是web程序进行国际化il8n处理的核心参数。prepareDispatcherAndWrapRequest()设置encoding和Local参数。并对httpServletRequest进行一定的封装 (2)ActionContext的创建总是伴随着valueStack的创建。valueStackFactory负责创建valueStack,并为valueStack设置上下文环境;紧接着valueStack创建的就是ActionContext,并且ActionContext的创建以valueStack的上下文环境作为参数。 valueStack的上下文环境与ActionContext的数据存储空间是等同的。代码证明: ctx = new ActionContext(stack.getContext()); (3)解析请求url,并且把值赋值给ActionMapping对象 (4)serviceAction执行action 现在我们就重点分析解析url,serviceAction执行action后面再详细分析 2、getMapping()方法:ActionMapper接口的实现类 DefaultActionMapper的getMapping() /*
* (non-Javadoc)
*
* @see org.apache.struts2.dispatcher.mapper.ActionMapper#getMapping(javax.servlet.http.HttpServletRequest)
*/
public ActionMapping getMapping(HttpServletRequest request,
ConfigurationManager configManager) {
ActionMapping mapping = new ActionMapping();//创建一个ActionMapping
String uri = getUri(request);//得到请求路径的URI,如:login.action int indexOfSemicolon = uri.indexOf(";");//修正url的带;jsessionid uri = (indexOfSemicolon > -1) ? uri.substring(0, indexOfSemicolon) : uri;
uri = dropExtension(uri, mapping);//删除扩展名,默认扩展名为action if (uri == null) {
return null;
}
parseNameAndNamespace(uri, mapping, configManager);//匹配Action的name和namespace handleSpecialParameters(request, mapping);//去掉特殊参数 //如果Action的name没有解析出来,直接返回 if (mapping.getName() == null) {
return null;
}
parseActionName(mapping);//主要是处理name!add 格式的解析
return mapping;
}
protected ActionMapping parseActionName(ActionMapping mapping) {
if (mapping.getName() == null) {
return mapping;
}
if (allowDynamicMethodCalls) {
// handle "name!method" convention.
String name = mapping.getName();
int exclamation = name.lastIndexOf("!");
if (exclamation != -1) {
mapping.setName(name.substring(0, exclamation));//提取左边为name mapping.setMethod(name.substring(exclamation + 1));//提取右边的method }
}
return mapping;
}
注释:getMapping()方法返回ActionMapping类型的对象,该对象包含三个参数:Action的name、namespace和要调用的方法method 2.1查看ActionMapping对象:里面有name等等属性
public class ActionMapping {
private String name;
private String namespace;
private String method;
private String extension;
private Map<String, Object> params;
private Result result;
} 2.2getUri(request)获取请求路径:
/**
* Gets the uri from the request
*
* @param request The request
* @return The uri
*/
protected String getUri(HttpServletRequest request) {
// handle http dispatcher includes.
String uri = (String) request
.getAttribute("javax.servlet.include.servlet_path");
if (uri != null) {
return uri;
}
uri = RequestUtils.getServletPath(request);
if (uri != null && !"".equals(uri)) {
return uri;
}
uri = request.getRequestURI();
return uri.substring(request.getContextPath().length());
} 注释:request.getContextPath()
其作用是获取当前的系统路径
我做了一个测试,先看看打印结果: uRequestUtils.getServletPath(request) = /skip.action 不难看出getUri(request)是为了获得请求路径 /skip.action 2.3、dropExtension(uri, mapping)删除扩展名 protected List<String> extensions = new ArrayList<String>() {{
add("action");
add("");
}};
protected String dropExtension(String name, ActionMapping mapping) {
if (extensions == null) {
return name;
}
for (String ext : extensions) {
if ("".equals(ext)) { int index = name.lastIndexOf('.');
if (index == -1 || name.indexOf('/', index) >= 0) {
return name;
}
} else {//删除扩展名.action
String extension = "." + ext;
if (name.endsWith(extension)) {
name = name.substring(0, name.length() - extension.length());
mapping.setExtension(ext);
return name;
}
}
}
return null;
}
extensions中默认的保存了action,其他事怎么加入的呢? @Inject(StrutsConstants.STRUTS_ACTION_EXTENSION)
public void setExtensions(String extensions) {
if (extensions != null && !"".equals(extensions)) {
List<String> list = new ArrayList<String>();
String[] tokens = extensions.split(",");
for (String token : tokens) {
list.add(token);
}
if (extensions.endsWith(",")) {
list.add("");
}
this.extensions = Collections.unmodifiableList(list);
} else {
this.extensions = null;
}
} 原来是预处理,
通过注解在初始化的时候赋值,STRUTS_ACTION_EXTENSION = "struts.action.extension"
想想以前在struts.properties文件中设置struts.action.extension=action,原来是这的道理啊,哈哈。 2.4 parseNameAndNamespace(uri, mapping, configManager)从uri中解析出来name和namespace,并且把name和names赋值给mapping。 2.5 handleSpecialParameters(request, mapping)去除特殊参数:
public void handleSpecialParameters(HttpServletRequest request,
ActionMapping mapping) {
// handle special parameter prefixes.
Set<String> uniqueParameters = new HashSet<String>();
Map parameterMap = request.getParameterMap();
for (Iterator iterator = parameterMap.keySet().iterator(); iterator
.hasNext();) {
String key = (String) iterator.next();
// Strip off the image button location info, if found
if (key.endsWith(".x") || key.endsWith(".y")) {
key = key.substring(0, key.length() - 2);
}
// Ensure a parameter doesn't get processed twice
if (!uniqueParameters.contains(key)) {
ParameterAction parameterAction = (ParameterAction) prefixTrie
.get(key);
if (parameterAction != null) {
parameterAction.execute(key, mapping);
uniqueParameters.add(key);
break;
}
}
}
}
注释;主要是去除鼠标参数,横竖坐标。
|
