一、前言
在自定义MVC框架原理中讲述了什么是MVC架构,以及它和三层架构的区别,在其简单的代码演示中,还存有一定的缺陷,今天将带大家继续进行优化。
二、优化问题
1.子控制器的初始化配置问题
//用于保存path与action子控制器的映射 public Map<String, Action> actionMap=new HashMap<String, Action>(); @Override public void init() throws ServletException { actionMap.put("/book", new BookAction()); actionMap.put("/goods", new GoodsAction()); }
在初始化方法中初始化子配置器的值,当我们每新增一张表,那我们都得在初始化方法中新增一个子配置器的值,我们既然要自定义MVC,最后肯定是要封装成jar包的,封装成jar包后是不能修改的,所以我们要让它变成自动化的。
2.页面跳转优化代码冗余问题
public void detail(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到查看详情💕💕💕"); resp.sendRedirect("far.jsp"); } public void del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到删除💕💕💕"); resp.sendRedirect("far.jsp"); } public void upd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到修改💕💕💕"); resp.sendRedirect("far.jsp"); } public void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到新增💕💕💕"); resp.sendRedirect("far.jsp"); } public void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到主页面💕💕💕"); req.getRequestDispatcher("far.jsp").forward(req, resp); } .
我们在子控制器中无论是什么操作都是要进行页面回显的,需要进行重定向response.sendRedirect();或者转发request.getRequestDispatcher().forward();操作(ajax方式除外)这些代码是冗余的。
3.优化参数封装问题
Book book=new Book(); public String detail(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到查看详情💕💕💕"); String bid = req.getParameter("bid"); String bname = req.getParameter("bname"); String price = req.getParameter("price"); book.setBid(Integer.valueOf(bid)); book.setBname(bname); book.setPrice(Integer.valueOf(price)); }
当我们对每张表进行操作时,都要获取参数以及封装对象等,如果一张表有十几个参数,那对我们来说无疑是繁琐的,而且容易出错。
三、进行优化
1.解决子控制器初始化配置
我们可以利用XML文件来定义和验证MVC配置文件的结构和内容。XML文件可以描述MVC中的模型(Model)、视图(View)和控制器(Controller)之间的关系和行为。拿到配置文件中的信息后,进行反射实例化动态处理。
这个xml文件存放在根目录下,先建立一个Source Folder文件夹将我们的config.xml文件放入即可。
<?xml version="1.0" encoding="UTF-8"?> <config> <action path="/registerAction" type="test.action.RegisterAction"> <forward name="success" path="/index.jsp" redirect="true" /> <forward name="failed" path="/register.jsp" redirect="false" /> </action> <action path="/book" type="com.ctb.servlet.BookAction"> <forward name="list" path="/far.jsp" redirect="false" /> <forward name="exit" path="/far.jsp" redirect="true" /> </action> </config>
action标签中的path:是DispatchServlet类截取到的uri路径。
action标签中的type:是子控制器的全路径名。
forward标签中的name:是重定向还是转发,是否携带数据
forward标签中的path:是跳转的页面。
forward标签中的redirect:判断为true则重定向跳转页面,为false则转发跳转页面
注:增删改用重定向,查询用转发
接下来我们将进行xml解析并建模,大家可以翻阅xml解析和xml建模这两篇博客
xml建模过程在里面都有,就不进行代码展示了
2.解决页面跳转的代码冗余问题
我们可以利用xml配置文件进行优化,在forward标签中的name属性可以给它设置最终方法所返回的值从而进行判断是重定向还是转发
<forward name="list" path="/far.jsp" redirect="false" /> <forward name="exit" path="/far.jsp" redirect="true" />
BookAction
package com.ctb.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.ctb.entity.Book; import com.ctb.framework.Action; import com.ctb.framework.ModelDriver; /** * * @author biao * * 2023年6月29日:下午6:41:01 */ public class BookAction extends Action { Book book=new Book(); public String detail(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到查看详情💕💕💕"); return "list"; } public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到删除💕💕💕"); return "exit"; } public String upd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到修改💕💕💕"); return "exit"; } public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到新增💕💕💕"); return "exit"; } public String list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到主页面💕💕💕"); return "list"; } }
3.解决优化参数封装问题
我们定义一个模型驱动接口,让子控制通用
package com.ctb.framework; /** * 定义方法,减少代码冗余 * 避免了表多和重复代码 * @author biao * * 2023年6月30日:下午4:48:27 */ public interface ModelDriver<T> { T getModel(); }
接下来实现接口即可
package com.ctb.servlet; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.ctb.entity.Book; import com.ctb.framework.Action; import com.ctb.framework.ModelDriver; /** * * @author biao * * 2023年6月29日:下午6:41:01 */ public class BookAction extends Action implements ModelDriver<Book>{ Book book=new Book(); public String detail(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到查看详情💕💕💕"); return "list"; } public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到删除💕💕💕"); return "exit"; } public String upd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到修改💕💕💕"); return "exit"; } public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到新增💕💕💕"); return "exit"; } public String list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("欢迎来到主页面💕💕💕"); return "list"; } /** * 因为实现类必须重写这个方法以及传递泛型,到时候谁用就是谁 */ @Override public Book getModel() { // TODO Auto-generated method stub return book; } }
4.中央控制器
最后,优化我们的中央控制器,在解决上述三个问题的同时,我们的DispathServlet类自然也会改变
package com.ctb.framework; import java.io.IOException; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import com.ctb.model.ActionModel; import com.ctb.model.ConfigModel; import com.ctb.model.ConfigModelFactory; import com.ctb.model.ForwordModel; import com.ctb.servlet.BookAction; /** * 请求分发功能 * @author biao * * 2023年6月29日:下午6:45:13 */ @WebServlet("*.action") public class DispathServlet extends HttpServlet{ //获取文件配置器中的子控制器 private ConfigModel configModel; @Override public void init() throws ServletException { try { configModel=ConfigModelFactory.build("/config.xml"); } catch (Exception e) { e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //获取uri地址 String uri = req.getRequestURI(); //截取 uri=uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf(".")); // 根据path也就是路径(uri)找到配置的type(子控制器) ActionModel ActionModel = configModel.pop(uri); // 防止配置没写完善这里做一个非空判断如果请求路径未配置就抛出一个自定义异常给他 if (ActionModel == null) throw new RuntimeException("Config is not configured yet."); // 拿到ActionModel里面的type值(type值就是子控制器的全路径名) String type = ActionModel.getType(); try { //根据全路径名获取类类并反射实例化 Action action = (Action) Class.forName(type).newInstance(); //查看该类是否实现ModelDriver接口 if(action instanceof ModelDriver) { ModelDriver md=(ModelDriver)action; //获取泛型传递的实体对象 Object model = md.getModel(); //获取请求参数的所有的属性及参数 Map<String, String[]> parameterMap = req.getParameterMap(); //使用工具类将参数值封装到表对应的对象中 BeanUtils.populate(model, parameterMap); } //调用子控制器 String execute =action.excute(req, resp); //判断是重定向还是转发-根据返回值找到指定ForwardModel ForwordModel pop = ActionModel.pop(execute); //如果是ajax不需要配置xml,所以ForwardModel有值的时候才进行跳转判断 if(pop!=null) { //拿到redirect进行相对应的判断 boolean redirect = pop.isRedirect(); //拿到path进行相对应的页面跳转 String path = pop.getPath(); if(redirect) {//true重定向 //注意这里会丢失项目路径所以要request.getContextPath() resp.sendRedirect(req.getContextPath()+path); }else {//false转发 req.getRequestDispatcher(path).forward(req, resp); } } } catch (Exception e) { e.printStackTrace(); } } }
结果就不演示了,与自定义MVC框架原理中输出结果差不多,重在代码逻辑
✨原创不易,还希望各位大佬支持一下
👍 点赞,你的认可是我创作的动力!
⭐️ 收藏,你的青睐是我努力的方向!
✏️ 评论,你的意见是我进步的财富!