protected void initStrategies(ApplicationContext context) {
//初始化多媒体解析器
initMultipartResolver(context);
//初始化语言支持
initLocaleResolver(context);
//初始化主题
initThemeResolver(context);
//初始化url-->Handler
initHandlerMappings(context);
//初始化HandlerAdapter具体的匹配调用过程
initHandlerAdapters(context);
//初始化调用异常处理器
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
//初始化视图解析器
initViewResolvers(context);
initFlashMapManager(context);
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
...
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
...
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
根据url正则匹配到mappedHandler 然后再拿到HandlerAdapter ha 通过ha反射调用具体对应的方法
下面开始撸我们自己的mvc框架,也按照springmvc的套路来
现在web.xml配置我们的servlet
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
version="2.4">
<servlet>
<servlet-name>SpringMVCservlet-name>
<servlet-class>com.fanday.mvc.servlet.DispatcherServletservlet-class>
<init-param>
<param-name>contextConfigLocationparam-name>
<param-value>applicationContext.propertiesparam-value>
init-param>
<load-on-startup>1load-on-startup>
servlet>
<servlet-mapping>
<servlet-name>SpringMVCservlet-name>
<url-pattern>/*url-pattern>
servlet-mapping>
web-app>
然后定义我们自己的Adapter和HandlerAdapter类
package com.fanday.mvc;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
public class Handler {
//调用对应的具体controller对象
private Object controller;
//和url匹配的方法
private Method method;
//对应RequestMapping的url正则
private Pattern pattern;
public Handler(Object controller, Method method, Pattern pattern) {
this.controller = controller;
this.method = method;
this.pattern = pattern;
}
public Object getController() {
return controller;
}
public void setController(Object controller) {
this.controller = controller;
}
public Method getMethod() {
return method;
}
public void setMethod(Method method) {
this.method = method;
}
public Pattern getPattern() {
return pattern;
}
public void setPattern(Pattern pattern) {
this.pattern = pattern;
}
}
package com.fanday.mvc;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Arrays;
import java.util.Map;
public class HandlerAdapter {
//保存对应的RequestParam value==>参数的位置
//或者HttpRequestServlet.getName()===>index
private Map paramType;
public HandlerAdapter(Map paramType) {
this.paramType = paramType;
}
/**
* 具体调用的方法
* @param req
* @param resp
* @param handler 和url匹配的handler
* @throws Exception
*/
public void handle(HttpServletRequest req, HttpServletResponse resp, Handler handler) throws Exception {
//获取要调用方法的全部参数类型
Class>[] parameterTypes = handler.getMethod().getParameterTypes();
//创建一个反射调用需要的参数值得数组,数组长度和参数长度一样
Object[] paramValues = new Object[parameterTypes.length];
/**
* 如果参数类型-->index map里面有HttpServletRequest
* 就在这个index下的数组赋值req
*/
if (paramType.containsKey(HttpServletRequest.class.getName())) {
paramValues[paramType.get(HttpServletRequest.class.getName())] = req;
}
if (paramType.containsKey(HttpServletResponse.class.getName())) {
paramValues[paramType.get(HttpServletResponse.class.getName())] = resp;
}
/**
* 循环遍历RequestParam value==>index
* 如果拿到的value在请求参数里面有
* 那么就从req中取出来赋值给数组
*
*/
for (Map.Entry entry : paramType.entrySet()) {
String paramName = entry.getKey();
Integer index = entry.getValue();
//拿到请求name对应的value
String[] values = req.getParameterValues(paramName);
if (values != null && values.length != 0){
String value = Arrays.toString(values).replaceAll("\\[|\\]", "").replaceAll(",\\s", ",");
//赋值给参数数组,并且把取出来的string类型转成我们参数的类型
paramValues[index] = castValueType(value,parameterTypes[index]);
}
}
//最后反射调用Controller的method方法
handler.getMethod().invoke(handler.getController(),paramValues);
}
private Object castValueType(String value, Class> clazz) {
if(clazz == String.class){
return value;
}else if(clazz == Integer.class){
return Integer.valueOf(value);
}else if(clazz == int.class){
return Integer.valueOf(value).intValue();
}else{
return null;
}
}
public Map getParamType() {
return paramType;
}
public void setParamType(Map paramType) {
this.paramType = paramType;
}
}
接下来开始写我们的DisPatchServlet
package com.fanday.mvc.servlet;
import com.fanday.ioc.annotation.Controller;
import com.fanday.ioc.annotation.RequestMapping;
import com.fanday.ioc.annotation.RequestParam;
import com.fanday.ioc.support.AnnotationApplicationContext;
import com.fanday.mvc.Handler;
import com.fanday.mvc.HandlerAdapter;
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.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Pattern;
public class DispatcherServlet extends HttpServlet {
public static final String CONTEXT_CONFIG_LOCATION = "contextConfigLocation";
private List handlerMapping = new ArrayList();
private Map adapterMapping = new ConcurrentHashMap();
@Override
public void init() throws ServletException {
//取出来web.xml中配置的param参数
String location = getInitParameter(CONTEXT_CONFIG_LOCATION);
//创建ApplicationContext上下文,启动bean的解析 创建 注入等过程
AnnotationApplicationContext context = new AnnotationApplicationContext(location);
//请求解析
initMultipartResolver(context);
//多语言、国际化
initLocaleResolver(context);
//主题View层的
initThemeResolver(context);
//解析url和Method的关联关系
initHandlerMappings(context);
//适配器(匹配的过程)
initHandlerAdapters(context);
//异常解析
initHandlerExceptionResolvers(context);
//视图转发(根据视图名字匹配到一个具体模板)
initRequestToViewNameTranslator(context);
//解析模板中的内容(拿到服务器传过来的数据,生成HTML代码)
initViewResolvers(context);
initFlashMapManager(context);
System.out.println("GPSpring MVC is init.");
}
private void initFlashMapManager(AnnotationApplicationContext context) {
}
private void initViewResolvers(AnnotationApplicationContext context) {
}
private void initRequestToViewNameTranslator(AnnotationApplicationContext context) {
}
private void initHandlerExceptionResolvers(AnnotationApplicationContext context) {
}
private void initHandlerAdapters(AnnotationApplicationContext context) {
if (handlerMapping.isEmpty()) return;
//遍历所有的handlerMapping
for (Handler handler : handlerMapping) {
Method method = handler.getMethod();
//创建一个保存RequestParam 注解的value(即参数名)==>index(参数位置索引)
Map paramType = new HashMap();
//获取所有的参数类型数组
Class>[] parameterTypes = method.getParameterTypes();
for (int i = 0; i < parameterTypes.length; i++) {
Class> type = parameterTypes[i];
//如果有HttpServletRequest类型就往map中保存 类型名==>index
if (type == HttpServletRequest.class || type == HttpServletResponse.class) {
paramType.put(type.getName(),i);
}
}
//获取所有的参数注解,之所以返回二维数组,是因为每个参数可能有
//多个注解修饰
Annotation[][] pas = method.getParameterAnnotations();
for (int i = 0; i < pas.length; i++) {
//获取第i个参数的修饰注解数组
Annotation[] pa = pas[i];
//遍历每个参数的修饰注解
for (Annotation a:pa){
if(a instanceof RequestParam){
String paramName = ((RequestParam) a).value();
if(!"".equals(paramName)){
//如果注解属于@RequestParam
//把注解参数 name==>index保存map
paramType.put(paramName,i);
}
}
}
}
adapterMapping.put(handler,new HandlerAdapter(paramType));
}
}
/**
* 初始化handlerMappings
* @param context
*/
private void initHandlerMappings(AnnotationApplicationContext context) {
//获取context中所有的bean
Map beans = context.getBeans();
if (beans.isEmpty()) return;
for (Map.Entry entry : beans.entrySet()) {
//只对controller修饰的类做解析
if (!entry.getValue().getClass().isAnnotationPresent(Controller.class)) return;
String url = "";
Class> clazz = entry.getValue().getClass();
if (clazz.isAnnotationPresent(RequestMapping.class)) {
//先取类上面的url
url = clazz.getAnnotation(RequestMapping.class).value();
}
Method[] methods = clazz.getMethods();
//再取对应方法上的url
for (Method m : methods) {
if (!m.isAnnotationPresent(RequestMapping.class)) continue;
String subUrl = m.getAnnotation(RequestMapping.class).value();
String regex = (url + subUrl).replaceAll("/+", "/");
Pattern pattern = Pattern.compile(regex);
//添加到handlerMapping中去
handlerMapping.add(new Handler(entry.getValue(), m, pattern));
}
}
}
private void initThemeResolver(AnnotationApplicationContext context) {
}
private void initLocaleResolver(AnnotationApplicationContext context) {
}
private void initMultipartResolver(AnnotationApplicationContext context) {
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
this.doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
try {
doDispatch(req,resp);
} catch (Exception e) {
e.printStackTrace();
}
}
private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
//取出匹配的handler
Handler handler = getHandler(req);
//根据handler取出HandlerAdapter
HandlerAdapter ha = getHandlerAdapter(handler);
//调用handle方法处理请求,暂时未做ModalAndView处理
ha.handle(req,resp,handler);
}
private HandlerAdapter getHandlerAdapter(Handler handler) {
if(adapterMapping.isEmpty())return null;
return adapterMapping.get(handler);
}
private Handler getHandler(HttpServletRequest req) {
if(handlerMapping.isEmpty())return null;
String contextPath = req.getContextPath();
String url = req.getRequestURI();
//获取请求的url 除去contextPath剩余的
url = url.replace(contextPath,"").replaceAll("/+","/");
for (Handler handler:handlerMapping){
if(handler.getPattern().matcher(url).matches()){
//匹配到就把handler返回
return handler;
}
}
return null;
}
}
测试我们的mvc框架
至此mvc框架也完成了,剩余的就是模板引擎的处理了,说一下模板的大致思想:
代码下载传送门