一.什么是自定义MVC框架
MVC自定义框架是指基于MVC模式而构建的自定义框架,用于开发和管理特定的Web应用程序。通过自定义框架,开发者可以按照自己的需求和约定构建自己的应用程序结构,并实现对模型、视图和控制器的定制和扩展。
自定义框架通常提供了一系列工具和库,用于简化开发过程、处理路由和请求、管理数据和视图的输出等。开发者可以根据自己的项目需求,选择或编写适合的模块和扩展来拓展框架的功能。这样,开发者可以更加高效和灵活地构建符合自己需求的应用程序。
二.搭建自定义MVC框架
要自定义搭建一个基于MVC模式的框架,可以按照以下步骤进行:
1.定义目录结构:创建一个合适的目录结构,用于组织框架的各个组件和功能模块。通常包括模型、视图、控制器、配置文件、路由器等。
2.设计模型(Model):根据应用程序的需求,设计和实现模型层的代码。模型负责处理数据的获取、存储和操作。可以根据框架需求,选择相应的数据库连接方式、ORM(对象关系映射)工具等。
3.设计视图(View):设计和实现视图层的代码,用于呈现数据给用户并处理用户界面的逻辑。视图通常由HTML、CSS和客户端脚本组成。
4.设计控制器(Controller):设计和实现控制器层的代码,处理用户的请求并协调模型和视图之间的交互。控制器负责接收和解析用户的请求,调用相应的模型进行数据处理,并将最终结果传递给视图进行展示。
5.设计路由器(Router):设计和实现路由器的代码,用于将用户的请求映射到相应的控制器和动作。路由器根据不同的URL和请求方法,将请求分发给对应的控制器。
6.设计配置文件:创建一个配置文件,用于存储框架的各种配置参数,例如数据库连接信息、路由规则、密钥等。这样可以使框架更灵活和可配置。
7.编写框架核心代码:实现框架的核心代码,包括加载配置、解析路由、初始化控制器等。确保框架的基本功能和运行机制正常。
8.提供扩展机制:考虑到不同项目的需求差异,提供一些扩展机制,允许开发者根据需要添加自定义的模块和功能。
9.编写示例应用:编写一个简单的示例应用程序,演示如何使用框架进行开发。这可以作为其他开发者上手和理解框架的参考。
10.测试和优化:进行测试和调试,确保框架的稳定性和性能。根据反馈和需求进行优化和改进。
最后,你需要考虑到每个组件的互相沟通和协作,并根据实际应用需求进行完善和迭代。搭建一个自定义的MVC框架需要一定的知识和经验,同时也要对底层的技术原理有一定的了解。如果你是初学者或时间有限,也可以考虑使用已有的成熟框架,以节省开发时间和精力。
三.自定义MVC框架优化实现
3.1利用xml建模反射优化
创建配置文件:
<?xml version="1.0" encoding="UTF-8"?> <config> <action path="/order" type="com.junlinyi.servlet.OrderAction"> <!-- forward标签:没有子标签; name:字符串,同一action标签下的forward标签name值不能相同 ; path:以/开头的字符串 redirect:只能是false|true,允许空,默认值为false --> <forward name="failed" path="/reg.jsp" redirect="false" /> <forward name="success" path="/login.jsp" redirect="true" /> </action> <action path="/book" type="com.junlinyi.servlet.BookAction"> <forward name="failed" path="/login.jsp" redirect="false" /> <forward name="success" path="/main.jsp" redirect="true" /> </action> </config>
分析:action path: (/)加上你的写的项目类名 forward path:要跳转的页面 redirect:重定向判断 type:项目的路径
注意: 如果你没有配置文件就会报错,下列是展示图:报action not config 就是没有配置文件
Action :
package com.junlinyi.framework; import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 子控制器 * 真正做事,处理浏览器发送请求的类 * @author: 君临沂 * */ public class Action { protected String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String methodName = req.getParameter("methodName"); // 返回值 String res=""; try { Method m = this.getClass().getDeclaredMethod(methodName,HttpServletRequest.class,HttpServletResponse.class); m.setAccessible(true); // 动态调用方法 res=(String) m.invoke(this,req,resp); } catch (Exception e) { e.printStackTrace(); } return res; } }
DispathServlet:
package com.junlinyi.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.junlinyi.model.ActionModel; import com.junlinyi.model.ConfigModel; import com.junlinyi.model.ConfigModelFactory; import com.junlinyi.model.ForwardModel; import com.junlinyi.servlet.BookAction; import com.junlinyi.servlet.OrderAction; /** * 中央控制器 * @author: 君临沂 * */ @WebServlet("*.action") public class DispathServlet extends HttpServlet{ // public Map<String,Action> actionMap=new HashMap<String, Action>(); // 原来所有的子控器是放到map集合中, // 现在所有的子控制器在mvc.xml中, // 其实就是放到configModel private ConfigModel configModel; @Override public void init() throws ServletException { // actionMap.put("/book",new BookAction()); // actionMap.put("/order",new OrderAction()); // 初始化 try { // configModel包含所有的子控制器 configModel =ConfigModelFactory.build(); } catch (Exception e) { // TODO Auto-generated catch block 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 { String uri = req.getRequestURI(); uri=uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf(".")); // Action action = actionMap.get(uri); // 通过uri=/book,在configModel对象中找 ActionModel actionModel = configModel.pop(uri); // 判断 if(actionModel == null) throw new RuntimeException("action not config");//你没有配置 // 拿type值 com.junlinyi.servlet.BookAction String type = actionModel.getType(); // 反射实例化 BookAction Action action; try { action = (Action) Class.forName(type).newInstance(); // BookAction有没有实现ModelDriver接口 if(action instanceof ModelDriver) { ModelDriver md=(ModelDriver) action; Object bean = md.getModel(); Map<String, String[]> map = req.getParameterMap(); BeanUtils.populate(bean, map); } // 具体业务代码执行后的返回值 add/del/upd/list的返回值===》list /tolist String res = action.execute(req, resp); // 通过返回值拿到,该方法结果是重定向还是转发,还是跳转那个页面 ForwardModel forwardModel = actionModel.pop(res); if(forwardModel !=null) { boolean redirect = forwardModel.isRedirect(); String path = forwardModel.getPath(); if(redirect) { resp.sendRedirect(req.getContextPath()+"/"+path); }else { req.getRequestDispatcher(path).forward(req, resp); } } } catch (Exception e) { e.printStackTrace(); } } }
ConfigModelFactory:
package com.junlinyi.model; import java.io.InputStream; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * 23种设计模式--工厂模式--创建型模式 * @author: 君临沂 * */ public class ConfigModelFactory { public static ConfigModel build() throws Exception { ConfigModel configModel=new ConfigModel(); InputStream is = ConfigModelFactory.class.getResourceAsStream("/mvc.xml"); SAXReader sa=new SAXReader(); Document doc = sa.read(is); // System.out.println(doc.asXML()); List<Element> actionEls = doc.selectNodes("/config/action"); for (Element actionEl : actionEls) { // System.out.println(actionEl.asXML()); ActionModel actionModel=new ActionModel(); actionModel.setPath(actionEl.attributeValue("path")); actionModel.setType(actionEl.attributeValue("type")); List<Element> forwardEls = doc.selectNodes("/config/action/forward"); for (Element forwardEl : forwardEls) { System.out.println(forwardEl.asXML()); ForwardModel forwardModel=new ForwardModel(); forwardModel.setName(forwardEl.attributeValue("name")); forwardModel.setPath(forwardEl.attributeValue("path")); // 只有填false才能转发,其它都是重定向 forwardModel.setRedirect(!"false".equals(forwardEl.attributeValue("redirect"))); actionModel.push(forwardModel); } configModel.push(actionModel); } return configModel; } public static void main(String[] args) throws Exception { ConfigModelFactory.build(); } }
ForwardModel:
package com.junlinyi.model; /** * * @author: 君临沂 * */ public class ForwardModel { private String name; private String path; private boolean redirect; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public boolean isRedirect() { return redirect; } public void setRedirect(boolean redirect) { this.redirect = redirect; } }
BookAction:
package com.junlinyi.servlet; import java.io.IOException; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.junlinyi.entity.Book; import com.junlinyi.framework.Action; import com.junlinyi.framework.ModelDriver; /** * BookAction类 * @author: 君临沂 *要有表对应的类属性对象 Book book *获取所有的参数值 req.getParameterMap(); *将参数值封装到表对应的对象中 *要做到所有的子控制器通用 */ public class BookAction extends Action implements ModelDriver<Book>{ private Book book=new Book(); public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { Map<String, String[]> map = req.getParameterMap(); System.out.println("恭喜你进入add...."); req.setAttribute("hjh","小黑包来了哦"); // resp.sendRedirect("res.jsp"); return "tolist"; } public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("恭喜你进入del...."); req.setAttribute("hjh","小黑包来了哦"); // resp.sendRedirect("res.jsp"); return "tolist"; } public String upd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("恭喜你进入upd...."); req.setAttribute("hjh","小黑包来了哦"); // resp.sendRedirect("res.jsp"); return "tolist"; } public String list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { System.out.println("恭喜你进入list...."); req.setAttribute("hjh","小黑包来了哦"); // req.getRequestDispatcher("res.jsp").forward(req, resp); return "list"; } @Override public Book getModel() { return book; } }
index.jsp :
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> </head> <body> 常识:查询必然转发,增删改使用重定向 弊端:中央控制器的action容器加载不可以灵活配置<hr> <a href="book.action?methodName=add">增加</a> <a href="book.action?methodName=del">删除</a> <a href="book.action?methodName=upd">修改</a> <a href="book.action?methodName=list">查询</a> </body> </html>
res.jsp: ${hjh }再加点内容(方便自己测试)
结果图展示:
正好对应这个常识:查询必然转发,增删改使用重定向