自定义框架
自定义框架目录结构
创建framework.xml配置文件
<?xml version="1.0" encoding="UTF-8"?> <framework> <action name="hello" class="com.eric.action.HelloAction" method="hello"> <result name="success" type="dispatcher">/index.jsp</result> <result name="failed" type="redirect">/index.jsp</result> </action> </framework>
- 根据xml文件中定义的节点
<action>
<result>
创建对应的Action
Result
类
- 根据xml文件中定义的节点
Action类
public class Action { private String name; private String classes; private String method = "execute"; private Map<String, Result> resultMap = new HashMap<String, Result> (); public Action() { super(); } public Action(String name, String classes, String method) { super(); this.name = name; this.classes = classes; this.method = method; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClasses() { return classes; } public void setClasses(String classes) { this.classes = classes; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } public Map<String, Result> getResultMap() { return resultMap; } public void setResultMap(Map<String, Result> resultMap) { this.resultMap = resultMap; } }
- 配置文件中method可以为空,即默认执行
execute
方法
- 配置文件中method可以为空,即默认执行
Result类
public class Result { private String name = "success"; private String type = "dispatcher"; private String location; public Result() { super(); } public Result(String location) { super(); this.location = location; } public Result(String type, String location) { super(); this.type = type; this.location = location; } public Result(String name, String type, String location) { super(); this.name = name; this.type = type; this.location = location; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getLocation() { return location; } public void setLocation(String location) { this.location = location; } }
name
默认为success
type
默认为dispatcher
解析xml配置文件
- 导入dom4j jar包
- 创建AcrionMapper对象用于解析xml文件
public class ActionMapper { public static Map<String, Action> actionMap = new HashMap<String, Action> (); //解析xml配置文件 public static void parser() throws DocumentException { InputStream is = ActionMapper.class.getClassLoader().getResourceAsStream("framework.xml"); Document document = new SAXReader().read(is); Element root = document.getRootElement(); //处理aciton节点 List<Element> actions = root.elements(); for(Element element : actions) { Action action = new Action(); //获取action的属性值 action.setName(element.attributeValue("name")); action.setClasses(element.attributeValue("class")); String method = element.attributeValue("method"); if(method != null) { action.setMethod(method); } //处理action中的result List<Element> results = element.elements(); for(Element e : results) { Result result = new Result(); String resultName = e.attributeValue("name"); String resultType = e.attributeValue("type"); if(resultName != null) { result.setName(resultName); } if(resultType != null) { result.setType(resultType); } result.setLocation(e.getStringValue()); //将result对象添加到action中 action.getResultMap().put(result.getName(), result); } //将action放入actionmap中 actionMap.put(action.getName(), action); } } }
创建核心过滤器
public class CoreFilter implements Filter{ @Override public void destroy() { } @Override public void init(FilterConfig config) throws ServletException { //初始化时解析配置文件 try { ActionMapper.parser(); } catch (DocumentException e) { e.printStackTrace(); } } @Override public void doFilter(ServletRequest rq, ServletResponse rp, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) rq; HttpServletResponse resp = (HttpServletResponse) rp; //1---将请求映射到action中 Action targetAction = reqToAction(req); // System.out.println(targetAction.getName()); // System.out.println(targetAction.getMethod()); // System.out.println(targetAction.getClasses()); if(targetAction == null) { chain.doFilter(rq, rp); } try { //2---创建action对象 Object proxyAction = createProxyAction(targetAction.getClasses()); //3---将用户提交的数据设置到action的属性中 setProperty(req, proxyAction); //4---执行action的方法,返回执行结果 String result = execute(proxyAction, targetAction.getMethod()); //5---处理action方法的结果 //重定向用resp,转发用req //根据结果获取对应的Result对象,并且作为参数传入 Result r = targetAction.getResultMap().get(result); resultExecute(req, resp, r, proxyAction); } catch (Exception e) { e.printStackTrace(); } } //1---将请求映射到action中 private Action reqToAction(HttpServletRequest req) { String path = req.getRequestURI(); //uri不正确,只处理action结尾的请求 if(!path.endsWith(".action")) { return null; } //获得请求的名 String reqName = path.substring(path.lastIndexOf("/") + 1, path.lastIndexOf(".")); return ActionMapper.actionMap.get(reqName); } //2---创建action对象 private Object createProxyAction(String className) throws Exception { Class clzz = Class.forName(className); return clzz.newInstance(); } //3---将用户提交的数据设置到action的属性中 --- 简化了很多细节 private void setProperty(HttpServletRequest req, Object obj) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { //创建Class Class clzz = obj.getClass(); Map map = req.getParameterMap(); for(Iterator iter = map.keySet().iterator(); iter.hasNext();) { Object key = iter.next(); //根据提交的参数查找Field Field field = clzz.getDeclaredField(key.toString()); if(field == null) { continue; } field.setAccessible(true); //要进行相应的类型转换,此处省略 field.set(obj, req.getParameter(key.toString())); field.setAccessible(false); // System.out.println(key + "-----" + req.getParameter(key.toString())); } } //4---执行action的方法 private String execute(Object proxyAction, String method) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class clzz = proxyAction.getClass(); //获取类方法 Method m = clzz.getDeclaredMethod(method); //执行方法 return (String) m.invoke(proxyAction); } //5---处理action方法的结果 private void resultExecute(HttpServletRequest req, HttpServletResponse resp, Result r, Object proxyAction) throws IOException, IllegalArgumentException, IllegalAccessException, ServletException { //判断结果类型 //重定向 if("redirect".equals(r.getType())) { resp.sendRedirect(r.getLocation()); } //转发 //将action的属性值设置到request的attribute中 //只能通过Class获取属性 --- 原因:有的属性不是通过前台页面提交过来的 Class clzz = proxyAction.getClass(); //fds --- 获取类中所有的属性 Field[] fds = clzz.getDeclaredFields(); for(Field fd : fds) { //传入属性名,以及属性在该对象中的值 fd.setAccessible(true); req.setAttribute(fd.getName(), fd.get(proxyAction)); fd.setAccessible(false); } req.getRequestDispatcher(r.getLocation()).forward(req, resp); } }
- 核心过滤器中的关键处理流程
- 初始化时解析配置文件
- 调用ActionMapper对象解析xml文件,并将结果存储在
actionMap<uri, Action>
中
- 调用ActionMapper对象解析xml文件,并将结果存储在
- 将请求映射到action中
- 获取请求uri,并根据uri在actionMap中查找对应的Action对象
- 创建action对象
- 根据Action对象的类型,创建proxyAction对象
- 将用户提交的数据设置到action的属性中
- 通过反射机制,获取proxyAction对象的属性域,将req中提交的数据添加到proxyAction的Field中
- 执行action的方法,返回执行结果
- 通过反射机制获取proxyAction的方法并且执行
- 处理action方法的结果
- 根据返回的执行结果获取对应的Result对象,再根据Result中的type属性进行转发或者重定向
- 初始化时解析配置文件
- 核心过滤器中的关键处理流程
框架执行的总体流程:
解析XML文件,创建Action对象并存储到
actionMap
中收到请求后,先获取
actionMap
根据请求的uri取出
actionMap
中对应的targetAction
根据
targetAction
的classes
(即<action name="xxx" class="clzz">
中的clzz),通过反射机制创建clzz代理类(proxyAction)扫描二维码关注公众号,回复: 2247839 查看本文章根据
targetAction
的method
属性(即<action name="xxx" class="clzz"> method="method"
中的method),通过反射机制获取proxyAction的method
方法并且执行获取执行后的String返回值,根据返回值,在
targetAction
的resultMap
中获取对应的Result类根据Result类的
type
属性,选择转发或者重定向