Handwriting an MVC framework

Handwriting an MVC framework

We write all the methods in one class, so that we don’t need many servlets

Insert picture description here

First, we need a Servlet to receive all request addresses ending with *.do

We are in the initialization method inti

1. Load the configuration file

2. Establish a pool of mapped addresses

Go to the mapper from the servlet to find the corresponding address, get the corresponding method, get the result of the method put back, and return the result to the user

servlet -> mapper -> call method -> put the result back to the user

Write Servlet

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>DispatcherServlet</servlet-name>
        <servlet-class>
            com.lqh.mvc.DispatcherServlet
        </servlet-class>
        <init-param>
            <param-name>contentConfigLocation</param-name>
            <param-value>application.properties</param-value>
        </init-param>
        <load-on-startup>0</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>
</web-app>

DispatcherServlet


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.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class DispatcherServlet extends HttpServlet {
    
    
    @Override
    public void init(ServletConfig config) throws ServletException {
    
    
        String path = config.getInitParameter("contentConfigLocation");
        InputStream is = DispatcherServlet.class.getClassLoader().getResourceAsStream(path);
        HandlerMapping.load(is);
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    
        // 1.   获取用户请求的uri
        String uri = req.getRequestURI();
        HandlerMapping.MVCMapping mapping = HandlerMapping.get(uri);
        if(mapping == null){
    
    
            resp.sendError(404,"自定义MVC:映射地址不存在"+uri);
            return;
        }
        Object obj = mapping.getObj();
        Method method = mapping.getMethod();
        Object result = null;
        try {
    
    
            result = method.invoke(obj, req, resp);
        } catch (IllegalAccessException e) {
    
    
            e.printStackTrace();
        } catch (InvocationTargetException e) {
    
    
            e.printStackTrace();
        }
        switch(mapping.getResponseType()){
    
    
            case TEXT:
                resp.getWriter().write((String)result);
                break;
            case VIEW:
                resp.sendRedirect((String)result);
                break;

        }

    }

}

Configuration file application.properties

#用于管理员的controller
admin=com.lqh.controller.AdminController
#用于快递管理的controller
express=com.lqh.controller.ExpressController
#用于快递员管理的controller
courier=com.lqh.controller.CourierController
#用于用户管理的controller
user=com.lqh.controller.UserController

Write annotations

ResponseBody

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
 * 注解作用:
 *  被此注解添加的方法,会被用于处理请求
 *  方法返回的内容,会以文字形式返回到客户端
 */
public @interface ResponseBody {
    
    
    String value();

}

ResponseView


@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**
 * 注解作用:
 *  被此注解添加的方法,会被用于处理请求
 *  方法返回的内容,会直接重定向
 */
public @interface ResponseView {
    
    
    String value();

}

Write an enumeration to describe the type of response

ResponseType

public enum ResponseType {
    
    
    TEXT,VIEW;
}

Write a mapper

HandlerMapping

package com.lqh.mvc;

import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 映射器(包含大量的网址与方法的对应关系)
 */
public class HandlerMapping {
    
    
    private static Map<String,MVCMapping> data = new HashMap<>();

    public static MVCMapping get(String uri){
    
    
        return data.get(uri);
    }

    public static void load(InputStream is){
    
    
        Properties ppt = new Properties();
        try {
    
    
            ppt.load(is);
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        //获取配置文件中描述的一个个的类
        Collection<Object> values = ppt.values();
        for (Object cla:values) {
    
    
            String className = (String) cla;
            try {
    
    
                //加载配置文件中描述的每一个类
                Class c  = Class.forName(className);
                //创建这个类的对象
                Object obj = c.getConstructor().newInstance();
                //获得这个类的所有方法
                Method[] methods = c.getMethods();
                for(Method m:methods){
    
    
                    Annotation[] as = m.getAnnotations();
                    if(as != null){
    
    
                        for(Annotation annotation:as){
    
    
                            if(annotation instanceof ResponseBody){
    
    
                                //说明此方法用于返回字符串给客户端
                                MVCMapping mapping = new MVCMapping(obj,m,ResponseType.TEXT);
                                Object o = data.put(((ResponseBody) annotation).value(),mapping);
                                if(o != null){
    
    
                                    //说明存在了重复的请求地址
                                    throw  new RuntimeException("请求地址重复"+((ResponseBody) annotation).value());
                                }

                            }else if(annotation instanceof ResponseView){
    
    
                                //说明此方法用于返回界面给客户端
                                MVCMapping mapping = new MVCMapping(obj,m,ResponseType.VIEW);
                                Object o =data.put(((ResponseView) annotation).value(),mapping);
                                if(o != null){
    
    
                                    //说明存在了重复的请求地址
                                    throw  new RuntimeException("请求地址重复"+((ResponseView) annotation).value());
                                }
                            }
                        }
                    }
                }
            } catch (Exception e) {
    
    
                e.printStackTrace();
            }
        }
    }

    /**
     * 映射器
     * 映射对象,每一个对象封装了一个方法,用于请求处理
     */
    public static class MVCMapping{
    
    
        private Object obj;
        private Method method;
        private ResponseType responseType;

        public MVCMapping() {
    
    
        }

        public MVCMapping(Object obj, Method method, ResponseType responseType) {
    
    
            this.obj = obj;
            this.method = method;
            this.responseType = responseType;
        }

        public Object getObj() {
    
    
            return obj;
        }

        public void setObj(Object obj) {
    
    
            this.obj = obj;
        }

        public Method getMethod() {
    
    
            return method;
        }

        public void setMethod(Method method) {
    
    
            this.method = method;
        }

        public ResponseType getResponseType() {
    
    
            return responseType;
        }

        public void setResponseType(ResponseType responseType) {
    
    
            this.responseType = responseType;
        }
    }
}

{
this.method = method;
}

    public ResponseType getResponseType() {
        return responseType;
    }

    public void setResponseType(ResponseType responseType) {
        this.responseType = responseType;
    }
}

}


Guess you like

Origin blog.csdn.net/weixin_43515837/article/details/112733031