自定义mvc

前端:
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();
                }
            }
        }
    }


}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值