1.什么是MVC
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范。用一种业务逻辑、数据、界面显示分离的方法,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。
MVC结构
- Model:是应用程序中用于处理应用程序数据逻辑的部分,通常模型对象负责在数据库中存取数据。
- View:是应用程序中处理数据显示的部分,通常视图是依据模型数据创建的。
- Controller:是应用程序中处理用户交互的部分,通常控制器负责从视图读取数据,控制用户输入,并向模型发送数据。
MVC是一个框架模式,它强制性的使应用程序的输入、处理和输出分开。使用MVC应用程序被分成三个核心部件:模型、视图、控制器。它们各自处理自己的任务。最典型的MVC就是JSP + servlet + javabean的模式
- Model:常用javabean去实现,通过各种类来对数据库的数据进行获取,并封装在对象当中。
- View:常用JSP来实现,通过可直接观察的JSP页面来展示我们从数据库中获取的数据。
- Controller:常用servlet来实现,通过servlet来获取经过javabean包装过的对象(已存入数据库中的数据),然后再发送数据传输到JSP界面。
- 1)不能跨层调用; 2)只能由上往下进行调用:View -> Controller -> Model
MVC优化:
开始创建配置文件
<?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>
要将这个做成架包,所以里面的东西不能是死的,不然就会有新的就会改变,所以我们就用到了建模,将它变成活,到时候只要在配置文件里面添加即可 以前都是将子控制器放在Map集合中,现在要将其放在MVC.XML文件中
DispatherAction :
package com.zhanghao.framework; import java.io.IOException; 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; /** * 对应图中的ActionServlet:中央控制器 * * @author jj * */ @WebServlet("*.action") public class DispatherServlet extends HttpServlet { // public Map<String, Action> actionmap = new HashMap<String,Action>();//通过Map集合去拿到Action类 // 以前所有的子控制器都是放到Map集合中,现在所有的子控制器在mvc.xml中,其实就是放到configModel private ConfigModel configModel; public void init() throws ServletException {// 通过Map集合去拿到Action类之后,写一个初始化的方法init(),把所有的action放进去。(案例只有一个BookAction) // 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 request, HttpServletResponse response) throws ServletException, IOException { doPost(request, response); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // book -> BookAction -> add String uri = request.getRequestURI();// 获取URL地址 uri = uri.substring(uri.lastIndexOf("/"), uri.lastIndexOf("."));// 截取 // Action action = // actionmap.get(uri);//把所有的action放进init()方法之后,就可以通过map拿到uri,在这里返回一个action对象后续要通过它去抓取add等方法去提供服务 ActionModel actionModel = configModel.pop(uri);// 要通过uri=/book 在configModel对象中找值,而不是在Map里找 if (actionModel == null) throw new RuntimeException("action not config");//抛异常 // 返回的type值就是拿到com.Kissship.web.OrderAction路径 String type = actionModel.getType(); // BookAction bookaction = new BookAction();对象实例化 Action action; try { action = (Action) Class.forName(type).newInstance();// 反射实例化 //BookAction有没有实现ModelDriver接口 如果实现了才可向下转型 if(action instanceof ModelDriver) { ModelDriver md = (ModelDriver) action; Object bean = md.getModel();//这时候这model对象里还是没有值的 Map<String, String[]> map = request.getParameterMap();//所有参数值都在map里 BeanUtils.populate(bean, map);//将参数值封装到表对应的对象中 } //具体业务代码执行后的返回值————add/upd/del/list的返回值-》list/toList String res = action.execute(request, response);// 通过实例化的返回值action拿到execute反射代码块 //要通过返回值拿到,该方法结果是重定向还是转发,还是跳转哪个页面 ForwardModel forwardModel = actionModel.pop(res); if(forwardModel != null) { boolean redirect = forwardModel.isRedirect(); String path = forwardModel.getPath(); if(redirect) { response.sendRedirect(request.getContextPath() + "/" + path); }else { request.getRequestDispatcher(path).forward(request, response); } } } catch (Exception e) { e.printStackTrace(); } } }
如果你没有配置文件就会报错,下列是展示图:报action not config 就是没有配置文件
Action类:
下面我们这个Action类中所写的是我们改变了的返回参数
package com.zhanghao.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 jj * */ public class Action { protected String execute(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String methodName = request.getParameter("methodName"); String res = ""; try { Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class); m.setAccessible(true); res = (String) m.invoke(this, request, response); } catch (Exception e) { e.printStackTrace(); } return res; } }
ConfigModelFactory:
package com.zhanghao.utils; import java.io.InputStream; import java.util.Iterator; import java.util.List; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.Node; import org.dom4j.io.SAXReader; //工厂模式 public class ConfigModelFactory { //常量的定义 private static final String DEFAULT_PATH="/config.xml"; private ConfigModelFactory() {} public static ConfigModel createConfigModel() { return createConfigModel(DEFAULT_PATH); } public static ConfigModel createConfigModel(String path) { ConfigModel configModel=null; try { configModel=new ConfigModel(); //获取config.xml配置文件,并返回InputStream输入流 InputStream is=ConfigModelFactory.class.getResourceAsStream(DEFAULT_PATH); //创建SAXReader对象,读取InputStream输入流 SAXReader saxReader=new SAXReader(); Document doc=saxReader.read(is); //获取Xml文件中的元素信息进行建模 List<Node> lstNodes=doc.selectNodes("/config/action"); Element actionElement=null; String actionPath=null; String actionType=null; ActionModel actionModel=null; List<Node> forwardLstNodes=null; Element forwardElement=null; String forwardName=null; String forwardPath=null; String forwardRedirect=null; ForwardModel forwardModel=null; for (Node node : lstNodes) { //获取Action元素节点的属性信息 actionElement=(Element)node; actionPath=actionElement.attributeValue("path"); actionType=actionElement.attributeValue("type"); actionModel=new ActionModel(); actionModel.setPath(actionPath); actionModel.setType(actionType); configModel.push(actionModel); //获取Action元素节点下的Forward元素节点信息 forwardLstNodes=actionElement.selectNodes("forward"); for (Node forwardNode : forwardLstNodes) { forwardElement=(Element)forwardNode; forwardName=forwardElement.attributeValue("name"); forwardPath=forwardElement.attributeValue("path"); forwardRedirect=forwardElement.attributeValue("redirect"); //将属性值封装到实体对象 forwardModel=new ForwardModel(); forwardModel.setName(forwardName); forwardModel.setPath(forwardPath); forwardModel.setRedirect(forwardRedirect); actionModel.push(forwardModel); } } } catch (Exception e) { e.printStackTrace(); } return configModel; } public static void main(String[] args) { //XML建模,将XML配置文件中的元素信息转换成对象 ConfigModel configModel=ConfigModelFactory.createConfigModel(); System.out.println("OK"); //获取第一个Action中name为success的对象信息 ActionModel actionModel=configModel.get("/regAction"); ForwardModel forwardModel=actionModel.get("success"); System.out.println(forwardModel.getName()); System.out.println(forwardModel.getPath()); System.out.println(forwardModel.isRedirect()); } }
ForwardModel:
package com.zhanghao.utils; import java.io.Serializable; public class ForwardModel implements Serializable { private static final long serialVersionUID = 1L; private String name; private String path; private boolean redirect; public ForwardModel() { super(); } 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; } public void setRedirect(String redirect) { this.redirect = Boolean.parseBoolean(redirect); } }
BookAction:
package com.zhanghao.dao; import java.io.IOException; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.zhanghao.entity.Book; import com.zhanghao.framework.Action; import com.zhanghao.framework.ModelDriver; public class BookAction extends Action implements ModelDriver<Book>{ private Book book = new Book(); public String add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { Map<String, String[]> parameterMap = request.getParameterMap(); // String bid = request.getParameter("bid"); // String bname = request.getParameter("bname"); // String price = request.getParameter("price"); // Book book = new Book(); // book.setBid(Integer.valueOf(bid)); // book.setBname(bname); // book.setPrice(Float.valueOf(price)); System.out.println(book); System.out.println("BookAction.add..."); request.setAttribute("content", "Kissship"); // response.sendRedirect("res.jsp"); return "toList"; } public String del(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("BookAction.del..."); request.setAttribute("content", "Kissship"); // response.sendRedirect("res.jsp"); return "toList"; } public String upd(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("BookAction.upd..."); request.setAttribute("content", "Kissship"); // response.sendRedirect("res.jsp"); return "toList"; } public String list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("BookAction.list..."); request.setAttribute("content", "Kissship"); // request.getRequestDispatcher("res.jsp").forward(request, response); return "list"; } @Override public Book getModel() { return book; } }
到这我们就可以开始写jsp文件了
index.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> </head> <body> <p>版本1</p> 弊端:每一张表对应的每一个操作,都要写一个servlet类来处理<hr> <a href="bookAdd.action">增加</a> <a href="bookDel.action">删除</a> <a href="bookUpd.action">修改</a> <a href="bookList.action">查询</a> <hr><hr> <p>版本2</p> 弊端:每一张表对应的每一个操作,只要写一个servlet类来处理,但是每增加一个操作,都需要改变原有代码,换句话说要增加条件分支<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> <hr><hr> <p>版本3</p> 弊端:虽然解决了代码冗余的问题,但是放到项目范围,反射的代码是重复的<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> <hr><hr> <p>版本4</p> 弊端:中央控制器的action容器加载不可以灵活配置<hr> <a href="order.action?methodName=add">增加</a> <a href="order.action?methodName=del">删除</a> <a href="order.action?methodName=upd">修改</a> <a href="order.action?methodName=list">查询</a> <a href="goods.action?methodName=list">检验异常</a> <hr><hr> <p>版本5</p> 常识:查询必然转发,增删改使用重定向 弊端:中央控制器的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> <hr><hr> <p>版本6</p> 弊端:jsp传递到后台,封装到实体类的代码过多<hr> <a href="book.action?methodName=add&bid=1&bname=Kissship&price=9.9">增加</a> <a href="book.action?methodName=del">删除</a> <a href="book.action?methodName=upd">修改</a> <a href="book.action?methodName=list">查询</a> <hr><hr> <p>版本7</p> 解决了版本6的问题<hr> <a href="book.action?methodName=add&bid=2&bname=Kissship&price=99.9">增加</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文件用来测试
<%@ 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> </head> <body> 跳转成功:携带数据${content }; </body> </html>
请看结果如图: