首先弄清楚 发送请求 都会被 filter 拦截,由 filter 处理,具体实现步骤:
- 1、自定义一个 MyAction的接口,之后的Action 实现这个类和其中的execute方法
- 2、仿造 struts2 在 web.xml中配置一个filter
<filter>
<filter-name>struts2</filter-name>
<filter-class>com.rindy.framework.mystruts.filter.MyStrutsPrepareAndExecuteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*</url-pattern>
</filter-mapping>
- 3、自定义一个Filter ,实现里面的 int 和 doFilter 方法,这个类实现框架主要的功能
package com.rindy.framework.mystruts.filter;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.rindy.framework.mystruts.MyAction;
import com.rindy.framework.mystruts.wrapper.ActionWrapper;
import com.rindy.framework.mystruts.wrapper.PackageWrapper;
import com.rindy.framework.mystruts.wrapper.ResultWrapper;
import com.rindy.framework.utils.Dom4j;
public class MyStrutsPrepareAndExecuteFilter implements Filter {
private Map<String, PackageWrapper> packageMap;
private HttpServletRequest request;
public void destroy() {
}
public void doFilter(ServletRequest arg0, ServletResponse arg1,
FilterChain chain) throws IOException, ServletException {
// 1、解析请求 得到两个值: namespace 的值 、 action的名字
request = (HttpServletRequest) arg0;
HttpServletResponse response = (HttpServletResponse) arg1;
// 使用 request.getServletPath() ,得到的路径不需要从中截取 namespace,而是
// /xxx/yyy.action 的字符串
String servletPath = request.getServletPath();
//表示只处理 后缀名为 .action 的请求,拦截到的 其他 如 jsp等就不会处理
if (servletPath.lastIndexOf(".action") == -1) {
chain.doFilter(request, response);
} else {
try {
int lastSlashIndex = servletPath.lastIndexOf("/");//取到最后一个 / 的位置, 将 namespace 和 xxx.action 取出
String actionName = servletPath.substring(lastSlashIndex + 1);
String namespaceName = servletPath.substring(0, lastSlashIndex);
// 2、到map中找到这个 Action
PackageWrapper packageWrapper =null;
for( Map.Entry<String, PackageWrapper> entry: packageMap.entrySet()){
PackageWrapper pw=entry.getValue();
pw.getNamespace().equals(namespaceName);
packageWrapper=pw;
break;
}
//根据action 名字从packageWrapper 里面找出 ActionWrapper
ActionWrapper aw = packageWrapper.getActionMap().get(actionName);
// 3、反射Action
String actionClassName = aw.getClassName();
Class c = Class.forName(actionClassName);
// 4、激活 相应的 方法
// 5、得到返回的result String
String result = invokeActionMethod(c, actionName, aw);
// 6、从 map中找到这个 string 对应的result值
ResultWrapper rw = aw.getResultWrapper().get(result);
// 7、转发到这个 result对应的内容中
String dispatcherType=rw.getType();
String page=rw.getValue();
//取出 result 属性的 type 是否有值
if(dispatcherType!=null && !"".equals(dispatcherType)){
//有,而且等于 direct ,说明是需要重定向到 指定的页面
if("direct".equals(dispatcherType)){
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
response.sendRedirect(basePath+page);
}
}else{
request.getRequestDispatcher(page).forward(request, response);
}
} catch (Exception e) {
e.printStackTrace();
request.getSession().setAttribute("myStrutsException", e);
}
}
}
public void init(FilterConfig config) throws ServletException {
String realPath = config.getServletContext().getRealPath("/");
// 读取配置文件 struts.xml
String filePath=getFilePath(realPath,"struts.xml");
// 解析xml
packageMap = parseStrutsXml(filePath);
}
private Map<String, PackageWrapper> parseStrutsXml( String filePath) {
Dom4j dom4j = new Dom4j();
Map<String, PackageWrapper> map = dom4j.getStrutsXML(filePath);
return map;
}
private String getFilePath(String realPath,String configFileName) {
// struts.xml 配置文件的真正路径
return realPath+"WEB-INF\\classes\\"+configFileName;
}
/**
* @return 这个 action 执行完 的 字符串
* @throws SecurityException
* @throws NoSuchMethodException
* @throws InvocationTargetException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InstantiationException
*/
private String invokeActionMethod(Class c, String requestActionName,
ActionWrapper aw) throws NoSuchMethodException, SecurityException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException, InstantiationException {
String requestResult = "";
Object obj = c.newInstance();
//注入参数的功能
injectParamterToAction( request,obj,c);
if (aw.getMethodName() == null || "".equals(aw.getMethodName())) {
requestResult = ((MyAction) obj).execute();
} else {
String actionMethodname = aw.getMethodName();
Method m = c.getMethod(actionMethodname, null);
requestResult = (String) m.invoke(obj, null);
}
return requestResult;
}
private void injectParamterToAction(HttpServletRequest request2,
Object obj, Class c) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
//基本类型的参数注入
//1、从request 中取出 所有的键值对,转成 Map < setName, xxx>
Map<String,String[]> map=pareseRequest(request2);new HashMap<String,String>();
//2、从 c 中导出要注入的方法,上一步 的map 转化就是 方便这一步的查找
Method[] ms=c.getMethods();
for( Method m: ms){
String methodName=m.getName();
if( map.containsKey(methodName)){
String[] values=map.get(methodName);
if( values.length==1){
String s=values[0];
String paramterTypeName=m.getParameterTypes()[0].getName();
//3、反向激活方法,注入参数
if( paramterTypeName.equals("java.lang.Integer") || paramterTypeName.equals("int")){
m.invoke(obj, Integer.parseInt(s));
continue;
}else if(paramterTypeName.equals("java.lang.Double") || paramterTypeName.equals("double")){
m.invoke(obj, Double.parseDouble(s));
continue;
}else if(paramterTypeName.equals("java.lang.Float") || paramterTypeName.equals("float")){
m.invoke(obj, Float.parseFloat(s));
continue;
}else if(paramterTypeName.equals("java.lang.Boolean") || paramterTypeName.equals("boolean")){
m.invoke(obj, Boolean.parseBoolean(s));
continue;
}else if(paramterTypeName.equals("java.lang.Short") || paramterTypeName.equals("short")){
m.invoke(obj,Short.parseShort(s));
continue;
}else{
m.invoke(obj, s);
continue;
}
}
}
}
}
private Map<String, String[]> pareseRequest(HttpServletRequest request) {
Map<String,String[]> map=new HashMap<String,String[]>();
Enumeration<String> enu=request.getParameterNames();
while( enu.hasMoreElements()){
String key=enu.nextElement();
String methodName="set"+key.substring(0, 1).toUpperCase()+key.substring(1);
String[] values=request.getParameterValues(key);
map.put(methodName, values);
}
return map;
}
}
4、自定义struts2 需要解析的struts.xml
<struts>
<!-- 配置包 通过 namespace 来规范访问这个包下的所有 action 的访问路径-->
<package name="default" namespace="/" >
<action name="user_add.action" class="com.rindy.action.UserAction" method="add">
<result name="success" type="direct">
/a.jsp
</result>
</action>
</package>
</struts>
5、index.jsp中表单的内容
<form action="user_add.action" method="post">
用户名:<input type="text" name="name"><br/>
年龄:<input type="text" name="age"><br/>
<input type="submit" value="提交"/>
</form>
6、我们这里没有做其他的复杂处理,进入UserAction中的add(),返回success,查找result中的值,根据type设置的类型,转发或者重定向到具体的页面,初版的struts框架就形成了,功能也是比较简单的,。后续会慢慢完善,下面我们来看一下效果。截图只是展现了页面的内容,跳转看不到,大家可以根据本博客动手试试看。
参数其实已经接到了,只是我们并没有在action 进行处理,后期会加上,这里只是在后台打印看下效果的实现
struts自定义框架是在影哥的带领下完成的,一直都在强调理解底层实现的重要性,架构师和程序员的区别,大家还是好好努力吧。加油。校招顺利!