手写简易MVC

最近看了几篇手写关于SpringMVC的文章,自己试了一下

先写俩注解Controller和Requesting

package com.my_mvc.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// 注解运行的位置
@Target(ElementType.TYPE)  
// 生命周期, 在运行时加载在内存
@Retention(RetentionPolicy.RUNTIME)  
public @interface Controller {


}
package com.my_mvc.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {

    public String value();

}

扫描包的工具类

package com.my_mvc.util;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: YANG_ZG
 * @Date: 2018/9/8 9:36
 * @Description: 用来扫描包下面的类
 */
public class ClassScanner {

    /**
     * 扫描某个包下所有的类
     * @return Map<String, Class<?>>  Map<类名, 类的class实例>
     */
    public static Map<String, Class<?>> scannerScanner(String basePackge) {
        Map<String, Class<?>> results = new HashMap<>();
        // 把包名的.替换为/
        String filePath = basePackge.replace(".","/");
        // 通过类加载器获得完整路径
        Enumeration<URL> dirs = null;
        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(filePath);
        } catch (IOException e) {
            e.printStackTrace();
        }
        // rootPath 真实的磁盘路径,.class文件的路径  /D:/IDEAWorkspaces/SpringMVC_myself/out/production/SpringMVC_myself/com/my_mvc/util
        String rootPath = Thread.currentThread().getContextClassLoader().getResource(filePath).getPath();
        // 取出路径多余的部分/D:/IDEAWorkspaces/SpringMVC_myself/out/production/SpringMVC_myself/
        if (rootPath != null){
            int i = rootPath.lastIndexOf(filePath);
            // rootPath = rootPath.substring(i) + "/";
            // 在Tomcat部署时候不需要  + "/"
            rootPath = rootPath.substring(i);
        }
        while (dirs.hasMoreElements()){
            URL url = dirs.nextElement();
            // 根据url判断是否是文件对象
            if (url.getProtocol().equals("file")){
                File file = new File(url.getPath().substring(1));
                scannerScanner(file, rootPath, results);
            }
        }
        return results;
    }

    private static void scannerScanner(File folder, String rootPath, Map<String, Class<?>> classes){
        // 拿到folder的所有文件对象
        // 文件夹里为空,listFiles()返回为空
        File[] files = folder.listFiles();
        for (int i = 0; files != null && i < files.length; i++ ){
            File file = files[i];
            // 判断是否继续是个是文件夹,是文件夹继续递归
            if (file.isDirectory()){
                String tempPath = rootPath + file.getName() + "/";
                scannerScanner(file, tempPath, classes);
            }else {
                String path = file.getAbsolutePath(); // 真实路径
                if (path.endsWith(".class")){
                    // 将路径中的 \ 替换为 /
                    path = path.replace("\\", "/");
                    // 完整的路径
                    String className = rootPath + path.substring(path.lastIndexOf("/") + 1, path.indexOf(".class"));
                    className = className.replace("/", ".");
                    // System.out.println(className);
                    try {
                        classes.put(className, Class.forName(className));
                    } catch (ClassNotFoundException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        scannerScanner("com.my_mvc.util");
    }
}

controller 抽象父类

package com.my_mvc.util;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @Auther: YANG_ZG
 * @Date: 2018/9/8 11:26
 * @Description: 所有的 controller 抽象父类
 */

public abstract class BaseController {
	
	protected HttpServletRequest request;
	protected HttpServletResponse response;
	
	
	
	public void init(HttpServletRequest request, HttpServletResponse response) {
		this.request = request;
		this.response = response;
	}
	public HttpServletRequest getRequest() {
		return request;
	}
	public void setRequest(HttpServletRequest request) {
		this.request = request;
	}
	public HttpServletResponse getResponse() {
		return response;
	}
	public void setResponse(HttpServletResponse response) {
		this.response = response;
	}
	
}

DispatcherServlet

package com.my_mvc.servlet;

import com.my_mvc.annotation.Controller;
import com.my_mvc.annotation.RequestMapping;
import com.my_mvc.util.BaseController;
import com.my_mvc.util.ClassScanner;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * @Auther: YANG_ZG
 * @Date: 2018/9/8 16:41
 * @Description: DispatcherServlet
 */
@WebServlet(urlPatterns={"*.do"}, initParams = {@WebInitParam(name = "basePackage", value = "com.my_mvc")})
public class DispatcherServlet extends HttpServlet {

	private static final long serialVersionUID = -3752494172091060171L;
	
	// 存储controller实例,此写法单例。。。。。多例可以= null, 调用每次new 一个出来
    private Map<String, Object> controllers = new HashMap<>();
    // 反射调用的method
    private Map<String, Method> methods = new HashMap<>();

    
    @SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("================================");
        // 在实际中,在xml中获得参数,,,现在@WebServlet 注解中先写死
        String basePackage = config.getInitParameter("basePackage");
        // 获得 包下 Map<类名, 类的class实例>
        Map<String, Class<?>> classMap = ClassScanner.scannerScanner(basePackage);
        Iterator<String> iterator = classMap.keySet().iterator();
        while (iterator.hasNext()){
            String className = iterator.next();
            Class clazz = classMap.get(className);
            String path = "";
            // 判断类是否存在Controller注解
            if(clazz.isAnnotationPresent(Controller.class)){
                System.out.println(clazz.getName() + "  是controller控制类。。。");
                // 管理类
                // 判断类是否被RequestMapping修饰
                if (clazz.isAnnotationPresent(RequestMapping.class)){
                    // 取出注解值
                    RequestMapping rm = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
                    path = rm.value();
                }
                try {
                    // 单例可以直接 clazz.newInstance(), 如果是多例不再这里new,value只存一个class,
                    controllers.put(className, clazz.newInstance());
                } catch (Exception e) {}

                // 得到类中的所有方法
                Method[] ms = clazz.getMethods();
                for (Method method : ms) {
                    // 看方法是否存在RequestMapping注解,没有跳过
                    if (!method.isAnnotationPresent(RequestMapping.class)){
                        continue;
                    }
                    // System.out.println(method.getName() + " 方法的映射的对外路径为:" + path + method.getAnnotation(RequestMapping.class).value());
                    methods.put(path + method.getAnnotation(RequestMapping.class).value(), method);
                }
            }
        }
    }
    
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    	String requestURI = req.getRequestURI();
    	String contextPath = req.getContextPath();
    	
    	int beginIndex = requestURI.indexOf(contextPath) + contextPath.length();
		int endIndex= requestURI.indexOf(".do");
		String mappingPath = requestURI.substring(beginIndex, endIndex);
		
		Method method = methods.get(mappingPath);
		// method.getDeclaringClass() 得到这个方法类的实例
		// 单例写法  Object controller =  controllers.get(method.getDeclaringClass().getName());
		BaseController controller;
		try {
			controller = (BaseController) method.getDeclaringClass().newInstance();
			controller = null;
			controller = (BaseController) controllers.get(method.getDeclaringClass().getName());
			// 这样可以在controller方法里使用request,response
			controller.init(req, resp);
			
			if (controller != null) {
					method.invoke(controller);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
    }
}

测试Controller类

package com.my_mvc;

import javax.servlet.http.HttpSession;

import com.my_mvc.annotation.Controller;
import com.my_mvc.annotation.RequestMapping;
import com.my_mvc.util.BaseController;

/**
 * @author: YANG_ZG
 * @date: 2018/9/8 17:49
 * @Description: test
 */
@Controller
@RequestMapping("/test")
public class TestController extends BaseController{

    @RequestMapping("/login")
    public void login(){
        System.out.println("test/login==================");
    }

    @RequestMapping("/add")
    public void add(){
        System.out.println("test/add==================");
        System.out.println(request.getAttribute("msg"));
    }

    @RequestMapping("/delete")
    public void delete(){
        System.out.println("test/delete==================");
    }

    public void pp(){
    }
}

把项目加载进tomcat服务器中启动http://localhost:8080/SpringMVC_myself/test/login.do

猜你喜欢

转载自blog.csdn.net/Yang_g_/article/details/82531994
今日推荐