欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

自定义mvc

程序员文章站 2022-07-08 10:38:33
...

前端:
1.请求服务器路径:/user/login和/user/register
2.servlet的作用在于根据路径引导请求去访问Control中的哪个方法
3.执行controller包中的众多的Control类的方法。

<a href="user/login.do">访问login</a>
<hr>
<a href="user/register.do">访问register</a>

配置web.xml:
作用:
1.配置前端访问servlet的路径
2.配置要扫描Controller包的的位置

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<!--配置前端访问的servlet位置-->
	<servlet>
		<servlet-name>DispatcherServlet</servlet-name>
		<servlet-class>mm.dispatcherServlet1</servlet-class>
		<init-param>
			<!--在配置文件里写信息,servlet在init方法读取信息读取-->
			<param-name>scanPackage</param-name>
			<!--扫面所有controller文件夹下的包-->
			<param-value>mm.controller</param-value>
		</init-param>
		<!--启动即加载-->
		<load-on-startup>1</load-on-startup>
	</servlet>
	<servlet-mapping>
		<servlet-name>DispatcherServlet</servlet-name>
		<url-pattern>*.do</url-pattern>
		<!--指定以do结尾的都会去这个servlet-->
	</servlet-mapping>
</web-app>

自定义注解:
1.Controller:标记类

package mm.annotation;

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

/**
 * @Author:ZZZ
 * @Date: 2020/12/15 16:29
 * @Version 1.0
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
    String value();
}

2.RequestMapping:标记方法

	package mm.annotation;

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

/**
 * @Author:ZZZ
 * @Date: 2020/12/15 16:29
 * @Version 1.0
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
    String value();
}

封装一个JavaBean用来存储Controller类里的信息:
1.Controller类的Class对象
2.方法的Class对象
3.方法上的注解值

package mm.bean;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.lang.reflect.Method;

/**
 * @Author:ZZZ
 * @Date: 2020/12/15 17:08
 * @Version 1.0
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
//序列化就可以将对象钝化(session)到硬盘用缓存
public class frameWorkBean implements Serializable {
    Method method;//control类的方法
    Object object;//该类对象
    String annotation_Name;//该方法上的注解名
}

servlet类:分配方法

package mm;

import lombok.SneakyThrows;
import mm.annotation.Controller;
import mm.annotation.RequestMapping;
import mm.bean.frameWorkBean;
import mm.utils.ClassScannerUtils;

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.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * @Author:ZZZ
 * @Date: 2020/12/15 16:20
 * @Version 1.0
 */

public class dispatcherServlet1 extends HttpServlet {
    //存储方法上的注解值
    //List<String> method_Anno_list = new ArrayList<>();
    frameWorkBean fwb=null;
    List<frameWorkBean> frameWorkBeanList=new ArrayList<>();
    //    读取配置文件
//    初始化作用:扫描所有的control包
    //带control的类就初始化对象,对象中的带requestMapping的方法就存储,即将包下的所有的带有requestMapping注解的方法的注解值存储到变量里
    //匹配了uri与注解相匹配后,要用反射执行该方法,这时候需要用该control类对象和方法的参数 ,
    // 1,方法对象,2该control类对象,3注解名 这三个成员。1.用注解名和uri比较,2.用方法对象和control类对象:执行该方法的类对象
    //只拿注解值可肯定没用,还要

    @SneakyThrows //处理异常注解
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init();
//        获取扫描的controller包的位置,已经在web.xml配置好
        String scanPackage = config.getInitParameter("scanPackage");//com.alibaba.controller
        //用utils扫描包下的所有类,拿到包下所有的类的字节码文件
        List<Class<?>> listClazz = ClassScannerUtils.getClasssFromPackage(scanPackage);
        //遍历所有的类字节码对象,先不为空
        if (listClazz != null) {
            for (Class<?> clazz : listClazz) {
                //每一个类的Class对象
                //判断Class上是否带Controller注解
                if (clazz.isAnnotationPresent(Controller.class)) {
                    //如果有Contoller则创建该类的对象
                    Object obj = clazz.newInstance();
                    //获得该类里的所有public方法
                    Method[] listMethods = clazz.getDeclaredMethods();
                    //方法不为空
                    if (listMethods != null) {
//                       遍历
                        for (Method method : listMethods) {
                            //看方法上注解名是否是RequestMapping注解
                            if (method.isAnnotationPresent(RequestMapping.class)) {
                                //如果是RequestMapping注解
                                fwb=new frameWorkBean();
                                //得到注解的值并存储到成员变量里,在get方法里进行比较
                                //获取方法上的注解value
                                String requestMapping_value = method.getAnnotation(RequestMapping.class).value();
                                fwb.setObject(obj);//设置类对象
                                fwb.setMethod(method);//设置该方法
                                fwb.setAnnotation_Name(requestMapping_value);//设置注解名
//                                存入bean对象(controller对象,controller类的带@RequestMapping方法,@RequestMapping的值)
                                frameWorkBeanList.add(fwb);
                            }
                        }
                    }
                }
            }
        }
    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }

    @SneakyThrows
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //获取前端传来的url,带有项目名如:/user/login.do
        String uri = request.getRequestURI();
        String contextPath = request.getContextPath();//项目名
