思维导图

?一、自定义MVC
什么是mvc?
MVC模式是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型、视图和控制器。
问题
1、数据处理dao,代码思路基本重复
2、servlet代码思路基本重复
2.1、doget/dopost实际上doget基本用不上
2.2、实体类参数接受冗余(req.fetparammeter(""))
2.3、关于结果页面的跳转
3、jsp代码思路基本重复
解决方案
1、通用分页、单表的增删改(优化)
2、servlet不需要写冗余的代码
3、自定义jsp
二、框架
第一种方法:
1、4个servlet

1个servlet4个方法

第二种方法:
package com.lxy.mvc;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 为什么要学习自定义MVC框架? 关键词:自定义MVC 框架 之前的开发模式 MVC: 模型层(Model)视图层(view)
* 控制层(controller) MVC怎么出现的: 各司其职 餐馆:点菜、收银、炒菜、传菜、收拾桌子卫生 大了
* 编码:实体类、数据处理Dao、Servlet、jsp 代码量多了
*
* 自定义MVC(演绎过程) 分析:
* 1、数据处理Dao 代码思路基本重复(前几次讲到)
* 2、servlet 代码思路基本重复
* 2.1、doget/dopost,实际上doGet基本用不上
* 2.2、实体类参数接受代码冗余(req.getParammeter(""),尤其当实体类属性多的情况,封装到实体类中。。。)
* 2.3、关于结果页面的跳转(转发、重定向) req.getdispather("/index.jsp").forward(req.resp);
* resp.sendredirect("/index.jsp");
* 3、jsp 代码思路基本重复(HTML、js前几次讲到)
*
* 解决方案
* 1、通用分页(讲过的)、单表的增删改(优化)
* 2、servlet不需要写冗余的代码——> 自定义MVC框架
* 3、自定义jsp标签
* 框架:反射+设计模式(极大的减少了代码量,把重复性的代码交给框架完成,让程序员关注点放在项目业务)
* 1、通用分页指点+通用的增删改
* 2、各层(mc)数据Dao层、控制层代码缩减
* 3、前台代码的缩减优化
*
* @author zjjt
*
*/
public class BookServlet extends HttpServlet {
@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 methodName = req.getParameter("methodName");
if ("add".equals(methodName)) {
add(req, resp);
} else if ("edit".equals(methodName)) {
edit(req, resp);
} else if ("delect".equals(methodName)) {
delect(req, resp);
} else if ("list".equals(methodName)) {
list(req, resp);
} else if ("load".equals(methodName)) {
load(req, resp);
}
}
private void list(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.list()...");
}
private void delect(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.delect()...");
}
private void add(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.add()...");
}
private void edit(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.edit()...");
}
private void load(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.load()...");
}
}
方法调用

