1.什么是MVC?
MVC全名:Model View Controller,其中Model(模型层)、View(视图层)、Controller(控制层)
它是一种软件设计典范,用于业务逻辑处理、数据、界面显示分离,
常用模式:
model1:jsp+jdbc
model2:mvc
三层架构和MVC的区别?
三层架构是一个经典的分层思想,将开发模式分为三层,每个人专注自己擅长模块即可
MVC是一种设计模式,其目的是让html和业务逻辑分开
2.MVC结构?
V(视图层)--》 JSP
C(控制层)--》 Servlet/Action
M(模型层)--》 Dao、Entity
1)实体域模型(entity层)
2)过程域模型(dao层)
注:1)不能跨层调用;
2)只能由上往下进行调用;View -> Controller -> Model
3.自定义MVC工作原理图
*.action 调度 截取*(请求路径名) 处理具体业务逻辑
JSP -----------> Servlet(中央控制器)--------------------->Action(子控制器)—>Model(Dao、DB)
通过XML对自定义MVC框架进行3步增强
一、反射增强第一步:
1)config.xml建模
2)获取Action配置信息 findActionModel
3)反射机制实例化Action子控制器 createAction
4)将请求委托给子控制器处理并返回结果码 execute() --> processCode
5)根据返回结果码进行页面跳转 --> forwardModel
重定向/转发
二、反射增强第二步: 将一组相关的操作放到一个Action中(反射调用方法)
1)创建DispatcherAction类
DispatcherAction extends Action
2)根据请求参数获取方法名,利用反射机制调用方法
参数名:methodName:add/minus/mul/div
3)创建CalAction类(CalAction提供一组加减乘除的方法)
CalAction extends DispatcherAction
提供一组与execute方法的参数、返回值相同的方法,只有方法名不一样
三、反射增强第三步:利用ModelDriver接口对Java对象进行赋值(反射读写属性)
1)利用反射机制对Java对象进行属性赋值
简化调用:BeanUtils.populate(calBean, parameterMap);
2)ModelDriver接口返回的对象不能为空
注1:Action多例模式?因为Action的属性要用来接收参数
xml建模:
package com.xujie.mvc.forward;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.io.InputStream;
import java.util.List;
/**
* xml建模
*/
public class ConfigModelFactory {
private static final String defpath="/abc.xml";
private static ConfigModel configModel;
public static ConfigModel createConfigModel() throws DocumentException {
return createConfigModel(defpath);
}
public static ConfigModel createConfigModel(String path) throws DocumentException {
if(null != configModel){
return configModel;
}
configModel = new ConfigModel();
//获取io流
InputStream is = ConfigModelFactory.class.getResourceAsStream(path);
//读取器对象
SAXReader sr = new SAXReader();
//得到document对象
Document document = sr.read(is);
List<Element> actionElement = document.selectNodes("/config/action");
ActionModel actionModel = null;
String actionPath = null;
String actionType = null;
ForwardModel forwardModel = null;
String forwardName = null;
String forwardPath = null;
boolean forwardRedirect = false;
for (Element a:actionElement
) {
actionModel = new ActionModel();
actionPath = a.attributeValue("path");
actionType = a.attributeValue("type");
actionModel.setPath(actionPath);
actionModel.setType(actionType);
configModel.put(actionModel);
//得到forward节点
List<Element> forward = a.selectNodes("forward");
//遍历forward节点
for (Element ward: forward
) {
forwardModel = new ForwardModel();
forwardName = ward.attributeValue("name");
forwardPath = ward.attributeValue("path");
forwardRedirect = Boolean.parseBoolean(ward.attributeValue("redirect"));
forwardModel.setPath(forwardPath);
forwardModel.setName(forwardName);
forwardModel.setRedirect(forwardRedirect);
//加到actionmodel里面的键值对里面
actionModel.put(forwardModel);
}
}
return configModel;
}
public static void main(String[] args) throws DocumentException {
ConfigModel model = ConfigModelFactory.createConfigModel();
System.out.println(model);
}
}
子控制器父类:
/**
* 子控制器父类 也不执行业务代码
*/
public abstract class Action {
public abstract String execute(HttpServletRequest req,HttpServletResponse resp) throws ServletException, IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException;
}
中央控制器:
package com.zking.j2ee12.mvc.framwork;
import com.zking.j2ee12.mvc.entity.CalBean;
import com.zking.j2ee12.mvc.xml.ActionMod;
import com.zking.j2ee12.mvc.xml.ConfigMod;
import com.zking.j2ee12.mvc.xml.ConfigTe;
import com.zking.j2ee12.mvc.xml.ForwardMod;
import org.apache.commons.beanutils.BeanUtils;
import org.dom4j.DocumentException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
/**
* 中央控制器 不执行业务代码,负责转发请求
*/
public class ActionServlet extends HttpServlet {
//定义一个集合 放入子控制器
// Map<String,Action> map = new HashMap<>();
private ConfigMod configMod;
@Override
public void init(ServletConfig config) throws ServletException {
try {
String path = config.getInitParameter("config");
if(null == path){
configMod = ConfigTe.createConfigTe();
}else{
configMod = ConfigTe.createConfigTe(path);
}
} catch (DocumentException e) {
throw new RuntimeException(e);
}
}
@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 servletPath = req.getServletPath();
int i = servletPath.lastIndexOf(".action");
String path = servletPath.substring(0, i);
//通过*部分 从集合找到对应的子控制器
ActionMod actionModel = this.findActionModel(path, configMod);
try {
//反射实例化对象
Action action = this.createAction(actionModel.getType());
//给实体类赋值
this.processModelDriver(action,req);
//执行子控制器中的execute方法
String code = action.execute(req, resp);
//通过execute方法的返回值控制跳转
this.processCode(code,actionModel,req,resp);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private ActionMod findActionModel(String path,ConfigMod configMod){
ActionMod actionMod = configMod.get(path);
if(null == actionMod){
throw new RuntimeException("找不到"+path+"对应的action");
}
return actionMod;
}
/**
* 反射实例化对象
* @param type
* @return
* @throws ClassNotFoundException
* @throws InstantiationException
* @throws IllegalAccessException
*/
private Action createAction(String type) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
//1.获取类对象
Class aClass = Class.forName(type);
//实例化对象
Action action =(Action) aClass.newInstance();
return action;
}
/**
* 处理execute方法的返回值 通过返回值实现跳转页面
*/
private void processCode(String code,ActionMod actionMod, HttpServletRequest req,HttpServletResponse resp) throws IOException, ServletException {
//1.通过code找到对应的forwardmodel对象
if(null == code || "".equals(code)){
return;//如果没有返回值 方法结束
}
//1.通过code找到对应的forwardmodel对象
ForwardMod forwardMod = actionMod.get(code);
if(null == forwardMod){//判断forwardmodel是否为空
throw new RuntimeException("找不到");
}
if(forwardMod.isRedirect()){//forwarmodel的属性为true
resp.sendRedirect(req.getContextPath()+forwardMod.getPath());
}else{
req.getRequestDispatcher(forwardMod.getPath()).forward(req,resp);
}
}
/**
* 配合modeldriver
*/
private void processModelDriver(Action action,HttpServletRequest req) {
//判断action是否实现了modeldriver接口
if(action instanceof ModelDriver){
//将action强转成modeldriver类型
ModelDriver md = (ModelDriver) action;
Object obj = md.getModel();
//遍历所有请求参数和obj的属性一致 就赋值
Map<String, String[]> map = req.getParameterMap();
try {
BeanUtils.populate(obj,map);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}
方法调用:
package com.zking.j2ee12.mvc.action;
import com.zking.j2ee12.mvc.framwork.Action;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
/**
* 处理一组相似或者相关的操作方法 反射调用方法
*/
public class DispatcherAction extends Action {
@Override
public final String execute(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
//1. 获取请求参数中的方法名
String methodName = this.getMethodName(req);
//2.放射调用方法
//2.1获取类对象
Class clazz = this.getClass();
//2.2获取方法对象
Method declaredMethod = clazz.getDeclaredMethod(methodName, HttpServletRequest.class, HttpServletResponse.class);
//2.3打开访问限制
declaredMethod.setAccessible(true);
//调用方法
String code =(String) declaredMethod.invoke(this, req, resp);
return code;
}
private String getMethodName(HttpServletRequest req){
String methodName = req.getParameter("methodName");
if(null == methodName || "".equals(methodName)){
Map<String, String[]> map = req.getParameterMap();
Set<String> set = map.keySet();
for (String key: set
) {
if(-1 != key.indexOf("method:")){
methodName = key.replaceAll("method:", "");
}
}
}
return methodName;
}
}
给实体类赋值:
/**
* 配合actionservlet 给实体类赋值
* @param <K>
*/
public interface ModelDriver<K> {
public K getModel();
}
web.xml配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<!--配置中央控制器-->
<servlet>
<servlet-name>ActionServlet</servlet-name>
<servlet-class>com.xujie.mvc.forward.ActionServlet</servlet-class>
<!--配置文件路径-->
<init-param>
<param-name>config</param-name>
<param-value>/abc.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>ActionServlet</servlet-name>
<url-pattern>*.action</url-pattern>
</servlet-mapping>
<!--配置中文乱码-->
<filter>
<filter-name>EncodingFilter</filter-name>
<filter-class>com.xujie.mvc.util.EncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>EncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--欢迎页面-->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
package com.zking.j2ee12.mvc.action;
import com.zking.j2ee12.mvc.entity.CalBean;
import com.zking.j2ee12.mvc.framwork.Action;
import com.zking.j2ee12.mvc.framwork.ModelDriver;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* 子控制器 负责用户的操作
*/
public class CalAction extends DispatcherAction implements ModelDriver<CalBean> {
private CalBean calBean = new CalBean();
public String add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Float rs = calBean.getNum1()+ calBean.getNum2();
req.getSession().setAttribute("rs",rs);
return "rs";
}
@Override
public CalBean getModel() {
return calBean;
}
}
config.xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!--
config标签:可以包含0~N个action标签
-->
<config>
<!--
action标签:可以饱含0~N个forward标签
path:以/开头的字符串,并且值必须唯一 非空
type:字符串,非空
-->
<action path="/calAction" type="com.zking.j2ee12.mvc.action.CalAction">
<!--
forward标签:没有子标签;
name:字符串,同一action标签下的forward标签name值不能相同 ;
path:以/开头的字符串
redirect:只能是false|true,允许空,默认值为false
-->
<forward name="rs" path="/rs.jsp" redirect="true" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
<action path="/userAction" type="com.zking.j2ee12.mvc.action.UserAction">
<forward name="rs" path="/rs.jsp" redirect="true" />
<forward name="success" path="/main.jsp" redirect="true" />
</action>
</config>