前言
在这篇 自定义MVC框架思想 中我已详细描述了工作原理及流程,本篇主要在此基础上继续做出优化,实现步骤如下:
自定义MVC实现
1. 导入XML配置文件
<?xml version="1.0" encoding="UTF-8"?> <config> <action path="/order" type="com.xzs.servlet.OrderAction"> <forward name="success" path="/index.jsp" redirect="true" /> <forward name="failed" path="/register.jsp" redirect="false" /> </action> <action path="/book" type="com.xzs.servlet.BookAction"> <forward name="List" path="/book.jsp" redirect="false" /> <forward name="toList" path="/index.jsp" redirect="true" /> </action> </config>
将其部署到Source Folder文件中
2. 导入XML解析建模
这里就不一一详细解说了,可以去 XML建模 中了解详细建模实例。
3. 优化中央控制器
3.1 修改DisPathServlet中init初始化方法
在DisPathServlet的init方法中将原有Map集合方式替换成XML建模方式
// 通过xml建模方法进行储存 private ConfigModel configModel; @Override public void init() throws ServletException { /** * 初始化存值就是给每个施工员根据施工证进行存档: */ try { // configModel包含了所有的子控制器 configModel = ConfigModelFactory.build(); } catch (Exception e) { e.printStackTrace(); } }
3.2 修改ActionServlet逻辑处理流程
根据请求路径名获取ActionModel
这里如果查不到指定对象,请认真检查xml文件的配置,以及截取的内容是否与xml配置相同
/** * 获取请求路径 */ String uri = request.getRequestURI(); // 截取book uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf(".")); // 要通过uri->> /book,在configModel对象中找 ActionModel actionModel = configModel.pop(uri); // 判断没找对象等于空就抛出异常 if (actionModel == null) throw new RuntimeException("action not config"); /** * 获取config文件中action标签的type属性值 * type指java类 * com.ycxw.servlet.BookAction */ String type = actionModel.getType();
3.3 通过反射机制实例化子控制器类
package com.xzs.framework; import java.lang.reflect.Method; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 子控制器(action) 处理浏览器请求的类 * * @author * * 2023年6月29日 下午8:30:32 */ public class Action { public String execute(HttpServletRequest request, HttpServletResponse response) throws Exception { // 获取methodName值,这里指前端点击功能传来的方法名 String methodName = request.getParameter("methodName"); //定义一个变量来保存返回值 String res = ""; /** * this--->BookAction/BlogAction/PermissionAction...可能是很多对象 * 所以需要通过反射找到对象带request,response参数的methidName方法 */ Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); m.setAccessible(true); // 动态调用其方法 res = (String) m.invoke(this, request, response); return res ; } }
3.4 中央控制器将请求委托给子控制器处理
Action instance = (Action) Class.forName(type).newInstance(); // 业务代码执行后返回值 String execute = instance.execute(request, response);
3.5 根据请求结果码跳转页面
// 通过返回值拿到,该方法结果是重定向还是转发,还是跳转哪个页面 ForwardModel forwardModel = actionModel.pop(execute); if (forwardModel != null) { // 获取forwardModel是否从定向值 boolean redirect = forwardModel.isRedirect(); /** * 获取xml元素path值 */ String path = forwardModel.getPath(); // 判断是否为重定向 if (redirect) { response.sendRedirect(request.getContextPath() + "/" + path); } else { request.getRequestDispatcher(path).forward(request, response); } }
4. 反射赋值
4.1 创建接口DriverModel
package com.xzs.framework; /** * 模型驱动接口 * Book book = new Book(); * @author * * @param <T> */ public interface ModelDriver<T> { T getModel(); }
4.2 实现接口类
针对需要进行反射赋值的具体子控制器类,实现该接口DriverModel。
package com.xzs.servlet; import java.io.IOException; import java.util.Map; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.xzs.entity.Book; import com.xzs.framework.Action; import com.xzs.framework.ModelDriver; /** * 施工类 继承子控制器 * * @author * * @2023年6月29日 下午8:32:59 */ public class BookAction extends Action implements ModelDriver<Book>{ //创建表对应的属性对象 Book book = new Book(); @Override public Book getModel() { // TODO Auto-generated method stub return book; } public String load(HttpServletRequest req, HttpServletResponse resp) { //获取所有的参数 Map<String, String[]> map = req.getParameterMap(); System.out.println("Book查询的业务逻辑"); try { resp.sendRedirect("index.jsp"); } catch (IOException e) { e.printStackTrace(); } return "List"; } public String query(HttpServletRequest req, HttpServletResponse resp) { System.out.println("Book查询的业务逻辑"); try { resp.sendRedirect("index.jsp"); } catch (IOException e) { e.printStackTrace(); } return "List"; } public String edit(HttpServletRequest req, HttpServletResponse resp) { System.out.println("Book修改的业务逻辑"); try { resp.sendRedirect("index.jsp"); } catch (IOException e) { e.printStackTrace(); } return "toList"; } public String delete(HttpServletRequest req, HttpServletResponse resp) { System.out.println("Book删除的业务逻辑"); try { resp.sendRedirect("index.jsp"); } catch (IOException e) { e.printStackTrace(); } return "toList"; } public String add(HttpServletRequest req, HttpServletResponse resp) throws Exception { System.out.println("Book新增的业务逻辑"); req.getRequestDispatcher("index.jsp").forward(req, resp); return "toList"; } }
只要实现了DriverModel接口,则必须要对实体类进行初始化,并在getModel()方法中返回实例化后的对象。
4.3 反射对象赋值
/** * 获取config文件中action标签的type属性值 * type指java类 * com.ycxw.servlet.BookAction */ String type = actionModel.getType(); // 通过反射创建对象 Action instance; try { instance = (Action) Class.forName(type).newInstance(); // 判断bookAction有没有实现ModelDriver接口 if (instance instanceof ModelDriver) { // 向下转型获取接口方法 ModelDriver md = (ModelDriver) instance; Object bean = md.getModel(); // 把获取的参数保存到该对象中 BeanUtils.populate(bean, request.getParameterMap()); }