MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写, 它是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码 核心思想:各司其职
总结: 主控制器:查看是否有对应的子控制器来处理用户请求,如果就调用子控制器来处理请求;没有就报错,就处理不了请求 子控制器:就是处理用户请求用的
原因:为了完成业务需求,需要不断修改框架代码,这样设计是不合理的
处理方式:参照web.xml的设计方法,来完成中央控制器管理子控制器的动态配置 代码如下: DispatcherServlet.java
package com.wangcomg.framework; import java.io.IOException; 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 com.wangcong.web.AddCalAction; import com.wangcong.web.DelCalAction; /** * 中央控制器 * 作用 * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * @author wangcong *1.对存放子控制器action容器的增强 *?原来为了完成业务需求,需要不断修改框架代码,这样设计是不合理的 *处理方式:参照web.xml的设计方法,来完成中央控制器管理子控制器的动态配置 */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 1127608027061642170L; private ConfigModel configModel=null; public void init() { try { configModel=ConfigModelFactory.newInstance(); } catch (Exception e) { 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 { String url=req.getRequestURI(); url=url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); ActionModel actionModel = configModel.get(url); try { Action action = (Action) Class.forName(actionModel.getType()).newInstance(); action.execute(req, resp); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <config> <action path="/cal_add" type="com.wangcong.web.AddCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_del" type="com.wangcong.web.DelCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> </config>ConfigModelFactory.java
package com.wangcomg.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"); } 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(); } } }打开服务运行cal.jsp 如下图:(只做了加减按钮) 点击+按钮时: 测试成功。说明加强成功。
由于每个数据处理页面都可能会有
req.getRequestDispatcher("/rs.jsp").forward(req, resp); resp.sendRedirect("/rs.jsp");所有在有增强2的来由 目的:达到简化代码的结果 修改代码如下: AddCalAction.java
package com.wangcong.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.wangcomg.eneity.Cal; import com.wangcomg.framework.Action; /** * 子控制器 * @author wangcong * */ public class AddCalAction implements Action{ @Override public String execute(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); //resp.sendRedirect("/rs.jsp"); return "rs"; } }DelCalAction.java
package com.wangcong.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.wangcomg.eneity.Cal; import com.wangcomg.framework.Action; /** * 子控制器 * @author wangcong * */ public class DelCalAction implements Action{ @Override public String execute(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"; } }DispatcherServlet.java
package com.wangcomg.framework; import java.io.IOException; 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 com.wangcong.web.AddCalAction; import com.wangcong.web.DelCalAction; /** * 中央控制器 * 作用 * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * @author wangcong *1.对存放子控制器action容器的增强 *?原来为了完成业务需求,需要不断修改框架代码,这样设计是不合理的 *处理方式:参照web.xml的设计方法,来完成中央控制器管理子控制器的动态配置 * *2.处理结果码的跳转形式 * 目的:达到简化代码的结果 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 1127608027061642170L; private ConfigModel configModel=null; public void init() { try { configModel=ConfigModelFactory.newInstance(); } catch (Exception e) { 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 { String url=req.getRequestURI(); url=url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); 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("false".equals(forwardModel.getRedirect())) { req.getRequestDispatcher(forwardModel.getPath()).forward(req, resp); }else { //注意,默认会缺损项目名 resp.sendRedirect(forwardModel.getPath()); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }mvc.xml
<?xml version="1.0" encoding="UTF-8"?> <config> <action path="/cal_add" type="com.wangcong.web.AddCalAction"> <forward name="rs" path="/rs.jsp" redirect="false" /> </action> <action path="/cal_del" type="com.wangcong.web.DelCalAction"> <forward name="rs" path="/rs.jsp"/><!-- 把redirect="false"去掉做测试 --> </action> </config>测试一下:正常运行+不会有问题但是运行-时会出现如下情况: 解决方法:
package com.wangcomg.framework; import java.io.IOException; 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 com.wangcong.web.AddCalAction; import com.wangcong.web.DelCalAction; /** * 中央控制器 * 作用 * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * @author wangcong *1.对存放子控制器action容器的增强 *?原来为了完成业务需求,需要不断修改框架代码,这样设计是不合理的 *处理方式:参照web.xml的设计方法,来完成中央控制器管理子控制器的动态配置 * *2.处理结果码的跳转形式 * 目的:达到简化代码的结果 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 1127608027061642170L; private ConfigModel configModel=null; public void init() { try { configModel=ConfigModelFactory.newInstance(); } catch (Exception e) { 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 { String url=req.getRequestURI(); url=url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); 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("false".equals(forwardModel.getRedirect())) { req.getRequestDispatcher(forwardModel.getPath()).forward(req, resp); }else { //注意,默认会缺损项目名 resp.sendRedirect(req.getContextPath()+forwardModel.getPath());//重点对比前面的。加了路径 } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }当修改地址栏去调用web里面的文件的时候可能会出现没有配置的情况则会出现:
mvx.xml
<?xml version="1.0" encoding="UTF-8"?> <config> <action path="/cal" type="com.wangcong.web.CalAction"> <forward name="rs" path="/rs.jsp" redirect="false"/> </action> </config>定义一个ActionSupport.java
package com.wangcomg.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; /** * * 增强版的子控制器 * 作用:将一组操作放到一个子控制器中(简化xml的配置) * @author wangcong * */ public class ActionSupport implements Action{ @Override public String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //从前台传递需要调用的方法名到后台,实现动态方法调用 String methodName = req.getParameter("methodName"); //思考:怎么获取到 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 e) { e.printStackTrace(); } catch (SecurityException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return code; } }定义一个CalAction.java
package com.wangcong.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.wangcomg.eneity.Cal; import com.wangcomg.framework.ActionSupport; public class CalAction extends ActionSupport{ public String add(HttpServletRequest req, HttpServletResponse resp) { 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())); return "rs"; } public String del(HttpServletRequest req, HttpServletResponse resp) { 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())); return "rs"; } }在更改cal.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <!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=ISO-8859-1"> <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"; } 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>测试结果成功:都能使用
新定义一个接口: ModelDriven
package com.wangcomg.framework; /** * 模型驱动接口 * 作用:给对应处理业务的子控制器中包含的实体类进行jsp参数封装 * @author wangcong * * @param <T> */ public interface ModelDriven<T> { T getModel(); }更改CalAction.java
package com.wangcong.web; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.wangcomg.eneity.Cal; import com.wangcomg.framework.ActionSupport; import com.wangcomg.framework.ModelDriven; public class CalAction extends ActionSupport implements ModelDriven<Cal>{ private Cal cal=new Cal(); public String add(HttpServletRequest req, HttpServletResponse resp) { req.setAttribute("rs",Integer.valueOf(cal.getNum1())+Integer.valueOf(cal.getNum2())); return "rs"; } public String del(HttpServletRequest req, HttpServletResponse resp) { req.setAttribute("rs",Integer.valueOf(cal.getNum1())-Integer.valueOf(cal.getNum2())); return "rs"; } @Override public Cal getModel() { // TODO Auto-generated method stub return cal; } }再更改DispatcherServlet.java
package com.wangcomg.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 org.apache.commons.beanutils.BeanUtils; import com.wangcong.web.AddCalAction; import com.wangcong.web.DelCalAction; /** * 中央控制器 * 作用 * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * @author wangcong *1.对存放子控制器action容器的增强 *?原来为了完成业务需求,需要不断修改框架代码,这样设计是不合理的 *处理方式:参照web.xml的设计方法,来完成中央控制器管理子控制器的动态配置 * *2.处理结果码的跳转形式 * 目的:达到简化代码的结果 * * *3.将一组操作一个子控制器去完成 * *4.处理jsp传递到后台的参数封装 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 1127608027061642170L; private ConfigModel configModel=null; public void init() { try { configModel=ConfigModelFactory.newInstance(); } catch (Exception e) { 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 { String url=req.getRequestURI(); url=url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); 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不再是空的了 //req.getParameterMap();//封装了所有前台的键值对 BeanUtils.populate(model, req.getParameterMap()); } String code=action.execute(req, resp); ForwardModel forwardModel = actionModel.get(code); if("false".equals(forwardModel.getRedirect())) { req.getRequestDispatcher(forwardModel.getPath()).forward(req, resp); }else { //注意,默认会缺损项目名 resp.sendRedirect(req.getContextPath()+forwardModel.getPath()); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }项目还是可以运行。
更改DispatcherServlet.java
package com.wangcomg.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 org.apache.commons.beanutils.BeanUtils; import com.wangcong.web.AddCalAction; import com.wangcong.web.DelCalAction; /** * 中央控制器 * 作用 * 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务 * @author wangcong *1.对存放子控制器action容器的增强 *?原来为了完成业务需求,需要不断修改框架代码,这样设计是不合理的 *处理方式:参照web.xml的设计方法,来完成中央控制器管理子控制器的动态配置 * *2.处理结果码的跳转形式 * 目的:达到简化代码的结果 * * *3.将一组操作一个子控制器去完成 * *4.处理jsp传递到后台的参数封装 * *5.解决框架配置文件重名冲突问题 * */ public class DispatcherServlet extends HttpServlet{ private static final long serialVersionUID = 1127608027061642170L; private ConfigModel configModel=null; public void init() { try { String mvxXmlLocation=this.getInitParameter("mvxXmlLocation"); if(null==mvxXmlLocation || "".equals(mvxXmlLocation)) { mvxXmlLocation="mvc.xml"; } System.out.println("mvxXmlLocation:"+mvxXmlLocation); configModel=ConfigModelFactory.newInstance(); } catch (Exception e) { 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 { String url=req.getRequestURI(); url=url.substring(url.lastIndexOf("/"), url.lastIndexOf(".")); 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不再是空的了 //req.getParameterMap();//封装了所有前台的键值对 BeanUtils.populate(model, req.getParameterMap()); } String code=action.execute(req, resp); ForwardModel forwardModel = actionModel.get(code); if("false".equals(forwardModel.getRedirect())) { req.getRequestDispatcher(forwardModel.getPath()).forward(req, resp); }else { //注意,默认会缺损项目名 resp.sendRedirect(req.getContextPath()+forwardModel.getPath()); } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }运行结果如下: 人为导入xml文件(自己搞出配置文件重名冲突问题 ) 写入一样的xml文件。 并更改web.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>MVC3</display-name> <servlet> <servlet-name>dispatcherServlet</servlet-name> <servlet-class>com.wangcomg.framework.DispatcherServlet</servlet-class> <init-param> <param-name>mvxXmlLocation</param-name> <param-value>/cong.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dispatcherServlet</servlet-name> <url-pattern>*.action</url-pattern> </servlet-mapping> </web-app>运行结果如下:
