10.1 MVC概念
在最开始的Web结构中,一个请求需要用一个Servlet来进行处理,这样做的坏处是,一个项目往往有成百上千个请求,那就需要成百上千的Servlet,文件多,代码冗余,这是令人无法接受的。所以我们引入MVC的架构模式。
MVC概念:
M:Model模型
V:View视图
C:Controller控制器
MVC是在表述层开发中运用的一种设计理念。主张把封装数据的『模型』、显示用户界面的『视图』、**协调调度的『控制器』**分开。
在MVC中,控制器是核心,控制着用户请求到业务逻辑的映射关系。通过MVC架构,后端的业务逻辑可以从冗余的代码中解放出来,从而专注于业务的处理,将请求映射、参数获取、视图跳转这些统一的操作交给控制器来做,从而能一定程度上实现代码解耦。
10.2 MVC和三层架构之间关系
10.3 控制器实例代码(DispatcherServlet)
控制器代码总结:
- 通过请求路径获取处理本次请求的controller对象
- 通过请求中的operate参数,获取controller对象中对本次请求的具体处理方法
- 通过反射获取方法的真实参数名,通过参数名从请求域中获取参数
- 通过方法的返回值进行视图跳转
package servlet;
import impl.FruitDAOImpl;
import org.junit.Test;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import pojo.Fruit;
import util.JDBCUtils;
import util.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.sql.Connection;
import java.util.HashMap;
@WebServlet(urlPatterns = "*.do")
public class DispatcherServlet extends ViewBaseServlet {
private HashMap<String, Object> beanMap = new HashMap<>();
/**
* 构造方法:解析配置文件,将配置文件中的每个bean标签都加载一个实例对象,并保存到beanMap中
* 在这里主要是获取统一的执行对象
* 比如关于fruit的一系列操作都封装在fruitController中,于是beanMap中初始化一个fruitController对象用于执行相关方法
*/
public DispatcherServlet(){
try {
InputStream inputStream = getClass().getClassLoader().getResourceAsStream("application-context.xml");
DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory.newInstance();
DocumentBuilder documentBuilder = documentBuilderFactory.newDocumentBuilder();
Document document = documentBuilder.parse(inputStream);
NodeList beanNodeList = document.getElementsByTagName("bean");
for (int i = 0; i < beanNodeList.getLength(); i++) {
Node beanNode = beanNodeList.item(i);
if (beanNode.getNodeType() == Node.ELEMENT_NODE){
Element beanElement = (Element) beanNode;
String beanId = beanElement.getAttribute("id");
String aClass = beanElement.getAttribute("class");
Object beanObj = Class.forName(aClass).getDeclaredConstructor().newInstance();
beanMap.put(beanId, beanObj);
}
}
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
//解析请求路径
String servletPath = request.getServletPath();
servletPath = servletPath.substring(1);
servletPath = servletPath.substring(0, servletPath.lastIndexOf(".do"));
// 通过请求路径获取要执行的方法的controller类对象
Object controllerBeanObj = beanMap.get(servletPath);
//通过请求的operate参数,获取处理本次请求的方法
String operate = request.getParameter("operate");
if(StringUtils.isEmpty(operate)){
operate = "index";
}
try {
// 获取controller类对象中要执行的方法
Method[] methods = controllerBeanObj.getClass().getDeclaredMethods();
for (Method method : methods) {
if (operate.equals(method.getName())){
//获取方法的参数
Parameter[] parameters = method.getParameters();
Object[] parametersValues = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
//获取方法的参数名,根据参数名进行传参
//Java8新特性可以直接获取方法的参数的真实名称,需要在Java Compiler中设置参数 -parameters
//如果是maven项目,想要获取方法参数真实名称则需要单独在pom.xml文件中进行配置,配置参数在文末列出
if ("request".equals(parameters[i].getName())){
parametersValues[i] = request;
} else if ("response".equals(parameters[i].getName())){
parametersValues[i] = response;
} else if ("session".equals(parameters[i].getName())){
parametersValues[i] = request.getSession();
} else {
String parameterName = parameters[i].getName();
String parameterValue = request.getParameter(parameterName);
String typeName = parameters[i].getType().getName();
if (parameterValue != null){
if ("java.lang.Integer".equals(typeName)){
parametersValues[i] = Integer.parseInt(parameterValue);
} else {
parametersValues[i] = parameterValue;
}
}
}
}
method.setAccessible(true);
String methodReturn = (String) method.invoke(controllerBeanObj, parametersValues);
if (methodReturn.startsWith("redirect:")){
String redirect = methodReturn.substring("redirect:".length());
response.sendRedirect(redirect);
} else{
processTemplate(methodReturn, request, response);
}
}
}
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}