优点:代码少,把所有类结合到一起
缺点:每新增一个方法就要改动原来的逻辑,代码过于冗余
3、反射处理、动态调用方法
package com.lxy.mvc;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/book.action")
public class BookServlet extends HttpServlet{
@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 methodName = req.getParameter("methodName");
try {
Method m = this.getClass().getDeclaredMethod(methodName, HttpServletRequest.class,HttpServletResponse.class);
m.setAccessible(true);
m.invoke(this,req, resp);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void load(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.load()");
}
private void list(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.list()");
}
private void delete(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.delect()");
}
private void edit(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.edit()");
}
private void add(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.add()");
}
private void ref(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.ref()");
}
}
三、完成自定义mvc框架
目标:将自定义mvc框架原理形成代码、框架
优化中央控制器:BookServlet中要做增删改查,那么必须要在dopost方法中写反射动态调用新增方法
优化子控制器:对于Bookservlet中要做增删改查而言,依然是每一个servlet都要写doget/dopost方法
建立模型驱动接口:实体类参数接受代码冗余
关于结果界面的跳转(转发、重定向)
1、mvc原理图
2、中央控制器与子控制器优化?
中央控制器
package com.lxy.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 org.apache.commons.beanutils.PropertyUtils;
import com.lxy.mvc.BookAction;
import com.lxy.mvc.GoodsAction;
/**
* 中央控制器
* @author Administrator
* jsp:/book.action/goods.action/order.action...
*/
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet {
// 在当前中央控制器中必然会有所有子控制器的集合
// 缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
// 思考:在不改动代码的情况下,中央控制器也能找到对应的子控制器去处理浏览器请求
// 方案:我把加子控制器的逻辑/动作,放到配置文件中完成(Dbutil改连接信息是放在代码中完成/现在是放在Properties文件中完成)
// 放在配置文件中完成的好处在于:代码更加灵活,修改相关信息不用动代码了
// private Map<String, ActionSupport> actions = new HashMap<>();
// configModel对象又通过建模的知识,把所有的配置信息给读取过来了
private ConfigModel configModel = null;
/**
* 初始化所有的子控制器到当前的中央控制器中
*/
@Override
public void init() throws ServletException {
// 在集合中就有了一个子控制器
// actions.put("/book", new BookAction());
// actions.put("/goods", new GoodsAction());
// actions.put("/order", new OrderAction());
// ...
try {
configModel = ConfigModelFactory.build();
} 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 {
// 把子控制器与浏览器请求关联起来,"寻找"能够处理请求的子控制器
// http://localhost:8080/book.action?methodName=add-->BookAction.add();
/*
* 思路
* 1.url-->/book
* 2.通过/book字符串在actions找到BookAction
* 3.调用BookAction的add,想要调用add,实际上只要统一调用execute就可以了
*/
// 获取到浏览器的请求地址
String url = req.getRequestURI();
// url-->/book
url = url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
// 通过/book字符串在actions找到BookAction
// ActionSupport actrion = actions.get(url);
// 在Map中寻找子控制器-->在配置文件中寻找子控制器
/*
* 1.通过/book找到对应的ActionModel对象
* 2.通过ActionModel对象拿到类的全路径名com.zking.web.BookAction
* 3.反射实例化对象
*/
ActionModel actionModel = configModel.pop(url);
// 类的全路径名
String type = actionModel.getType();
ActionSupport action = null;
try {
// BookAction/GoodsAction/..
action = (ActionSupport) Class.forName(type).newInstance();
// 完成实体类参数的封装
if(action instanceof ModelDriver) {
// 当前子控制器实现了模型驱动接口
ModelDriver m = (ModelDriver) action;
// Book/Goods/..
Object bean = m.getModel();
// 所有的请求参数都在这,需要将所有的请求参数封装到Book/Goods/..
BeanUtils.populate(bean, req.getParameterMap());
// PropertyUtils.getProperty(bean, name)
}
// 执行业务逻辑 bookAction.add方法的返回值 “list”
/*
* 1.书籍新增那么跳转书籍展示页面BookList.jsp 转发
* 2.书籍编辑跳转编辑界面BookEdit.jsp 重定向
*/
String res = action.execute(req, resp);
ForwardModel forwardModel = actionModel.pop(res);
String path = forwardModel.getPath();
boolean isRedirect = forwardModel.isRedirect();
if(isRedirect) {
resp.sendRedirect(req.getContextPath()+path);
}else {
req.getRequestDispatcher(path).forward(req, resp);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
xml
<?xml version="1.0" encoding="UTF-8"?>
<config>
<!-- 在这里每加一个配置,就相当于actions.put("/goods", new GoodsAction());
这样就解决了代码灵活性的问题
-->
<action type="com.lxy.mvc.BookAction" path="/book">
<forward path="/bookList.jsp" redirect="false" name="list"/>
<forward path="/bookEdit.jsp" redirect="true" name="toEdit"/>
</action>
<action type="com.lxy.mvc.GoodsAction" path="/goods">
<forward path="/login.jsp" redirect="false" name="failed"/>
<forward path="/main.jsp" redirect="true" name="success"/>
</action>
<action type="com.lxy.mvc.OrderAction" path="/order">
<forward path="/login.jsp" redirect="false" name="failed"/>
<forward path="/main.jsp" redirect="true" name="success"/>
</action>
</config>
子控制器
package com.lxy.framework;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 子控制器
* 它来处理浏览器请求
* 针对于add/ref/other进行向上抽取、抽象 abstract
*/
public interface Action {
//这一个方法就是add/ref/other进行向上抽取的抽象方法
// 作用:能够处理浏览器的“所有”请求。包括add/ref/other...
// 通过返回值来决定跳转哪一个页面(至于是重定向/转发由中央控制器决定..)
public String execute(HttpServletRequest req, HttpServletResponse resp);
// private void add(HttpServletRequest req, HttpServletResponse resp) {
// System.out.println("bookDao.add()...");
// }
// private void ref(HttpServletRequest req, HttpServletResponse resp) {
// System.out.println("bookDao.ref()...");
// }
// private void other(HttpServletRequest req, HttpServletResponse resp) {
// System.out.println("bookDao.other()...");
// }
}
ActionSupport
package com.lxy.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 作用:能够处理浏览器的“所有”请求。包括add/ref/other...
*
*
*/
public class ActionSupport implements Action {
@Override
public String execute(HttpServletRequest req, HttpServletResponse resp) {
String methodName = req.getParameter("methodName");
String res = null;
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;
}
}
?建立模型驱动接口
ModelDriver模型驱动接口:
package com.lxy.framework;
/**
* 模型驱动接口
* 作用:帮助“中央控制器”完成参数封装的工程
*/
public interface ModelDriver<T> {
/**
* GoodsAction-->goods
* BookAction-->book
* ...
* @return
*/
T getModel();
}
中央器的操作?
// ConfigModel对象又通过建模的知识,把所有的的配置信息给读取过来
private ConfigModel configModel=null;
// 初始化所有的子控制器到当前的中央控制器中
public void init() throws ServletException {
// 在集合中就有了一个子控制器
// actions.put("/book", new BookAction());
// actions.put("/goods", new GoodsAction());
// ……
try {
configModel=ConfigModelFactory.build();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
1
中央控制器中的dopost
2.通过/book字符串在actions找到BookAction
// ActionSupport actrion = actions.get(url);
// 原来在Map中寻找子控制器——>现在在配置文件中寻找子控制器
/**
* 思路:
* 1.通过/book找到对应的ActionModel对象
* 2.通过ActionModel对象拿到类的全路径名com.lv.framework.BookAction
* 3.反射实例化对象
*/
ActionModel actionModel = configModel.pop(url);
// 拿到类的全路径名
String type = actionModel.getType();
ActionSupport action;
try {
action = (ActionSupport) Class.forName(type).newInstance();
// 完成实体类参数的封装
if(action instanceof ModelDriver) {
// 当前子控制器实现了模型驱动接口
ModelDriver m=(ModelDriver) action;
// Book/Goods……
Object bean=m.getModel();
// 所有的请求参数都在这,需要将所有的请求参数封装到Book/Goods……
BeanUtils.populate(bean, req.getParameterMap());
}
?
页面跳转
子控制器:针对于add/ref/other进行向上抽取、抽象
这个方法就是add/ref/other进行向上抽取的抽象方法 作用:能够处理浏览器的“所有”请求,包括add/ref/other 通过返回值来决定跳转哪一个页面,至于重定向还是转发,由中央控制器决定
package com.lxy.framework;
import java.io.IOException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 子控制器
* 针对于add/ref/other进行向上抽取、抽象
*/
@WebServlet("/Action")
public interface Action{
/*private void add(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("bookDao.edit()");
}*/
// 这个方法就是add/ref/other进行向上抽取的抽象方法
// 作用:能够处理浏览器的“所有”请求,包括add/ref/other
// 通过返回值来决定跳转哪一个页面,至于重定向还是转发,由中央控制器决定
public String execute(HttpServletRequest req, HttpServletResponse resp);
}
中央控制器?
String res=action.execute(req, resp);
ForwardModel forwardModel=actionModel.pop(res);
String path=forwardModel.getPath();
boolean isredirect = forwardModel.isRedirect();
// isredirect指是重定向
if(isredirect) {
resp.sendRedirect(req.getContextPath()+path);
}else {
req.getRequestDispatcher(path).forward(req, resp);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
|