自定义MVC框架

1.Annocatioon

JDK5 之后,增加 Annotation 注解的基本语法,通过注解可以省略XML 的配置信息,简化代码的编写形式。
Annotation 中,如果想要自定义,可以通过如下语法:
@Target(ElementType.xxxx) 
@Retention(RetentionPolicy.xxxx) 
public @interface 注解名 {

 }
Target: 对应的是当前的注解能够定义在哪个位置上。
ElementType.Type -- 类
ElementType.Field -- 字段
ElementType.Method -- 方法
Retention: 在什么场景下能够起作用。
RetentionPolicy.CLASS - 定义类
RetentionPolicy.SOURCE - 编写代码
RetentionPolicy.RUNTIME -- 运行时
@Controller
package com.csi.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 { 

 }
@RequestMapping
package com.csi.annotation;

import java.lang.annotation.ElementType; 

import java.lang.annotation.Retention; 

import java.lang.annotation.RetentionPolicy; 

import java.lang.annotation.Target; 

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

String value() default "" ;

}

2.解析Annotation

扫描包的工具类

package com.csi.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;


/**
 * 找到某个包下的所有的以.class结尾的java文件
 */
public class ClassScanner {


    /**
     * 获得包下面的所有的class
     * @param
     * @return List包含所有class的实例
     */
    public static List<Class<?>> getClasssFromPackage(String packageName) {
        List<Class<?>> 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();
                }
            }
        }
    }
}

监听器:ClassLoaderContextListener

package com.csi.listener;

import com.csi.annotation.Controller;
import com.csi.annotation.RequestMapping;
import com.csi.utils.ClassScanner;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import java.lang.reflect.Method;
import java.util.List;

public class ClassLoaderContextListener implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        initClassLoader();
    }

    private void initClassLoader() {
        //根据包找到包下面所有的类
        List<Class<?>> classList = ClassScanner.getClasssFromPackage("com.csi.controller");

        //遍历所有的类
        for (Class<?> clazz : classList) {
            //如果当前类上存在Controller,就要获取方法
            if (clazz.isAnnotationPresent(Controller.class)) {
                //获得方法得名称
                Method[] methods = clazz.getMethods();

                //遍历当前包含了Controller注解得所有方法
                for (Method method : methods) {

                    //判断方法上是否添加了RequestMapping注解
                    if (method.isAnnotationPresent(RequestMapping.class)) {

                        //获取到包含了RequestMapping注解的value值
                        String urlPath = method.getAnnotation(RequestMapping.class).value();

                        //将值作为键,将方法作为值,存储在map集合中
                        WebApplicationContext.methodMap.put(urlPath, method);
                    }
                }
            }
        }
    }
}
解析用户的请求路径:
package com.csi.servlet;

import com.csi.listener.WebApplicationContext;

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

public class DispatcherServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //步骤1:获取到用户的请求URL
        String urlPath = req.getServletPath();

        Method method = WebApplicationContext.methodMap.get(urlPath);

        if (method != null) {
            //步骤2:调用对应的Method方法
            //2-1:如何找到要对应的类
            Object instance = null;
            try {
                instance = method.getDeclaringClass().newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            }

            try {
                method.invoke(instance, req, resp);
            } catch (IllegalAccessException e) {
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        } else {
            resp.sendRedirect("failure.jsp");
        }

    }
}

3.使用

3.1:需要在工程下建立com.csi.controller的包

3.2:在包中建立类,在该类上,添加@Controller的注解

3.3:建立类中的方法,根据需求,在适当的方法上添加@RequestMapping的注解.

4.pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.csi</groupId>
    <artifactId>shop</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>


        <dependency>
            <groupId>com.csi</groupId>
            <artifactId>MyMvcFrameWork</artifactId>
            <version>1.0-SNAPSHOT</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>

        <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>

        <dependency>
            <groupId>com.googlecode.json-simple</groupId>
            <artifactId>json-simple</artifactId>
            <version>1.1.1</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.tomcat.maven</groupId>
                <artifactId>tomcat7-maven-plugin</artifactId>
                <version>2.2</version>
                <configuration>
                    <port>8888</port>
                    <path>/</path>
                    <uriEncoding>UTF-8</uriEncoding>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

相关文章

学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习...
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面...
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生...
Can’t connect to local MySQL server through socket \'/v...
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 ...
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服...