1.SpringMVC的工作流程
- 客户发送请求 (request)
- 请求交由核心处理(DispatcherServlet)
- 核心控制器找到映射器,映射器看看请求路径是什么(HandleMapping)
- 控制器再找到适配器,看看有哪些类实现了Controller接口或者对应的Bean对象(HandleAdapter)
- 将带过来的数据进行转换,格式化等等操作 找到我们的控制器Action,处理完业务之后返回
- 最后通过视图解析器来对ModelAndView进行解析
- 跳转到对应的JSP/html页面
2.核心代码
2.1 在web.xml中配置使得controller的请求都经过DispatcherServlet
2.2DispatcherServlet
```java package com.woniuxy.myspringmvc.core;
import java.io.File; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; import java.util.Properties; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
import com.fasterxml.jackson.databind.ObjectMapper; import com.woniuxy.myspringmvc.annotation.ResponseBody; import com.woniuxy.myspringmvc.annotation.ResponseForward; import com.woniuxy.myspringmvc.annotation.ResponseRedirect;
public class DispatcherServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
// 配置文件
private Properties configProp = new Properties();
// 获取包下controller类全名
private List
private void doScanner(String packageName) {
// 类全名:包名+类名
// 将包名转化为文件路径
String packagePath = packageName.replaceAll("\\.", "/");
// 获取src文件下的真实路径,widow中空格是%20,要将他转换成空格
String path = DispatcherServlet.class.getClassLoader().getResource(packagePath).getPath().replace("%20", " ");
// 创建file对象
File file = new File(path);
// 判断文件是否存在
if (!file.exists()) {
return;
}
// 获取子文件
File[] files = file.listFiles();
for (File f : files) {
if (f.isDirectory()) {
doScanner(packageName + "." + f.getName());
} else {
// 获取源文件名称
String fileName = f.getName();
// 获取类名
String name = fileName.replace(".class", "");
// 类全名
String className = packageName + "." + name;
// 存储到controllers中
//System.out.println(className);
classNames.add(className);
}
}
System.out.println(path);
}
private void loadProperties(ServletConfig config) {
// 根据name获取servlet初始化参数值
String configName = config.getInitParameter("config");
// 如果用户配置了文件名,则以配置的为准,否则取默认值
if (configName == null) {
configName = "application.properties";
}
InputStream is = null;
try {
is = DispatcherServlet.class.getClassLoader().getResourceAsStream(configName);
configProp.load(is);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null)
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Object result = handlerAdapter.adapter(request, response);
if (result==null) {
return;
}
//获取当前方法对象
Method method=handlerMapper.getMethodMapper().get(request.getPathInfo());
if (method.isAnnotationPresent(ResponseBody.class)) {
//设置响应内容类型
response.setContentType("application/json;charset=utf-8");
//将返回值的java对象转化成json,并通过指定输出流写出
new ObjectMapper().writeValue(response.getOutputStream(),result);
}else if(method.isAnnotationPresent(ResponseForward.class)){
String path=(String)result;
//请求转发
request.getRequestDispatcher("../../"+path).forward(request, response);
}else if(method.isAnnotationPresent(ResponseRedirect.class)){
String path=(String)result;
//重定向
response.sendRedirect(path);
}
}
}
<a name="6zImK"></a>
## 2.3HandlerMapping
```java
package com.woniuxy.myspringmvc.core;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.woniuxy.myspringmvc.annotation.Controller;
import com.woniuxy.myspringmvc.annotation.RequestMapping;
public class HandlerMapper {
// 存储controller的实例,键:类名,值:对应controller对象
private Map<String, Object> controllers = new HashMap<String, Object>();
// 存储请求URL与controller映射,键:请求URL,值controller对象
private Map<String, Object> controllerMapper = new HashMap<String, Object>();
// 存储请求URL与controller映射,键:请求URL,值controller对象的方法
private Map<String, Method> methodMapper = new HashMap<String, Method>();
public HandlerMapper(List<String> classNames) {
// 实例化:创建添加了controller注解的controller对象,并存储到controllers中
doInstance(classNames);
// 建立映射,建立请求与controller的方法映射
initHandlerMapper();
}
private void initHandlerMapper() {
// 循环遍历每个controller对象
for (Object controller : controllers.values()) {
// 获取当前controller对象的class实例;
Class cl = controller.getClass();
// 判断当前controller类上是否存在RequestMapping注解
if (cl.isAnnotationPresent(RequestMapping.class)) {
// 获取requestmapping注解
RequestMapping controllerRequestMapping = (RequestMapping) cl
.getDeclaredAnnotation(RequestMapping.class);
// 获取注解值
String controllerRequestMappingValue = controllerRequestMapping.value();
// 获取controller类所有方法
Method[] methods = cl.getDeclaredMethods();
for (Method method : methods) {
// 判断当前方法是否存在requestmapping注解
if (method.isAnnotationPresent(RequestMapping.class)) {
// 获取当前方法的requestmapping注解
RequestMapping methodRequestMapping = method.getDeclaredAnnotation(RequestMapping.class);
// 获取当前方法上的request1mapping注解值
String methodRequestMappingValue = methodRequestMapping.value();
// 生成键
String key = controllerRequestMappingValue + methodRequestMappingValue;
// 建立请求与controller的映射
controllerMapper.put(key, controller);
// 建立请求与method的映射
methodMapper.put(key, method);
}
}
}
}
}
private void doInstance(List<String> classNames) {
// 循环遍历每个controller全类名
for (String className : classNames) {
try {
// 通过类全名获取class实例
Class cl = Class.forName(className);
// 判断当前controller上是否存在controlle注解
if (cl.isAnnotationPresent(Controller.class)) {
// 创建目标controller对象
Object o = cl.newInstance();
// 存储到controllers中
controllers.put(cl.getSimpleName(), o);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
public Map<String, Object> getControllers() {
return controllers;
}
public void setControllers(Map<String, Object> controllers) {
this.controllers = controllers;
}
public Map<String, Object> getControllerMapper() {
return controllerMapper;
}
public void setControllerMapper(Map<String, Object> controllerMapper) {
this.controllerMapper = controllerMapper;
}
public Map<String, Method> getMethodMapper() {
return methodMapper;
}
public void setMethodMapper(Map<String, Method> methodMapper) {
this.methodMapper = methodMapper;
}
}
2.4HandlerAdapter
package com.woniuxy.myspringmvc.core;
import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.Iterator;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class HandlerAdapter {
private HandlerMapper handlerMapper;
public HandlerAdapter(HandlerMapper handlerMapper) {
this.handlerMapper = handlerMapper;
}
public Object adapter(HttpServletRequest request, HttpServletResponse response) throws IOException {
Object result = null;
// 获取请求的映射键
String key = request.getPathInfo();
// 根据键查找对应controller对象以及method对象
Object controller = handlerMapper.getControllerMapper().get(key);
Method method = handlerMapper.getMethodMapper().get(key);
if (controller == null | method == null) {
response.sendError(404, "请求的controller或method不存在!");
return result;
}
// 获取参数个数
int methodParamCount = method.getParameterCount();
// 存储方法参数实参
Object[] realMethodParams = new Object[methodParamCount];
// 获取页面所有参数的map对象
Map<String, String[]> pageParamVals = request.getParameterMap();
// 获取方法所有参数
Parameter[] methodParames = method.getParameters();
for (int i = 0; i < methodParames.length; i++) {
// 每一个形参
Parameter methodParam = methodParames[i];
// 获取方法参数类型
Class methodParamTypeCl = methodParam.getType();
// 获取参数方法名称
String methodTypeName = methodParamTypeCl.getSimpleName();
// 获取方法参数名称
String methodParamName = methodParam.getName();
// 判断参数数据类型
if (methodTypeName.equals("HttpServletRequest")) {
realMethodParams[i] = request;
} else if (methodTypeName.equals("HttpServletResponse")) {
realMethodParams[i] = response;
} else if (methodParamTypeCl.getClassLoader() == null) {
// java自带类型,比如String、int等
// 取出当前方法的参数的实参
String[] pageParamVal = pageParamVals.get(methodParamName);
// 判断参数是否存在
if (pageParamVal == null) {
response.sendError(404, method.getName() + "方法的" + methodParamName + "参数不存在!");
return result;
}
// 将客户端传参进行类型转换
realMethodParams[i] = parseType(pageParamVal, methodParamTypeCl);
} else {
// 自定义类型
Object o = null;
try {
// 创建目标类对象
o = methodParamTypeCl.newInstance();
// 获取当前类的属性
Field[] files = methodParamTypeCl.getDeclaredFields();
for (Field field : files) {
// 获取当前属性名称
String fieldName = field.getName();
// 根据属性名和方法参数名称获取前端参数键
String pageParamKey = methodParamName + "." + fieldName;
// 尝试从前端参数中取值
String[] pageParamVal = pageParamVals.get(pageParamKey);
if (pageParamVal == null) {
continue;
}
// 获取当前属性类型
Class fieldTypeCl = field.getType();
// 将String转为真实类型
Object val = parseType(pageParamVal, fieldTypeCl);
// 赋值
// 获取set方法名称
String fieldSetMethodName = "set" + (fieldName.charAt(0) + "").toUpperCase()
+ fieldName.substring(1);
// 获取set方法对象
Method fieldSetMethod = methodParamTypeCl.getDeclaredMethod(fieldSetMethodName, fieldTypeCl);
// 执行set方法,赋值
fieldSetMethod.invoke(o, val);
}
} catch (Exception e) {
e.printStackTrace();
}
realMethodParams[i] = o;
}
}
try {
result = method.invoke(controller, realMethodParams);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
private Object parseType(String[] pageParamVal, Class methodTypeCl) {
Object val = null;
// 存储当前目标类型是否为数组类型
boolean isArray = false;
// 存储元素类型名称
String aimTypeName = null;
// 判断目标类型是否为数组
if (methodTypeCl.isArray()) {
isArray = true;
aimTypeName = methodTypeCl.getComponentType().getSimpleName();
} else {
aimTypeName = methodTypeCl.getSimpleName();
}
// 分别判断目标类型,进行类型转换
if (aimTypeName.equals("String")) {
// 为数组
if (isArray) {
val = pageParamVal;
} else {
val = pageParamVal[0];
}
} else if (aimTypeName.equals("int")) {
if (isArray) {
int[] array = new int[pageParamVal.length];
for (int i = 0; i < pageParamVal.length; i++) {
array[i] = Integer.parseInt(pageParamVal[i]);
}
val = array;
} else {
int v = Integer.parseInt(pageParamVal[0]);
val = v;
}
} else if (aimTypeName.equals("byte")) {
if (isArray) {
byte[] array = new byte[pageParamVal.length];
for (int i = 0; i < pageParamVal.length; i++) {
array[i] = Byte.parseByte(pageParamVal[i]);
}
val = array;
} else {
byte v = Byte.parseByte(pageParamVal[0]);
val = v;
}
} else if (aimTypeName.equals("boolean")) {
if (isArray) {
Boolean[] array = new Boolean[pageParamVal.length];
for (int i = 0; i < pageParamVal.length; i++) {
array[i] = Boolean.parseBoolean(pageParamVal[i]);
}
val = array;
} else {
Boolean v = Boolean.parseBoolean(pageParamVal[0]);
val = v;
}
}else if (aimTypeName.equals("double")) {
if (isArray) {
Double[] array = new Double[pageParamVal.length];
for (int i = 0; i < pageParamVal.length; i++) {
array[i] = Double.parseDouble(pageParamVal[i]);
}
val = array;
} else {
Double v = Double.parseDouble(pageParamVal[0]);
val = v;
}
}else if (aimTypeName.equals("char")) {
if (isArray) {
Character[] array = new Character[pageParamVal.length];
for (int i = 0; i < pageParamVal.length; i++) {
array[i] = pageParamVal[i].charAt(0);
}
val = array;
} else {
Character v = pageParamVal[0].charAt(0);
val = v;
}
}
return val;
}
}