什么是MVC框架
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,
它是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,其好处是将业务逻辑聚集到一个部件里面,在改进和指定个性化页面的同时不需要重新编写业务逻 辑,MVC被独特的发展起来用于映射传统的输入,处理,显示在一个业务逻辑的图形化业务界面中。
核心思想:各司其职
注1:不能跨层调用
注2:只能出现由上而下的调用
MVC工作原理图:
主控制(ActionServlet)动态调用子控制器(Action)调用完成具体的业务逻辑(火车、控制台、车轨)请求、主控制器、子控制器
具体代码如下:
1,导入需要用到的jar包
2、mvc.xml建模 将Action的信息配置到xml(反射实例化)
解决了在框架代码中去改动,以便于完成客户需求,在框架中更改代码是不合理的
mvc.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<config>
<!-- <action path="/addCal" type="com.yuan.web.AddCalAction">
<forward name="res" path="/res.jsp" redirect="false" />
</action>
<action path="/delCal" type="com.yuan.web.DelCalAction">
<forward name="res" path="/res.jsp" redirect="true"/>
</action> -->
<action path="/cal" type="com.yuan.web.CalAction">
<forward name="res" path="/res.jsp" redirect="false"/>
</action>
</config>
ForwardModel
package com.yuan.framework; import java.io.Serializable; /** * 用来描述forward标签 * @author Administrator * */ public class ForwardModel implements Serializable { private static final long serialVersionUID = -8587690587750366756L; private String name; private String path; private String 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 String getRedirect() { return redirect; } public void setRedirect(String redirect) { this.redirect = redirect; } }
ActionModel
package com.yuan.framework; import java.io.Serializable; import java.util.HashMap; import java.util.Map; /** * 用来描述action标签 * @author Administrator * */ public class ActionModel implements Serializable{ private static final long serialVersionUID = 6145949994701469663L; private Map<String, ForwardModel> forwardModels = new HashMap<String, ForwardModel>(); private String path; private String type; public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getType() { return type; } public void setType(String type) { this.type = type; } public void put(ForwardModel forwardModel){ forwardModels.put(forwardModel.getName(), forwardModel); } public ForwardModel get(String name){ return forwardModels.get(name); } }
ConfigModel
package com.yuan.framework; import java.io.Serializable; import java.util.HashMap; import java.util.Map; /** * 用来描述config标签 * @author Administrator * */ public class ConfigModel implements Serializable{ private static final long serialVersionUID = -2334963138078250952L; private Map<String, ActionModel> actionModels = new HashMap<String, ActionModel>(); public void put(ActionModel actionModel){ actionModels.put(actionModel.getPath(), actionModel); } public ActionModel get(String name){ return actionModels.get(name); } }
ConfigModelFactory
package com.yuan.framework; import java.io.InputStream; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; public class ConfigModelFactory { private ConfigModelFactory() { } private static ConfigModel configModel = null; public static ConfigModel newInstance() throws Exception { return newInstance("mvc.xml"); } /** * 工厂模式创建config建模对象 * * @param path * @return * @throws Exception */ public static ConfigModel newInstance(String path) throws Exception { if (null != configModel) { return configModel; } ConfigModel configModel = new ConfigModel(); InputStream is = ConfigModelFactory.class.getResourceAsStream(path); SAXReader saxReader = new SAXReader(); Document doc = saxReader.read(is); List<Element> actionEleList = doc.selectNodes("/config/action"); ActionModel actionModel = null; ForwardModel forwardModel = null; for (Element actionEle : actionEleList) { actionModel = new ActionModel(); actionModel.setPath(actionEle.attributeValue("path")); actionModel.setType(actionEle.attributeValue("type")); List<Element> forwordEleList = actionEle.selectNodes("forward"); for (Element forwordEle : forwordEleList) { forwardModel = new ForwardModel(); forwardModel.setName(forwordEle.attributeValue("name")); forwardModel.setPath(forwordEle.attributeValue("path")); forwardModel.setRedirect(forwordEle.attributeValue("redirect")); actionModel.put(forwardModel); } configModel.put(actionModel); } return configModel; } public static void main(String[] args) { try { ConfigModel configModel = ConfigModelFactory.newInstance(); ActionModel actionModel = configModel.get("/loginAction"); ForwardModel forwardModel = actionModel.get("failed"); System.out.println(actionModel.getType()); System.out.println(forwardModel.getPath()); } catch (Exception e) { e.printStackTrace(); } } }
3、创建中央控制器
DispatcherServlet
package com.yuan.framework; import java.io.IOException; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import javax.management.RuntimeErrorException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.beanutils.BeanUtils; import com.yuan.web.AddCalAction; import com.yuan.web.DelCalAction; /** * 中央控制器 * 作用: 接受请求,通过请求寻找处理请求对应的子控制器。 * @author *** * */ public class DispatcherServlet extends HttpServlet { /** * */ private static final long serialVersionUID = 1L; // private Map<String , IAction> actionMap = new HashMap<>(); //在configModel对象中包含了所有的子控制器信息, private ConfigModel configModel; public void init() { // actionMap.put("/addCal", new AddCalAction()); // actionMap.put("/delCal", new DelCalAction()); try { String xmlPath = this.getInitParameter("xmlPath"); if(xmlPath == null || "".equals(xmlPath)){ configModel = ConfigModelFactory.newInstance(); } else { configModel = ConfigModelFactory.newInstance(xmlPath); } } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { init(); String url= req.getRequestURI(); // /项目名/addCal.action url = url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); // IAction action = actionMap.get(url); ActionModel actionModel = configModel.get(url); if(actionModel == null) { throw new RuntimeException("你没有配置action标签,找不到对应的子控制器来处理浏览器发送的请求"); } try { IAction action = (IAction) Class.forName(actionModel.getType()).newInstance(); //此时的action就是com.yuan.web.CalAction if(action instanceof ModelDrivern) { ModelDrivern drivern = (ModelDrivern) action; //此时的model的所有属性值是null的 Object model = drivern.getModel(); BeanUtils.populate(model, req.getParameterMap()); //我们可以将req.getParameterMap()的值通过反射的方式将其塞进model实例中 (源码) // Map<String, String[]> parameterMap = req.getParameterMap(); // Set<Entry<String, String[]>> entrySet = parameterMap.entrySet(); // Class<? extends Object> clz = model.getClass(); // for (Entry<String, String[]> entry : entrySet) { // Field field = clz.getField(entry.getKey()); // field.setAccessible(true); // field.set(model, entry.getValue()); // } } String code = action.execute(req, resp); ForwardModel forwardModel = actionModel.get(code); if(forwardModel!=null) { String jspPath = forwardModel.getPath(); if("false".equals(forwardModel.getRedirect())) { //做转发的处理 req.getRequestDispatcher(jspPath).forward(req, resp); }else { resp.sendRedirect(req.getContextPath()+jspPath); } } } catch (InstantiationException | IllegalAccessException | ClassNotFoundException | SecurityException | InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } // action.execute(req, resp); } }
web.xml配置
<servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>com.yuan.framework.DispatcherServlet</servlet-class> <init-param> <param-name>xmlPath</param-name> <param-value>/mvc.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping>
4、一个增强版的子控制器(ActionSupport)实现简单的子控制器(IAction)
IAction(接口)
package com.yuan.framework; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 子控制器 * 作用:用来直接处理浏览器发送过来的请求。 * @author ** * */ public interface IAction { String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException; }
ActionSupport 通过结果码控制页面的跳转,减少了逻辑层中的页面跳转代码重复性
package com.yuan.framework; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 增强版子控制器 * 原来的子控制器只可以处理一个请求, * 有时候用户请求是多个,但是都是操作同一张表,那么原有的子控制器代码编写繁琐。 * 增强版的作用就是将一组相关的操作放到一个IAction中(子控制器)。 * @author ** * */ public class ActionSupport implements IAction { @Override public final String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String methodName= req.getParameter("methodName"); String code = null; //this在这里指的是CalAction它的一个类实例 try { Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class); m.setAccessible(true); code = (String) m.invoke(this, req,resp); } catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { e.printStackTrace(); } return code;
} }
5、业务逻辑层 将一组相关的操作放到一个Action中(反射调用方法)
CalAction
package com.yuan.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.entity.Cal; import com.yuan.framework.ActionSupport; import com.yuan.framework.ModelDrivern; public class CalAction extends ActionSupport implements ModelDrivern<Cal> { private Cal cal = new Cal(); public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // String num1 = req.getParameter("num1"); // String num2 = req.getParameter("num2"); // Cal cal = new Cal(Integer.valueOf(num1),Integer.valueOf(num2)); req.setAttribute("res", cal.getNum1()- cal.getNum2()); // req.getRequestDispatcher("res.jsp").forward(req, resp); return "res"; } public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // String num1 = req.getParameter("num1"); // String num2 = req.getParameter("num2"); // Cal cal = new Cal(Integer.valueOf(num1),Integer.valueOf(num2)); req.setAttribute("res", cal.getNum1()+cal.getNum2()); // req.getRequestDispatcher("res.jsp").forward(req, resp); return "res"; } public String chen(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // String num1 = req.getParameter("num1"); // String num2 = req.getParameter("num2"); // Cal cal = new Cal(Integer.valueOf(num1),Integer.valueOf(num2)); req.setAttribute("res", cal.getNum1()*cal.getNum2()); // req.getRequestDispatcher("res.jsp").forward(req, resp); return "res"; } public String chu(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // String num1 = req.getParameter("num1"); // String num2 = req.getParameter("num2"); // Cal cal = new Cal(Integer.valueOf(num1),Integer.valueOf(num2)); req.setAttribute("res", cal.getNum1()/cal.getNum2()); // req.getRequestDispatcher("res.jsp").forward(req, resp); return "res"; } @Override public Cal getModel() { return cal; } }
6、创建一个模型接口 利用ModelDriver接口对Java对象进行赋值(反射读写属性),剪掉了逻辑层的获取jsp页面传值的代码重复性
package com.yuan.framework; /** * 模型驱动接口 * 作用:将jsp页面所有传递过来的参数以及参数值 * 都自动封装到浏览器所要操作的实体类中, * @author ** * */ public interface ModelDrivern<T> { T getModel(); }
7、Cal 实体类
package com.entity; public class Cal { private int num1; private int num2; public int getNum1() { return num1; } public void setNum1(int num1) { this.num1 = num1; } public int getNum2() { return num2; } public void setNum2(int num2) { this.num2 = num2; } public Cal(int num1, int num2) { super(); this.num1 = num1; this.num2 = num2; } public Cal() { super(); // TODO Auto-generated constructor stub } }
8、jsp页面代码
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>Insert title here</title> <script type="text/javascript"> function doSub(num){ if(num==1){ calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=add"; }else if(num==2){ calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=del"; } else if(num==3){ calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=chen"; } else if(num==4){ calForm.action = "${pageContext.request.contextPath }/cal.action?methodName=chu"; } calForm.submit(); } </script> </head> <body> <form name="calForm" action="" method="post"> num1:<input type="text" name="num1"> <br> num2:<input type="text" name="num2"> <br> <button onclick="doSub(1)">+</button> <button onclick="doSub(2)">-</button> <button onclick="doSub(3)">*</button> <button onclick="doSub(4)">/</button> </form> </body> </html>
9、运行结果:
加
减
乘
除
谢谢观看^-^ !!!