SpringMVC框架

思路:

  1. 在项目部署的时候,就马上启动扫描的工作了。

    a. 把扫描的工作提前放到servlet的init方法去做: init --- service - destroy

    b. 让这个init方法调用的时机再提前一些,提前到项目发布的时候就执行。

    c. 设置 <load-on-startup> 1</load-on-startup>

  2. DispatcherServlet注册的时候,不要使用注解来注册了,而是使用xml来注册, 在xml里面注册的时候,就可以配置servlet的初始化参数,用户指定扫描具体那个包。 <init-param>

  3. 扫描得到包下的所有类了之后,不是每一个类我们都要查看它的所有方法有没有requestMapping这个注解

    1. 只看类上有没有一个注解@Controller , 这个注解是自定义的注解。

    2. 谁身上有这个注解,我们就解析这个类里面的所有方法。

  4. 在init方法里面完成扫描的工作之后,需要使用一个Map集合来进行映射关系,也就是完成扫描工作之后,使用一个map集合来包装 映射的地址和controller的对象。 map集合里面就包装了请求地址和调用方法的一个关系。 KEY : 请求地址 , value : 包装的javaBean。

    class MethodBean{

    private Method method; //具体的方法对象

    private Object obj; //调用这个方法要用的实例对象

    }

    Map<String , MethodBean> map ;

    MethodBean mb = new MethodBean(方法对象 , 类的实例对象);

    map.put("/user/register" , mb);

  5. 在请求来的时候,在service里面获取请求的地址

  6. 截获请求的地址了之后,就可以直接问map要方法来调用。

    MethodBean mb = map.get("/user/register");

    Method m = mb.getMethod();

    m.invoke(mb.getObj() , req , resp);

  7. 在用户请求到来之前执行扫描包的操作

//工具类

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


}
//servlet包


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.HashMap;
import java.util.List;
import java.util.Map;

public class DispatcherServlet extends HttpServlet {
    Map<String, MethodBean> map = new HashMap<>();

    @Override
    public void init(ServletConfig config) throws ServletException {
        try {
            //在用户请求到来之前便执行初始化扫描包的操作
            //获取需要初始化的包名
            String packageName = config.getInitParameter("packageName");

            //扫描得到的包下面的所以字节码
            //得到有个list集合,也就是包下所有类的集合
            List<Class<?>> classList = ClassScannerUtils.getClasssFromPackage(packageName);

            //遍历得到的集合
            for (Class<?> clazz : classList) {
                //判断这个集合里面的类是否有注解Controller
                if (clazz.isAnnotationPresent(Controller.class)) {
                    //有这个注解,那就获取这个注解下面的类中的所有方法得到一个方法数组
                    Method[] methods = clazz.getMethods();

                    //变量得到的方法数组,每遍历一次,获取方法上面的注解ResqustMapping
                    for (Method method : methods) {
                        ResqustMapping annotation = method.getAnnotation(ResqustMapping.class);

                        //判断这些方法上面的注解ResqustMapping是否为空
                        //不为空的话就获取注解中的值
                        if (annotation != null) {
                            String value = annotation.value();

                            //得到值后存储封装在map集合中
                            MethodBean methodBean = new MethodBean(method ,clazz.newInstance() );
                            map.put(value, methodBean);
                        }
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        try {
            //获取地址
            String uir = req.getRequestURI();

            //截取地址
            String path = uir.substring(0, uir.lastIndexOf("."));

            //用截取到的地址去map集合中找对象
            //那就得创建map集合对象
            MethodBean methodBean = map.get(path);

            //判断有没有执行到方法
            if (methodBean != null) {
                //不为空,执行到了,便获取参数
                Method method = methodBean.getMethod();
                Object object = methodBean.getObject();

                //调用方法
                method.invoke(object , req , resp);
            }else {
                System.out.println("没有找到方法......"+path);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}
//controller  需要扫描的包

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Controller
public class UserController {

    @ResqustMapping("/user/register")
    public void register(HttpServletRequest  req, HttpServletResponse resp){
        System.out.println("调用了UserControllor的用户注册......register");
    }


    @ResqustMapping("/user/login")
    public void login(HttpServletRequest  req, HttpServletResponse resp){
        System.out.println("调用了UserControllor的用户登录......login");
    }
}
//bean 包

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;

import java.lang.reflect.Method;

@Data
@AllArgsConstructor//有参
@NoArgsConstructor//无参
@ToString
public class MethodBean {
    private Method method;
    private Object object;
}
//定义注解的包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 ResqustMapping {
    String value();

}
//定义注解的包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 {

}
<!--相关依赖  pom.xml-->

<dependencies>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.18.16</version>
    </dependency>
  </dependencies>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
  </properties>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.tomcat.maven</groupId>
        <artifactId>tomcat7-maven-plugin</artifactId>
        <version>2.2</version>
        <configuration>
          <!-- 指定端口 -->
          <port>82</port>
          <!-- 请求路径 -->
          <path>/</path>
        </configuration>
      </plugin>
    </plugins>
  </build>
<!--web.xml文件中定义需要扫描包的操作,初始化-->

	<!--注册DispatcherServlet-->
	<servlet>
		<servlet-name>dispatcher</servlet-name>
		<servlet-class>servlet/DispatcherServlet</servlet-class>

		<!--告诉DispatcherServlet要扫描的包是哪个-->
		<init-param>
			<param-name>packageName</param-name>
			<param-value>controller</param-value>
		</init-param>


		<!--让DispatcherServlet在项目发布的时候,就进行初始化,执行init方法-->
		<load-on-startup>1</load-on-startup>
	</servlet>

	<servlet-mapping>
		<servlet-name>dispatcher</servlet-name>
		<url-pattern>*.do</url-pattern>
	</servlet-mapping>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值