1. 本章须要实现的内容:

  1. 实现ControllerRequestProcessor类的编写: Controller申请处理器
  2. 实现JspRequestProcessor类的编写:jsp资源申请解决
  3. 实现PreRequestProcessor类的编写: 申请预处理,包含编码以及门路解决
  4. 实现StaticResourceRequestProcessor类的编写: 动态资源申请解决,包含但不限于图片,css,以及js文件等, 转发到DefaultServlet

2. PreRequestProcessor类的编写

2.1 PreRequestProcessor类须要实现的代码

package org.myframework.mvc.processor.impl;/** * @author wuyiccc * @date 2020/6/16 18:54 * 岂曰无衣,与子同袍~ */import lombok.extern.slf4j.Slf4j;import org.myframework.mvc.RequestProcessorChain;import org.myframework.mvc.processor.RequestProcessor;/** * 申请预处理,包含编码以及门路解决 */@Slf4jpublic class PreRequestProcessor implements RequestProcessor {    @Override    public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {        // 1.设置申请编码,将其对立设置成UTF-8        requestProcessorChain.getRequest().setCharacterEncoding("UTF-8");        // 2.将申请门路开端的/剔除,为后续匹配Controller申请门路做筹备        // (个别Controller的解决门路是/aaa/bbb,所以如果传入的门路结尾是/aaa/bbb/,        // 就须要解决成/aaa/bbb)        String requestPath = requestProcessorChain.getRequestPath();        //http://localhost:8080/myframework requestPath="/"        if (requestPath.length() > 1 && requestPath.endsWith("/")) {            requestProcessorChain.setRequestPath(requestPath.substring(0, requestPath.length() - 1));        }        log.info("preprocess request {} {}", requestProcessorChain.getRequestMethod(), requestProcessorChain.getRequestPath());        return true;    }}

2.2 PreRequestProcessor类相干代码解说:

3. StaticResourceRequestProcessor类的编写

3.1 StaticResourceRequestProcessor类须要实现的代码:

package com.wuyiccc.helloframework.mvc.processor.impl;import com.wuyiccc.helloframework.mvc.RequestProcessorChain;import com.wuyiccc.helloframework.mvc.processor.RequestProcessor;import lombok.extern.slf4j.Slf4j;import javax.servlet.RequestDispatcher;import javax.servlet.ServletContext;/** * @author wuyiccc * @date 2020/7/14 22:40 * 岂曰无衣,与子同袍~ */@Slf4jpublic class StaticResourceRequestProcessor implements RequestProcessor {    public static final String DEFAULT_TOMCAT_SERVLET = "default";    public static final String STATIC_RESOURCE_PREFIX = "/static/";    //tomcat默认申请派发器RequestDispatcher的名称    RequestDispatcher defaultDispatcher;    public StaticResourceRequestProcessor(ServletContext servletContext) {        this.defaultDispatcher = servletContext.getNamedDispatcher(DEFAULT_TOMCAT_SERVLET);        if (this.defaultDispatcher == null) {            throw new RuntimeException("There is no default tomcat servlet");        }        log.info("The default servlet for static resource is {}", DEFAULT_TOMCAT_SERVLET);    }    @Override    public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {        //1.通过申请门路判断是否是申请的动态资源 webapp/static        if (isStaticResource(requestProcessorChain.getRequestPath())) {            //2.如果是动态资源,则将申请转发给default servlet解决            defaultDispatcher.forward(requestProcessorChain.getRequest(), requestProcessorChain.getResponse());            return false;        }        return true;    }    //通过申请门路前缀(目录)是否为动态资源 /static/    private boolean isStaticResource(String path) {        return path.startsWith(STATIC_RESOURCE_PREFIX);    }}

3.2 StaticResourceRequestProcessor类相干代码解说:

4. JspRequestProcessor

4.1 JspRequestProcessor须要实现的代码:

package org.myframework.mvc.processor.impl;import org.myframework.mvc.RequestProcessorChain;import org.myframework.mvc.processor.RequestProcessor;import javax.servlet.RequestDispatcher;import javax.servlet.ServletContext;/** * @author wuyiccc * @date 2020/6/16 18:59 * 岂曰无衣,与子同袍~ *//** * jsp资源申请解决 */public class JspRequestProcessor implements RequestProcessor {    //jsp申请的RequestDispatcher的名称    private static final String JSP_SERVLET = "jsp";    //Jsp申请资源门路前缀    private static final String JSP_RESOURCE_PREFIX = "/templates/";    /**     * jsp的RequestDispatcher,解决jsp资源     */    private RequestDispatcher jspServlet;    public JspRequestProcessor(ServletContext servletContext) {        jspServlet = servletContext.getNamedDispatcher(JSP_SERVLET);        if (null == jspServlet) {            throw new RuntimeException("there is no jsp servlet");        }    }    @Override    public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {        if (isJspResource(requestProcessorChain.getRequestPath())) {            jspServlet.forward(requestProcessorChain.getRequest(), requestProcessorChain.getResponse());            return false;        }        return true;    }    /**     * 是否申请的是jsp资源     */    private boolean isJspResource(String url) {        return url.startsWith(JSP_RESOURCE_PREFIX);    }}

4.2 JspRequestProcessor相干代码解说:

5. ControllerRequestProcessor类的编写

5.1 ControllerRequestProcessor须要实现的代码:

package org.myframework.mvc.processor.impl;import lombok.extern.slf4j.Slf4j;import org.myframework.core.BeanContainer;import org.myframework.mvc.RequestProcessorChain;import org.myframework.mvc.annotation.RequestMapping;import org.myframework.mvc.annotation.RequestParam;import org.myframework.mvc.annotation.ResponseBody;import org.myframework.mvc.processor.RequestProcessor;import org.myframework.mvc.render.JsonResultRender;import org.myframework.mvc.render.ResourceNotFoundResultRender;import org.myframework.mvc.render.ResultRender;import org.myframework.mvc.render.ViewResultRender;import org.myframework.mvc.type.ControllerMethod;import org.myframework.mvc.type.RequestPathInfo;import org.myframework.util.ConverterUtil;import org.myframework.util.ValidationUtil;import javax.servlet.http.HttpServletRequest;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.lang.reflect.Parameter;import java.util.*;import java.util.concurrent.ConcurrentHashMap;/** * @author wuyiccc * @date 2020/6/16 19:14 * 岂曰无衣,与子同袍~ *//** * Controller申请处理器 */@Slf4jpublic class ControllerRequestProcessor implements RequestProcessor {    //IOC容器    private BeanContainer beanContainer;    //申请和controller办法的映射汇合    private Map<RequestPathInfo, ControllerMethod> pathControllerMethodMap = new ConcurrentHashMap<>();    /**     * 依附容器的能力,建设起申请门路、申请办法与Controller办法实例的映射     */    public ControllerRequestProcessor() {        this.beanContainer = BeanContainer.getInstance();        Set<Class<?>> requestMappingSet = beanContainer.getClassesByAnnotation(RequestMapping.class);        initPathControllerMethodMap(requestMappingSet);    }    private void initPathControllerMethodMap(Set<Class<?>> requestMappingSet) {        if (ValidationUtil.isEmpty(requestMappingSet)) {            return;        }        //1.遍历所有被@RequestMapping标记的类,获取类下面该注解的属性值作为一级门路        for (Class<?> requestMappingClass : requestMappingSet) {            RequestMapping requestMapping = requestMappingClass.getAnnotation(RequestMapping.class);            String basePath = requestMapping.value();            if (!basePath.startsWith("/")) {                basePath = "/" + basePath;            }            //2.遍历类里所有被@RequestMapping标记的办法,获取办法下面该注解的属性值,作为二级门路            Method[] methods = requestMappingClass.getDeclaredMethods();            if (ValidationUtil.isEmpty(methods)) {                continue;            }            for (Method method : methods) {                if (method.isAnnotationPresent(RequestMapping.class)) {                    RequestMapping methodRequest = method.getAnnotation(RequestMapping.class);                    String methodPath = methodRequest.value();                    if (!methodPath.startsWith("/")) {                        methodPath = "/" + basePath;                    }                    String url = basePath + methodPath;                    //3.解析办法里被@RequestParam标记的参数,                    // 获取该注解的属性值,作为参数名,                    // 获取被标记的参数的数据类型,建设参数名和参数类型的映射                    Map<String, Class<?>> methodParams = new HashMap<>();                    Parameter[] parameters = method.getParameters();                    if (!ValidationUtil.isEmpty(parameters)) {                        for (Parameter parameter : parameters) {                            RequestParam param = parameter.getAnnotation(RequestParam.class);                            //目前暂定为Controller办法外面所有的参数都须要@RequestParam注解                            if (param == null) {                                throw new RuntimeException("The parameter must have @RequestParam");                            }                            methodParams.put(param.value(), parameter.getType());                        }                    }                    //4.将获取到的信息封装成RequestPathInfo实例和ControllerMethod实例,搁置到映射表里                    String httpMethod = String.valueOf(methodRequest.method());                    RequestPathInfo requestPathInfo = new RequestPathInfo(httpMethod, url);                    if (this.pathControllerMethodMap.containsKey(requestPathInfo)) {                        log.warn("duplicate url:{} registration,current class {} method{} will override the former one",                                requestPathInfo.getHttpPath(), requestMappingClass.getName(), method.getName());                    }                    ControllerMethod controllerMethod = new ControllerMethod(requestMappingClass, method, methodParams);                    this.pathControllerMethodMap.put(requestPathInfo, controllerMethod);                }            }        }    }    @Override    public boolean process(RequestProcessorChain requestProcessorChain) throws Exception {        //1.解析HttpServletRequest的申请办法,申请门路,获取对应的ControllerMethod实例        String method = requestProcessorChain.getRequestMethod();        String path = requestProcessorChain.getRequestPath();        ControllerMethod controllerMethod = this.pathControllerMethodMap.get(new RequestPathInfo(method, path));        if (controllerMethod == null) {            requestProcessorChain.setResultRender(new ResourceNotFoundResultRender(method, path));            return false;        }        //2.解析申请参数,并传递给获取到的ControllerMethod实例去执行        Object result = invokeControllerMethod(controllerMethod, requestProcessorChain.getRequest());        //3.依据解决的后果,抉择对应的render进行渲染        setResultRender(result, controllerMethod, requestProcessorChain);        return true;    }    /**     * 依据不同状况设置不同的渲染器     */    private void setResultRender(Object result, ControllerMethod controllerMethod, RequestProcessorChain requestProcessorChain) {        if (result == null) {            return;        }        ResultRender resultRender;        boolean isJson = controllerMethod.getInvokeMethod().isAnnotationPresent(ResponseBody.class);        if (isJson) {            resultRender = new JsonResultRender(result);        } else {            resultRender = new ViewResultRender(result);        }        requestProcessorChain.setResultRender(resultRender);    }    private Object invokeControllerMethod(ControllerMethod controllerMethod, HttpServletRequest request) {        //1.从申请里获取GET或者POST的参数名及其对应的值        Map<String, String> requestParamMap = new HashMap<>();        //GET,POST办法的申请参数获取形式        Map<String, String[]> parameterMap = request.getParameterMap();        for (Map.Entry<String, String[]> parameter : parameterMap.entrySet()) {            if (!ValidationUtil.isEmpty(parameter.getValue())) {                //只反对一个参数对应一个值的模式                requestParamMap.put(parameter.getKey(), parameter.getValue()[0]);            }        }        //2.依据获取到的申请参数名及其对应的值,以及controllerMethod外面的参数和类型的映射关系,去实例化出办法对应的参数        List<Object> methodParams = new ArrayList<>();        Map<String, Class<?>> methodParamMap = controllerMethod.getMethodParameters();        for (String paramName : methodParamMap.keySet()) {            Class<?> type = methodParamMap.get(paramName);            String requestValue = requestParamMap.get(paramName);            Object value;            //只反对String 以及根底类型char,int,short,byte,double,long,float,boolean,及它们的包装类型            if (requestValue == null) {                //将申请里的参数值转成适配于参数类型的空值                value = ConverterUtil.primitiveNull(type);            } else {                value = ConverterUtil.convert(type, requestValue);            }            methodParams.add(value);        }        //3.执行Controller外面对应的办法并返回后果        Object controller = beanContainer.getBean(controllerMethod.getControllerClass());        Method invokeMethod = controllerMethod.getInvokeMethod();        invokeMethod.setAccessible(true);        Object result;        try {            if (methodParams.size() == 0) {                result = invokeMethod.invoke(controller);            } else {                result = invokeMethod.invoke(controller, methodParams.toArray());            }        } catch (InvocationTargetException e) {            //如果是调用异样的话,须要通过e.getTargetException()            // 去获取执行办法抛出的异样            throw new RuntimeException(e.getTargetException());        } catch (IllegalAccessException e) {            throw new RuntimeException(e);        }        return result;    }}

5.2 ControllerRequestProcessor相干代码解说


6. ConverterUtil值转换工具类的补充


相干代码如下:

package com.wuyiccc.helloframework.util;/** * @author wuyiccc * @date 2020/7/15 8:02 * 岂曰无衣,与子同袍~ */public class ConverterUtil {    /**     * 返回根本数据类型的空值     * 须要非凡解决的根本类型即int\double\short\long\byte\float\boolean     *     * @param type 参数类型     * @return 对应的空值     */    public static Object primitiveNull(Class<?> type) {        if (type == int.class || type == double.class || type == short.class || type == long.class || type == byte.class || type == float.class) {            return 0;        } else if (type == boolean.class) {            return false;        }        return null;    }    /**     * String类型转换成对应的参数类型     *     * @param type         参数类型     * @param requestValue 值     * @return 转换后的Object     */    public static Object convert(Class<?> type, String requestValue) {        if (isPrimitive(type)) {            if (ValidationUtil.isEmpty(requestValue)) {                return primitiveNull(type);            }            if (type.equals(int.class) || type.equals(Integer.class)) {                return Integer.parseInt(requestValue);            } else if (type.equals(String.class)) {                return requestValue;            } else if (type.equals(Double.class) || type.equals(double.class)) {                return Double.parseDouble(requestValue);            } else if (type.equals(Float.class) || type.equals(float.class)) {                return Float.parseFloat(requestValue);            } else if (type.equals(Long.class) || type.equals(long.class)) {                return Long.parseLong(requestValue);            } else if (type.equals(Boolean.class) || type.equals(boolean.class)) {                return Boolean.parseBoolean(requestValue);            } else if (type.equals(Short.class) || type.equals(short.class)) {                return Short.parseShort(requestValue);            } else if (type.equals(Byte.class) || type.equals(byte.class)) {                return Byte.parseByte(requestValue);            }            return requestValue;        } else {            throw new RuntimeException("count not support non primitive type conversion yet");        }    }    /**     * 断定是否根本数据类型(包含包装类以及String)     *     * @param type 参数类型     * @return 是否为根本数据类型     */    private static boolean isPrimitive(Class<?> type) {        return type == boolean.class                || type == Boolean.class                || type == double.class                || type == Double.class                || type == float.class                || type == Float.class                || type == short.class                || type == Short.class                || type == int.class                || type == Integer.class                || type == long.class                || type == Long.class                || type == String.class                || type == byte.class                || type == Byte.class                || type == char.class                || type == Character.class;    }}

github地址:https://github.com/wuyiccc/he...