//解析
        String reqUri = uri.substring(contextPath.length(), uri.lastIndexOf("."));// /user/login
//存储bean的list不为空
        if(frameWorkBeanList!=null) {
            for (frameWorkBean frameWorkBean : frameWorkBeanList) {
            //得到每一组bean
                //比较bean里的注解名和请求的路径比较相等则执行bean组合里的方法
                if (frameWorkBean.getAnnotation_Name().equals(reqUri)) {
                    //Method.invoke(Object,Object...)
                    Method method = frameWorkBean.getMethod();
                    method.invoke(frameWorkBean.getObject(),request,response);
                    return;
                }
            }
        }
    }
}

UserController:
1.类上配置@Controller注解(类上注解作用表示要servlet会拿的类)
2.方法上配置@RequestMapping注解(方法上的注解表示servlet会拿的方法)

package mm.controller;

import mm.annotation.Controller;
import mm.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @Author:ZZZ
 * @Date: 2020/12/15 15:55
 * @Version 1.0
 */
@Controller("UserController")
public class UserController {
    @RequestMapping("/user/login")
    public void login(HttpServletRequest request , HttpServletResponse response) throws IOException {
        response.getWriter().write("login_hello");
    }

    @RequestMapping("/user/register")
    public void register(HttpServletRequest request , HttpServletResponse response) throws IOException {
        response.getWriter().write("register_world");
    }
}

ClassScannerUtils :扫描包下所有类:

package mm.utils;

import java.io.File;
import java.io.FileFilter;
import java.net.URL;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;

/**
 * @Description:扫描包下的类
 * @Author: yp
 */
public class ClassScannerUtils {

    /**
     * 获得包下面的所有的class
     * @param
     * @return List包含所有class的实例
     */
    public static List<Class<?>> getClasssFromPackage(String packageName) {
        List clazzs = new ArrayList<>();
        // 是否循环搜索子包
        boolean recursive = true;
        // 包名对应的路径名称
        String packageDirName = packageName.replace('.', '/');
        Enumeration<URL> dirs;

        try {
            dirs = Thread.currentThread().getContextClassLoader().getResources(packageDirName);
            while (dirs.hasMoreElements()) {

                URL url = dirs.nextElement();
                String protocol = url.getProtocol();
                if ("file".equals(protocol)) {
                    String filePath = URLDecoder.decode(url.getFile(), "UTF-8");
                    findClassInPackageByFile(packageName, filePath, recursive, clazzs);
                }
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return clazzs;
    }

    /**
     * 在package对应的路径下找到所有的class
     */
    public static void findClassInPackageByFile(String packageName, String filePath, final boolean recursive,
                                                List<Class<?>> clazzs) {
        File dir = new File(filePath);
        if (!dir.exists() || !dir.isDirectory()) {
            return;
        }
        // 在给定的目录下找到所有的文件,并且进行条件过滤
        File[] dirFiles = dir.listFiles(new FileFilter() {

            public boolean accept(File file) {
                boolean acceptDir = recursive && file.isDirectory();// 接受dir目录
                boolean acceptClass = file.getName().endsWith("class");// 接受class文件
                return acceptDir || acceptClass;
            }
        });

        for (File file : dirFiles) {
            if (file.isDirectory()) {
                findClassInPackageByFile(packageName + "." + file.getName(), file.getAbsolutePath(), recursive, clazzs);
            } else {
                String className = file.getName().substring(0, file.getName().length() - 6);
                try {
                    clazzs.add(Thread.currentThread().getContextClassLoader().loadClass(packageName + "." + className));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
    }


}

相关标签: java servlet mvc