title: 深入理解struts的运行机制
date: 2016-10-26 20:02
tags: java
categories: 编程
permalink: zxh
个人剖析,不喜勿喷
扫码关注公众号,不定期更新干活

这里写图片描述
在此申明本博文并非原创,原文:http://blog.csdn.net/lenotang/article/details/3336623,本文章是在此文章基础上进行优化。也谈不上优化,只是加上了点自己的想法
jar包准备
新建项目
这里写图片描述
流程梳理
struts配置文件
<?xml version="1.0" encoding="UTF-8"?>
<struts>
<package>
<action name="login" method="login" class="org.zxh.action.LoginAction">
<result name="success">/index.jsp</result>
<result name="login">/WEB-INF/login.jsp</result>
</action>
</package>
</struts>
熟悉struts的朋友都清楚struts.xml配置文件的重要性,这个配置文件名字是可以更改的,这里简单解释下这个配置文件的作用,首先我们找到action这个节点这个action的name是login,就是说前台中请求这个login经过这个配置文件解析就会把这个请求交给action中的class属性,也就是上面的
org.zxh.action.LoginAction
具体的是交由这个类的login(method)这个方法。这个方法会方法一个string类型的字符串,如果返回的是success就将页面重定向到index.jsp如果是login就重定向到login.jsp。这个配置文件就是这样的作用。因为是自己写的,所以这里并不会想struts框架那样封装了很多东西,这里只是为了让读者更加深入的理解struts的运行机制。
如何将我们写的struts.xml文件在程序中启动呢?
新建filter(FilterDispatcher)
这个servlet就是struts的核心过滤器,需要先继承过滤器。
```
public class FilterDispatcher implements Filter{
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2) throws IOException, ServletException {
// TODO Auto-generated method stub
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
```
String webRootPath = getClass().getClassLoader()
.getResource("struts.xml").getPath();
package org.zxh.util;
import java.util.HashMap;
import java.util.Map;
public class ActionConfig {
private String name;
private String clazzName;
private String method;
private Map<String, String> resultMap = new HashMap<String, String>();
public ActionConfig(){
}
public ActionConfig(String name , String clazzName , String method , Map<String, String> resultMap){
this.name=name;
this.clazzName=clazzName;
this.method=method;
this.resultMap=resultMap;
}
public String getName() {
return name;
}
public String getClazzName() {
return clazzName;
}
public String getMethod() {
return method;
}
public Map<String, String> getResultMap() {
return resultMap;
}
public void setName(String name) {
this.name = name;
}
public void setClazzName(String clazzName) {
this.clazzName = clazzName;
}
public void setMethod(String method) {
this.method = method;
}
public void setResultMap(Map<String, String> resultMap) {
this.resultMap = resultMap;
}
}
package org.zxh.util;
import java.io.File;
import java.util.List;
import java.util.Map;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
public class ConfigUtil {
public static void parseConfigFile(String fileName,
Map<String, ActionConfig> map) {
SAXReader reader = new SAXReader();
try {
Document doc = reader.read(new File("D:\\zxh\\soft\\apache-tomcat-7.0.70\\apache-tomcat-7.0.70\\webapps\\MyStruts\\WEB-INF\\classes\\struts.xml"));
Element root = doc.getRootElement();
List<Element> list = root.selectNodes("package/action");
for (Element element : list) {
ActionConfig config = new ActionConfig();
String name = element.attributeValue("name");
String clazzName = element.attributeValue("class");
String method = element.attributeValue("method");
config.setName(name);
config.setClazzName(clazzName);
if (method == null || "".equals(method)) {
method = "execute";
}
config.setMethod(method);
List<Element> resultList = element.selectNodes("result");
for (Element resultElement : resultList) {
String resultName = resultElement.attributeValue("name");
String urlPath = resultElement.getTextTrim();
if (resultName == null || "".equals(resultName)) {
resultName = "success";
}
config.getResultMap().put(resultName, urlPath);
}
map.put(name, config);
}
} catch (DocumentException e) {
e.printStackTrace();
}
}
}
@Override
public void init(FilterConfig arg0) throws ServletException {
String webRootPath = getClass().getClassLoader()
.getResource("struts.xml").getPath();
ConfigUtil.parseConfigFile(webRootPath, map);
}
过滤器的执行
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain arg2)
doFilter()方法类似于Servlet接口的service()方法。当客户端请求目标资源的时候,容器就会调用与这个目标资源相关联的过滤器的 doFilter()方法。其中参数 request, response 为 web 容器或 Filter 链的上一个 Filter 传递过来的请求和相应对象;参数 chain 为代表当前 Filter 链的对象,在特定的操作完成后,可以调用 FilterChain 对象的 chain.doFilter(request,response)方法将请求交付给 Filter 链中的下一个 Filter 或者目标 Servlet 程序去处理,也可以直接向客户端返回响应信息,或者利用RequestDispatcher的forward()和include()方法,以及 HttpServletResponse的sendRedirect()方法将请求转向到其他资源。这个方法的请求和响应参数的类型是 ServletRequest和ServletResponse,也就是说,过滤器的使用并不依赖于具体的协议。
HttpServletRequest request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
String url = request.getServletPath();
if(!url.endsWith(".action")){
arg2.doFilter(request, response);
return ;
}
int start = url.indexOf("/");
int end = url.lastIndexOf(".");
String path=url.substring(start+1,end);
ActionConfig config = map.get(path);
if(config==null){
response.setStatus(response.SC_NOT_FOUND);
return ;
}
String clazzName=config.getClazzName();
Object action = getAction(clazzName);
if(action==null){
response.setStatus(response.SC_NOT_FOUND);
return ;
}
request参数获取并赋值给action
public static void requestToAction(HttpServletRequest request , Object action )
Class<? extends Object> clazzAction = action.getClass();
Field[] fields = action.getClass().getDeclaredFields();
Enumeration<String> names=request.getParameterNames();
String name=names.nextElement();
boolean flag=false;
for (Field field : fields) {
if(name.equals(field.getName())){
flag=true;
}
}
if(!flag){
return;
}
String[] value=request.getParameterValues(name);
Class<Object> fieldType=(Class<Object>) clazzAction.getDeclaredField(name).getType();
String setName="set"+name.substring(0,1).toUpperCase()+name.substring(1);
Method method=clazzAction.getMethod(setName, new Class[]{fieldType});
private static Object[] transfer(Class<Object> fieldType , String[] value){
Object[] os = null;
String type=fieldType.getSimpleName().replace("[]", "");
if("String".equals(type)){
os=value;
}else if("int".equals(type)||"Integer".equals(type)){
os = new Integer[value.length];
for (int i = 0; i < os.length; i++) {
os[i] = Integer.parseInt(value[i]);
}
}else if("float".equals(type)||"Float".equals(type)){
os=new Float[value.length];
for (int i = 0; i < os.length; i++) {
os[i]=Float.parseFloat(value[i]);
}
}else if("double".equals(type)||"Double".equals(type)){
os=new Double[value.length];
for (int i = 0; i < os.length; i++) {
os[i]=Double.parseDouble(value[i]);
}
}
return os;
}
if(fieldType.isArray()){
method.invoke(action, new Object[]{object});
}else {
method.invoke(action, new Object[]{object[0]});
}
这说一下 method.invoke是将action类中method方法这个方法需要的参数就是object详解
//前置拦截,获取request里面的参数,调用action的set方法给属性设置值
BeanUtil.requestToAction(request, action);
private String executeAction(ActionConfig config, Object action) {
String method = config.getMethod();
String result = null;
try {
Method callMethod = action.getClass().getMethod(method,String.class);
result = (String) callMethod.invoke(action, new Object[] {});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return config.getResultMap().get(result);
}
request.getRequestDispatcher(result).forward(request, response);
详解
//前置拦截,获取request里面的参数,调用action的set方法给属性设置值
BeanUtil.requestToAction(request, action);
private String executeAction(ActionConfig config, Object action) {
String method = config.getMethod();
String result = null;
try {
Method callMethod = action.getClass().getMethod(method,String.class);
result = (String) callMethod.invoke(action, new Object[] {});
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return config.getResultMap().get(result);
}
request.getRequestDispatcher(result).forward(request, response);
上诉原理的×××
扫码关注公众号,不定期更新干活

这里写图片描述