1.mvc简介
MVC是一种架构型模式,它本身并不引入新的功能,只是用来指导我们改善应用程序的架构,使得应用的模型和视图相分离,从而得到更好的开发和维护效率,在MVC模式中,应用程序被划分成了模型(Model)、视图(View)和控制器(Controller)三个部分。
- 模型(Model):程序员编写程序应有的功能(实现算法等等)、数据库专家进行数据管理和数据库设计(可以实现具体的功能);
- 控制器(Controller):负责转发请求,对请求进行处理;
- 视图(View):界面设计人员进行图形界面设计。
?2.mvc工作原理
举例:?
<a href="ser.do?name=add">增加</a> <a href="ser.do?name=delete">删除</a> <a href="ser.do?name=upd">修改</a> <a href="ser.do?name=sele">查询</a>?
在之前的开发过程中,每一个界面都需要一个servlet 操作数据,最终达到目的,但是开发效率不
高;可以看的方法的调用取决于name ,那么我们把所有需要的方法放在一个servlet 中,通过name?
值控制方法的调用 ,这样的改变的确简便不少,但是每次新增加一个方法,都要改动原有的逻
辑,也就是说一直需要进行判断添加。我们可以利用放射,通过name 读取可以实现需求的方法
package com.wyy.web;
import java.io.IOException;
import java.lang.reflect.Method;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet("/ser.do")
public class setvlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// TODO Auto-generated method stub
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String name = req.getParameter("name");
// if("add".equals(name)) {
// add();
// }else if("delete".equals(name)) {
// del();
// }else if("upd".equals(name)) {
// upd();
// }else if("sele".equals(name)) {
// find();
//
// }
try {
//反射获取方法
Method m = this.getClass().getDeclaredMethod(name, HttpServletRequest.class,HttpServletResponse.class);
//打开权限
m.setAccessible(true);
m.invoke(this, req,resp);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void sele(HttpServletRequest req, HttpServletResponse resp) {
// TODO Auto-generated method stub
System.out.println("查询。。。。。。。。。");
}
private void upd(HttpServletRequest req, HttpServletResponse resp) {
// TODO Auto-generated method stub
System.out.println("修改。。。。。。。。。");
}
private void delete(HttpServletRequest req, HttpServletResponse resp) {
// TODO Auto-generated method stub
System.out.println("删除。。。。。。。。。");
}
private void add(HttpServletRequest req, HttpServletResponse resp) {
System.out.println("增加。。。。。。。。。");
}
}
后台输出:
增加。。。。。。。。。
?可以看到通过反射,解决了更改代码的问题,使代码更加灵活,我们只需要添加方法即可,反射
这段代码相当于中央控制器,并不直接处理浏览器请求,处理浏览器请求的是方法(子控制器)
那么 我们来思考一个问题:例如 book要进行增删改查,goods也要进行增删改查,那么在
bookServlet和goodsServlet都要写反射,一旦需求多了起来,反射代码会变得重复繁多,但是它
又是必须的,我们可以调整这段代码的位置,也就是说还需要进一步优化 ?
Action? ? 抽取所有处理请求的方法作为父类(子控制器)
package com.wyy.framework;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 子控制器
* 处理请求
* @author T440s
*
*/
public interface Action {
//所有请求处理方法的抽象方法
//处理所有请求
public void execte(HttpServletRequest req,HttpServletResponse resp);
}
?ActionSupport?
实现Action 重写execte方法 ,通过反射获取对应方法(处理所有请求)
作用:当出现更多需求时,只需要继承?ActionSupport 类即可
package com.wyy.framework;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ActionSupport implements Action {
/**
* 处理所有请求
*/
@Override
public void execte(HttpServletRequest req, HttpServletResponse resp) {
String parameter = req.getParameter("mathname");
try {
Method Method = this.getClass().getDeclaredMethod(parameter,HttpServletRequest.class,HttpServletResponse.class);
Method.setAccessible(true);
Method.invoke(this, req,resp);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return invoke;
}
}
?DispatchServlet (中央控制器)?
中央控制器作用:1.获取浏览器请求URL 2. 寻找可以处理请求的子控制器
- 在中央控制器中一定会存在一个储存着所有子控制器的集合
- 将所有子控制器初始化到中央控制器中
我们发现子控制器集合放在中央控制器中,当有了新的需求时,需要将子控制器添加到集合中,就
是说需要改的代码。那么我们将子控制器放到配置文件中,在初始化时,利用xml建模 将配置文件中
的子控制器读取出来,这样无论有多少需求,我们只需要在配置文件中配置即可。
package com.wyy.framework;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
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.dom4j.DocumentException;
import com.wyy.web.BookAction;
/**
* 中央控制器
* @author T440s
*
*/
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
//private Map<String , ActionSupport> map=new HashMap<String, ActionSupport>();
private ConfigModel config=null;
/**
* 在当前中央控制器中必然会有所有子控制器的集合
* 缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
* 放在配置文件中完成的好处在于:代码更加灵活,
*/
/**
* 初始化所有的子控制器到中央控制器
*/
@Override
public void init() throws ServletException {
//map.put("book", new BookAction());
try {
//xml建模 通过建模将配置文件中的信息读取
config= new ConfigModelFactory().buibl();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//寻找可以处理请求的子控制器
//获取浏览器的URL
String url = req.getRequestURI();
url=url.substring(url.indexOf("b"), url.lastIndexOf("."));
//ActionSupport action = map.get(url);
//action.execte(req, resp);
/**
* 通过url找到对应的对象
* 通过对象获取全路径名
* 反射实例化对象
*/
ActionModel popcon = config.popcon(url);
//全路径名
String type = popcon.getType();
try {
// 反射实例化对象 bookAction
ActionSupport action = (ActionSupport) Class.forName(type).newInstance();
action.execte(req, resp);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
xml配置文件
<action path="book" type="com.wyy.web.BookAction"> ?? ??? ?<forward name="list" path="booklist.jsp" redirect="false" /> ?? ??? ?<forward name="toEdit" path="toEdit.jsp" redirect="true" /> ?? ?</action>
获取请求参数(req.getparameter(""))
通常我们会通过请求获取页面上各种参数,代码冗余?
ModelDriver?帮助中央控制器完成参数封装的工程
package com.wyy.framework;
/**
* 模型驱动接口
* @author T440s
*
* @param <T>
*/
public interface ModelDriver<T> {
/**
* 获取模型对象的方法
* @return
*/
T getModel();
}
页面跳转方式,代码冗余
xml文件
????????<forward name="list" path="booklist.jsp" redirect="false" /> ?? ??? ?<forward name="toEdit" path="toEdit.jsp" redirect="true" />
name是?调用方法 , path是 跳转路径 ,redirect 是决定跳转方式
修改抽象方法execte的返回方式 ,通过execte返回值控制跳转页面
中央控制器优化
package com.wyy.framework;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
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.dom4j.DocumentException;
import com.wyy.web.BookAction;
/**
* 中央控制器
*
* @author T440s
*
*/
@WebServlet("*.action")
public class DispatchServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req, resp);
}
// private Map<String , ActionSupport> map=new HashMap<String, ActionSupport>();
private ConfigModel config = null;
/**
* 在当前中央控制器中必然会有所有子控制器的集合 缺陷:如果有商品的增删改查-->意味着要改动代码-->代码的设计不够灵活
* 放在配置文件中完成的好处在于:代码更加灵活,
*/
/**
* 初始化所有的子控制器到中央控制器
*/
@Override
public void init() throws ServletException {
// map.put("book", new BookAction());
try {
// xml建模 通过建模将配置文件中的信息读取
config = new ConfigModelFactory().buibl();
} catch (DocumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 寻找可以处理请求的子控制器
// 获取浏览器的URL
String url = req.getRequestURI();
url = url.substring(url.indexOf("b"), url.lastIndexOf("."));
// System.out.println(url);
// ActionSupport action = map.get(url);
// action.execte(req, resp);
/**
* 通过url找到对应的对象 通过对象获取全路径名 反射实例化对象
*/
ActionModel popcon = config.popcon(url);
// 全路径名
String type = popcon.getType();
try {
// 反射实例化对象 bookAction
ActionSupport action = (ActionSupport) Class.forName(type).newInstance();
// 完成实体类参数的封装
if (action instanceof ModelDriver) {
// 当前子控制器实现了模型驱动接口
ModelDriver m = (ModelDriver) action;
// 获取对象
Object model = m.getModel();
// 当前请求参数集合
Map<String, String[]> map = req.getParameterMap();
// BeanUtils.populate(model, map);
Set<Entry<String, String[]>> entrySet = map.entrySet();
// 反射获取对象属性
Field[] fie = model.getClass().getDeclaredFields();
for (Field field : fie) {
field.setAccessible(true);
// 获取属性名字
String name = field.getName();
for (Entry<String, String[]> entry : entrySet) {
// 当反射获取的对象属性名字与参数名相同时
if (entry.getKey().equals(name)) {
// 获取参数值
String val = entry.getValue()[0];
// 获取参数数据类型
String type3 = field.getType().toString();
Object o = val;
if (val != null) {
if (type3.equals("int")) {
o = Integer.parseInt(val);
}
if (type3.equals("float")) {
o = (float) Integer.parseInt(val);
}
}
field.set(model, o);
}
}
}
}
// 执行业务
// 通过返回值控制重定向 还是转发
String execte = action.execte(req, resp);
// 获取模型对象
ForwardModel pop = popcon.pop(execte);
// 获取跳转路径
String path = pop.getPath();
// 获取跳转方式
boolean isRedirect = pop.isRedirect();
if (isRedirect) {
resp.sendRedirect(path);
} else {
req.getRequestDispatcher(path).forward(req, resp);
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
通过浏览器请求建模获取对象全路径名,反射获取对象,判断对象是否继承模型驱动接口,因为只有继承了模型驱动接口才可以获得类对象(book),获取参数集合,通过反射将参数赋值给对应的对象属性。
package com.wyy.web;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wyy.framework.ActionSupport;
import com.wyy.framework.ModelDriver;
/**
* 继承父类的execte 方法 也就是继承反射调用动态方法
* @author T440s
*
*/
public class BookAction extends ActionSupport implements ModelDriver<Book>{
private Book b=new Book();
public String add(HttpServletRequest req,HttpServletResponse resp) {
System.out.println("----------------"+b);
return "list";
}
@Override
public Book getModel() {
// TODO Auto-generated method stub
return b;
}
}
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<a href="book.action?mathname=add" >增加</a>
<form action="book.action">
<input name="mathname" value="add" hidden=""/>
id<input name="bid"/>
书名<input name="bname"/>
价格<input name="price"/>
<button>提交</button>
</form>
</body>
</html>
后台打印
----------------Book [bid=1, bname=23, price=4.0] ?
?
|