1. 什么是MVC MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 它是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码 自定义MVC工作原理图 首先导入几个包 通过XML对自定义mvc框架进行增强
1 将Action的信息配置到xml(反射实例化) xml:
<?xml version="1.0" encoding="UTF-8"?> <!-- config标签:可以包含0~N个action标签 --> <config> <action path="/cal_add" type="com.yq.web.AddCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_del" type="com.yq.web.DelCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_cheng" type="com.yq.web.ChengCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_chu" type="com.yq.web.ChuCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> </config> 在这里插入代码片 /** * 中央控制器 * 作用: * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * * * 1.对存放子控制器action容器的增强 * 原来为了完成业务需求,需要不断修改框架的代码,这样的设计是不合理的 * 处理方法:参照web.xml的实际方法,来完成中央控制器的动态配置 * * @author 陌陌 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 5454279413518217926L; // private Map<String,Action> actionMap=new HashMap<String, Action>(); private ConfigModel configModel=null; public void init() { // http://localhost:8080/yq_mvc/cal_add.action // actionMap.put("/cal_add", new AddCalAction()); // actionMap.put("/cal_del", new DelCalAction()); // actionMap.put("/chengCal",new ChengCalAction()); // actionMap.put("/chuCal", new ChuCalAction()); try { configModel =ConfigModelFactory.newInstance(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String url = req.getRequestURI(); url = url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); // Action action = actionMap.get(url); // action.execute(req, resp); // Action action = actionMap.get(url); // action.execute(req, resp); ActionModel actionModel= configModel.get(url); try { Action action=(Action) Class.forName(actionModel.getType()).newInstance(); action.execute(req, resp); } catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 在这里插入代码片加法运算 结果为3 2.处理结果码的跳转形式
/** * 中央控制器 * 作用: * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * * * 1.对存放子控制器action容器的增强 * 原来为了完成业务需求,需要不断修改框架的代码,这样的设计是不合理的 * 处理方法:参照web.xml的实际方法,来完成中央控制器的动态配置 * * 2.处理结果码的跳转形式 * 达到简化代码的目的 * @author 陌陌 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 5454279413518217926L; // private Map<String,Action> actionMap=new HashMap<String, Action>(); private ConfigModel configModel=null; public void init() { // http://localhost:8080/yq_mvc/cal_add.action // actionMap.put("/cal_add", new AddCalAction()); // actionMap.put("/cal_del", new DelCalAction()); // actionMap.put("/chengCal",new ChengCalAction()); // actionMap.put("/chuCal", new ChuCalAction()); try { configModel =ConfigModelFactory.newInstance(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String url = req.getRequestURI(); url = url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); // Action action = actionMap.get(url); // action.execute(req, resp); // Action action = actionMap.get(url); // action.execute(req, resp); ActionModel actionModel= configModel.get(url); try { if(actionModel==null) { throw new RuntimeException("你没有配置指定的子控制器来处理用户的请求"); } Action action=(Action) Class.forName(actionModel.getType()).newInstance(); 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 e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 在这里插入代码片xml
<?xml version="1.0" encoding="UTF-8"?> <!-- config标签:可以包含0~N个action标签 --> <config> <action path="/cal_add" type="com.yq.web.AddCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_del" type="com.yq.web.DelCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_cheng" type="com.yq.web.ChengCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_chu" type="com.yq.web.ChuCalAction"> <forward name="rs" path="/rs.jsp" /> </action> </config> 在这里插入代码片3.将一组相关的操作放到一个Action中(反射调用方法)
/** * 增强版的子控制器 * 作用:将一组操作放到一个子控制器去完成 * * * @author 陌陌 * */ public class ActionSupport implements Action{ @Override public String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 从前台传递需要调用的方法名到后台,实现动态方法调用 String methodName =req.getParameter("methodName"); // 思考:com.yq.web.CalAction CalAction=new CalAction(); String code=null; try { Method m=this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class); m.setAccessible(true); code=(String) m.invoke(this, req,resp); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } return code; } } 在这里插入代码片CalAction:
package com.yq.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.yq.entity.Cal; import com.yq.framework.ActionSupport; public class CalAction extends ActionSupport{ public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String num1=req.getParameter("num1"); String num2=req.getParameter("num2"); Cal cal=new Cal(num1,num2); // req.setAttribute("rs", Integer.valueOf(cal.getNum1())+Integer.valueOf(cal.getNum2())); // req.getRequestDispatcher("/rs.jsp").forward(req, resp); return "rs"; } public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String num1=req.getParameter("num1"); String num2=req.getParameter("num2"); Cal cal=new Cal(num1,num2); // req.setAttribute("rs", Integer.valueOf(cal.getNum1())-Integer.valueOf(cal.getNum2())); // req.getRequestDispatcher("/rs.jsp").forward(req, resp); return "rs"; } public String cheng(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String num1=req.getParameter("num1"); String num2=req.getParameter("num2"); Cal cal=new Cal(num1,num2); // req.setAttribute("rs", Integer.valueOf(cal.getNum1())-Integer.valueOf(cal.getNum2())); // req.getRequestDispatcher("/rs.jsp").forward(req, resp); return "rs"; } public String chu(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String num1=req.getParameter("num1"); String num2=req.getParameter("num2"); Cal cal=new Cal(num1,num2); // req.setAttribute("rs", Integer.valueOf(cal.getNum1())-Integer.valueOf(cal.getNum2())); // req.getRequestDispatcher("/rs.jsp").forward(req, resp); return "rs"; } } 在这里插入代码片xml 只需要这一行就可以了
<action path="/cal" type="com.yq.web.AddCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> 在这里插入代码片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(v) { if(v==1){ calForm.action="${pageContext.request.contextPath }/cal.action?methodName=add"; }else if(v==2){ calForm.action="${pageContext.request.contextPath }/cal.action?methodName=del"; }else if(v==3){ calForm.action="${pageContext.request.contextPath }/cal.action?methodName=cheng"; }else{ calForm.action="${pageContext.request.contextPath }/cal.action?methodName=chu"; } calForm.submit(); } </script> </head> <body> <form id="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> 在这里插入代码片4.利用ModelDriver接口对Java对象进行赋值(反射读写属性)
模型驱动接口:
/** * 模型驱动接口 * 作用:给对应处理业务子控制器中包含的实体类jsp参数封装 * @author 陌陌 * * @param <T> */ public interface ModelDriven<T> { T getModel(); } 在这里插入代码片主控制器
/** * 中央控制器 * 作用: * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * * * 1.对存放子控制器action容器的增强 * 原来为了完成业务需求,需要不断修改框架的代码,这样的设计是不合理的 * 处理方法:参照web.xml的实际方法,来完成中央控制器的动态配置 * * 2.处理结果码的跳转形式 * 达到简化代码的目的 * * 3.将一组相关的操作放到一个子控制器中去 * * 4.处理jsp传递到后台的参数封装 * * @author 陌陌 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 5454279413518217926L; // private Map<String,Action> actionMap=new HashMap<String, Action>(); private ConfigModel configModel=null; public void init() { // http://localhost:8080/yq_mvc/cal_add.action // actionMap.put("/cal_add", new AddCalAction()); // actionMap.put("/cal_del", new DelCalAction()); // actionMap.put("/chengCal",new ChengCalAction()); // actionMap.put("/chuCal", new ChuCalAction()); try { configModel =ConfigModelFactory.newInstance(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String url = req.getRequestURI(); url = url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); // Action action = actionMap.get(url); // action.execute(req, resp); // Action action = actionMap.get(url); // action.execute(req, resp); ActionModel actionModel= configModel.get(url); try { if(actionModel==null) { throw new RuntimeException("你没有配置指定的子控制器来处理用户的请求"); } Action action=(Action) Class.forName(actionModel.getType()).newInstance(); if(action instanceof ModelDriven) { ModelDriven modelDriven=(ModelDriven) action; Object model=modelDriven.getModel(); // 给model赋值了,那么意味着在调用add或者del方法的时候cal不再是空的了 BeanUtils.populate(model, req.getParameterMap()); } 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 e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 在这里插入代码片5、使得框架的配置文件可变 给xml中配置主控制器提供一个参数,这样就能通过改xml来获取不同位置下的xml xml:
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" id="WebApp_ID" version="3.1"> <display-name>mvc</display-name> <servlet> <servlet-name>DispatcherServlet</servlet-name> <servlet-class>com.yq.framework.DispatcherServlet</servlet-class> <init-param> <param-name>mvcXmlLocation</param-name> <param-value>/qiong.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>DispatcherServlet</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app> 在这里插入代码片主控制器
package com.yq.framework; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.swing.ActionMap; import org.apache.commons.beanutils.BeanUtils; import com.yq.web.AddCalAction; import com.yq.web.ChengCalAction; import com.yq.web.ChuCalAction; import com.yq.web.DelCalAction; /** * 中央控制器 * 作用: * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * * * 1.对存放子控制器action容器的增强 * 原来为了完成业务需求,需要不断修改框架的代码,这样的设计是不合理的 * 处理方法:参照web.xml的实际方法,来完成中央控制器的动态配置 * * 2.处理结果码的跳转形式 * 达到简化代码的目的 * * 3.将一组相关的操作放到一个子控制器中去 * * 4.处理jsp传递到后台的参数封装 * * 5.解决框架配置文件重名冲突问题 * * @author 陌陌 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 5454279413518217926L; // private Map<String,Action> actionMap=new HashMap<String, Action>(); private ConfigModel configModel=null; public void init() { // http://localhost:8080/yq_mvc/cal_add.action // actionMap.put("/cal_add", new AddCalAction()); // actionMap.put("/cal_del", new DelCalAction()); // actionMap.put("/chengCal",new ChengCalAction()); // actionMap.put("/chuCal", new ChuCalAction()); try { String mvcXmlLocation=this.getInitParameter("mvcXmlLocation"); if(null==mvcXmlLocation||"".equals(mvcXmlLocation)) { mvcXmlLocation="mvc.xml"; } System.out.println("mvcXmlLocation:"+mvcXmlLocation); configModel =ConfigModelFactory.newInstance(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { String url = req.getRequestURI(); url = url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); // Action action = actionMap.get(url); // action.execute(req, resp); // Action action = actionMap.get(url); // action.execute(req, resp); ActionModel actionModel= configModel.get(url); try { if(actionModel==null) { throw new RuntimeException("你没有配置指定的子控制器来处理用户的请求"); } Action action=(Action) Class.forName(actionModel.getType()).newInstance(); if(action instanceof ModelDriven) { ModelDriven modelDriven=(ModelDriven) action; Object model=modelDriven.getModel(); // 给model赋值了,那么意味着在调用add或者del方法的时候cal不再是空的了 BeanUtils.populate(model, req.getParameterMap()); } 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 e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } 在这里插入代码片