1. 什么是MVC
MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,
它是一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码
Model1 jsp+jdbc
Model2 ->MVC
核心思想:各司其职
2. MVC结构
V
jsp/ios/android
C
servlet/action
M
实体域模型(名词)
过程域模型(动词)
注1:不能跨层调用
注2:只能出现由上而下的调用
3. 自定义MVC工作原理图
5. 通过XML对自定义mvc框架进行增强
5.1 将Action的信息配置到xml(反射实例化)
ConfigModelFactory.java
package com.lww.framework;
import java.io.IOException;
import java.net.URL;
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 web.AddCalAction;
import web.DelCalAction;
/**
* 中央控制器
* 作用:
* 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务
*
* 1.对存放次控制器action容器的增强
* 为了完成业务需求,需要不断修改框架的代码,这样设计是不合理的
* 处理方式:参照web.xml的实际方法,来完成中央控制器管理子控制器的动态
* */
public class DispatcherServlet extends HttpServlet{
private static final long serialVersionUID = -1527313358696067967L;
// private Map<String, Action> actionMap=new HashMap<String, Action>();
private ConfigModel configModel = null;
public void init() {
// actionMap.put("/cal_add", new AddCalAction());
// actionMap.put("/cal_del", new DelCalAction());
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);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String url=req.getRequestURI();
url=url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
// AddCalAction action=(AddCalAction)actionMap.get(url);
// Action a=(Action)action;
// Action action=actionMap.get(url);
//
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();
}
//
}
}
mvc.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/cal_add" type="web.AddCalAction">
<forward name="rs" path="/rs.jsp" redirect="false" />
</action>
<action path="/cal_del" type="web.DelCalAction">
<forward name="rs" path="/rs.jsp" redirect="false" />
</action>
</config>
然后在把ConfigModelFactory.java类的返回值改为mvc.xml
return newInstance("mvc.xml");
结果如下:
加
减
5.2 通过结果码控制页面的跳转
AddCalAction.java
package web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lww.framework.Action;
import entity.Cal;
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);;
return "rs";
}
}
DelCalAction.java
package web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.lww.framework.Action;
import entity.Cal;
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";
}
}
ConfigModelFactory.java
package com.lww.framework;
import java.io.IOException;
import java.net.URL;
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 web.AddCalAction;
import web.DelCalAction;
/**
* 中央控制器
* 作用:
* 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务
*
* 1.对存放次控制器action容器的增强
* 为了完成业务需求,需要不断修改框架的代码,这样设计是不合理的
* 处理方式:参照web.xml的实际方法,来完成中央控制器管理子控制器的动态
*
* 2 处理结果码的跳转形式
* 达到简化代码的目的
* */
public class DispatcherServlet extends HttpServlet{
private static final long serialVersionUID = -1527313358696067967L;
// private Map<String, Action> actionMap=new HashMap<String, Action>();
private ConfigModel configModel = null;
public void init() {
// actionMap.put("/cal_add", new AddCalAction());
// actionMap.put("/cal_del", new DelCalAction());
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);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String url=req.getRequestURI();
url=url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
// AddCalAction action=(AddCalAction)actionMap.get(url);
// Action a=(Action)action;
// Action action=actionMap.get(url);
//
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 | IllegalAccessException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
}
}
结果如下:(加减都一样)+(mvc.xml配置不变)
5.3 将一组相关的操作放到一个Action中(反射调用方法)
DispatcherAction
methodName:add/minus/mul/div
CalAction.java
package web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.plaf.basic.BasicSliderUI.ActionScroller;
import com.lww.framework.ActionSopport;
import entity.Cal;
public class CalAction extends ActionSopport{
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";
}
}
ActionSopport.java
package com.lww.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;
/**
* 增强版的子控制器
* 作用:
* 将一组相关的操作放到一个Action中(反射调用方法)
* */
public class ActionSopport implements Action{
@Override
public String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//从前台传递需要调用的方法名到后台,实现动态方法调用
String methodName=req.getParameter("methodName");
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) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
return code;
}
}
mvc.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<config>
<action path="/cal" type="web.CalAction">
<forward name="rs" path="/rs.jsp" redirect="false" />
</action>
</config>
cal.jsp页面(部分截图)
运行结果如下:(加减都一样)
5.4 利用ModelDriver接口对Java对象进行赋值(反射读写方法)
BeanUtils.populate(calBean, parameterMap);
ModelDriver接口返回的对象不能为空
CalAction.java
package web;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.swing.plaf.basic.BasicSliderUI.ActionScroller;
import com.lww.framework.ActionSopport;
import com.lww.framework.ModelDriven;
import entity.Cal;
public class CalAction extends ActionSopport implements ModelDriven<Cal>{
private Cal cal=new Cal();
public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("rs", Integer.valueOf(cal.getNum1())+Integer.valueOf(cal.getNum2()));
return "rs";
}
public String del(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.setAttribute("rs", Integer.valueOf(cal.getNum1())-Integer.valueOf(cal.getNum2()));
return "rs";
}
@Override
public Cal getModel() {
return cal;
}
}
ModelDriven.java
package com.lww.framework;
/**
* 模型驱动接口:
* 作用:给对应处理业务的子控制器中包含的实体类进行jsp参数封装
*
* */
public interface ModelDriven<T>{
T getModel();
}
DispatcherServlet.java
package com.lww.framework;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
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 web.AddCalAction;
import web.DelCalAction;
/**
* 中央控制器
* 作用:
* 接受用户请求,通过用户请求的url寻找指定的子控制器去处理业务
*
* 1.对存放次控制器action容器的增强
* 为了完成业务需求,需要不断修改框架的代码,这样设计是不合理的
* 处理方式:参照web.xml的实际方法,来完成中央控制器管理子控制器的动态
*
* 2 处理结果码的跳转形式
* 达到简化代码的目的
*
* 3 将一组相关的操作放到一个Action中(反射调用方法)
DispatcherAction
methodName:add/minus/mul/div
4.处理jsp传递到后台的参数封装
* */
public class DispatcherServlet extends HttpServlet{
private static final long serialVersionUID = -1527313358696067967L;
// private Map<String, Action> actionMap=new HashMap<String, Action>();
private ConfigModel configModel = null;
public void init() {
// actionMap.put("/cal_add", new AddCalAction());
// actionMap.put("/cal_del", new DelCalAction());
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);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String url=req.getRequestURI();
url=url.substring(url.lastIndexOf("/"), url.lastIndexOf("."));
// AddCalAction action=(AddCalAction)actionMap.get(url);
// Action a=(Action)action;
// Action action=actionMap.get(url);
//
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("false".equals(forwardModel.getRedirect())) {
req.getRequestDispatcher(forwardModel.getPath()).forward(req, resp);
}else {
resp.sendRedirect(req.getContextPath()+forwardModel.getPath());
}
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException | InvocationTargetException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//
}
}
注:其他代码不变!!!
运行结果如下:
5.5 使得框架的配置文件可变
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>com.lww.mvc</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.lww.framework.DispatcherServlet</servlet-class>
<init-param>
<param-name>mvcXmlLocation</param-name>
<param-value>/lww.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
执行这些代码:DispatcherServlet.java
try {
String mvcXmlLocation= this.getInitParameter("mvcXmlLocation");
if(null==mvcXmlLocation || "".equals(mvcXmlLocation)) {
mvcXmlLocation="mvc.xml";
}
System.out.println("mvcXmlLocation"+mvcXmlLocation);
configModel = ConfigModelFactory.newInstance(mvcXmlLocation);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
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>com.lww.mvc</display-name>
<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>com.lww.framework.DispatcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>dispatcherServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
</web-app>
执行这些代码:DispatcherServlet.java
try {
String mvcXmlLocation= this.getInitParameter("mvcXmlLocation");
if(null==mvcXmlLocation || "".equals(mvcXmlLocation)) {
mvcXmlLocation="mvc.xml";
}
System.out.println("mvcXmlLocation"+mvcXmlLocation);
configModel = ConfigModelFactory.newInstance(mvcXmlLocation);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}