手写SpringMVC框架

来源:互联网 发布:let it go 英文歌词 编辑:程序博客网 时间:2024/05/16 06:45

springmvc在项目中的作用

  1. 处理请求,把请求分发到不同的类和方法中
  2. ioc 依赖注入,创建实例。配置的方式和annotation的方式,今天实现annotation的方式
  3. aop 动态代理,事物控制,让程序员只专注于写自己的业务代码

步骤

  1. 定义包结构

    com.annotationcom.controllercom.servicecom.service.implcom.servlet
  2. 自定义注解

    元注解的作用就是负责注解其他注解    1.@Target, :作用目标,作用在方法上、变量上、还是类上    2.@Retention,用于描述注解的生命周期:        SOURCE:在源文件中有效       CLASS:在class文件中有效       RUNTIME:在运行时有效    3.@Documented,javadoc此类的工具文档化自定义4个注解:Controller,Service,RequestMapping,Qualifier注解就是存储信息的,跟xml功能差不多,存储了信息后,程序读到注解上面的信息做相应的操作

    3、包扫描

    包扫描的目的根据basepackage,就是基包(代码中指的是com),扫描下面的子包以及子包下的类拿到包下的所有类文件后,我们就可以得到文件名有包名有文件名,我们就可以通过反射new出这些类的实例目的就是扫描基包下的所有的类文件,根据文件获取类的完整类名:包名+类名通过文件的方式去扫描

    4、把所有的类new出实例后,我们就要把类中的依赖关系注入进去

    拿到类的Class对象拿到field对象拿到field上面的annotation对象根据annotation对象拿annotation对象的属性把属性当key拿到map中的实例然后field。set把实例设置进去

    5、建立一个url与类中方法的映射关系

    其实是同样的做法拿到类的Class对象拿到Method对象拿到Method上面的annotation对象把url和method对象存到map中

代码

自定义注解

package com.annotation;import java.lang.annotation.Documented;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)@Documented // 可以不写 用来文档打包的public @interface Controller {    String value() default "";}package com.annotation;import java.lang.annotation.Documented;import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target;@Target({ ElementType.FIELD }) // 注解在字段上@Retention(RetentionPolicy.RUNTIME)@Documented // 可以不写 用来文档打包的public @interface Qualifier {    String value() default "";}package com.annotation;import java.lang.annotation.Documented;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)@Documented // 可以不写 用来文档打包的public @interface ResquestMapping {    String value() default "";}package com.annotation;import java.lang.annotation.Documented;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)@Documented // 可以不写 用来文档打包的public @interface Service {    String value() default "";}

包扫描 IOC 和 handlerMapping

package com.servlet;import java.io.File;import java.io.IOException;import java.lang.reflect.Field;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.net.URL;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Map.Entry;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.annotation.Controller;import com.annotation.Qualifier;import com.annotation.ResquestMapping;import com.annotation.Service;public class DispatcherServlet extends HttpServlet {    private static final long serialVersionUID = 1L;    // 定义基包下的文件的全限定名集合    List<String> packageNames = new ArrayList<>();    // 定义实例化对象的map key为注解的value value为类的实例    Map<String, Object> instanceMap = new HashMap<>();    // 定义路径与方法映射集合    Map<String, Object> handlerMap = new HashMap<>();    @Override    public void init() throws ServletException {        /* 包扫描 */        // 根据basepackage,就是基包(代码中指的是com),扫描下面的子包以及子包下的类        // 拿到包下的所有类文件后,我们就可以得到文件名        // 有包名有文件名,我们就可以通过反射new出这些类的实例        // 目的就是扫描基包下的所有的类文件,根据文件获取类的完整类名:包名+类名        // 通过文件的方式去扫描        System.out.println(this.getClass().getClassLoader().getResource("/"));// null        System.out.println(this.getClass().getClassLoader().getResource(""));// file:/D:/Users/workspace-sts-3.7.1.RELEASE/SpringMVC/target/classes/        System.out.println(this.getClass().getClassLoader().getResource("com"));// file:/D:/Users/workspace-sts-3.7.1.RELEASE/SpringMVC/target/classes/com        System.out.println(DispatcherServlet.class.getClassLoader().getResource("/com"));// null        scanPackage("com");// spring中 是在xml中配置的        try {            // 拿到类的Class对象            filterAndInstance();            // 依赖注入            // 拿到field对象            // 拿到field上面的annotation对象            // 根据annotation对象拿annotation对象的属性            // 把属性当key拿到map中的实例            // 然后field。set把实例设置进去            ioc();            // 建立路径方法映射            handlerMap();            // 打印实例化对象的map            for (Entry<String, Object> entry : instanceMap.entrySet()) {                System.out.println(entry.getKey() + ":" + entry.getValue());            }            // 打印路径与方法映射集合map            for (Entry<String, Object> entry : handlerMap.entrySet()) {                System.out.println(entry.getKey() + ":" + entry.getValue());            }        } catch (Exception e) {            e.printStackTrace();        }    }    /**     * @Title: ioc     * @Description: 路径方法映射     */    private void handlerMap() {        if (instanceMap.isEmpty()) {            return;        }        // 遍历 实例集合 取得方法 包含 RequestMapping 注解        for (Entry<String, Object> entry : instanceMap.entrySet()) {            if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) {                Controller controllerAn = entry.getValue().getClass().getAnnotation(Controller.class);                String ctvalue = controllerAn.value();                Method[] methods = entry.getValue().getClass().getMethods();                for (Method method : methods) {                    if (method.isAnnotationPresent(ResquestMapping.class)) {                        ResquestMapping annotation = method.getAnnotation(ResquestMapping.class);                        String rmvalue = annotation.value();                        handlerMap.put("/" + ctvalue + "/" + rmvalue, method);                    }                }            }        }    }    /**     * @Title: ioc     * @Description: 属性依赖注入     */    private void ioc() throws IllegalArgumentException, IllegalAccessException {        // 如果 map 为空 说明没有实例化对象 返回        if (instanceMap.isEmpty()) {            return;        }        // 遍历 实例集合        for (Entry<String, Object> entry : instanceMap.entrySet()) {            if (entry.getValue().getClass().isAnnotationPresent(Controller.class)) {                // 获取 当前实例的字段                Field[] fields = entry.getValue().getClass().getDeclaredFields();                for (Field field : fields) {                    field.setAccessible(true);                    // 如果包含指定注解 那么通过该注解的 value 向正在遍历的实例化对象中注入 指定对象                    if (field.isAnnotationPresent(Qualifier.class)) {                        Qualifier annotation = field.getAnnotation(Qualifier.class);                        String value = annotation.value();                        field.set(entry.getValue(), instanceMap.get(value));                    }                }            }        }    }    /**     * @Title: filterAndInstance     * @Description: 定义过滤方法 添加需要实例化的类到instanceMap     */    private void filterAndInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException {        if (packageNames.isEmpty()) {            return;        }        for (String className : packageNames) {            // 反射 获取对象 className去掉.class            Class<?> clazz = Class.forName(className.replace(".class", ""));            // 根据注解判断是否需要实例化            if (clazz.isAnnotationPresent(Controller.class)) {                Object instance = clazz.newInstance();                Controller annotation = clazz.getAnnotation(Controller.class);                String key = annotation.value();                instanceMap.put(key, instance);            } else if (clazz.isAnnotationPresent(Service.class)) {                Object instance = clazz.newInstance();                Service annotation = clazz.getAnnotation(Service.class);                String key = annotation.value();                instanceMap.put(key, instance);            }        }    }    /**     * @Title: scanPackage     * @Description: 定义包扫描方法     */    private void scanPackage(String basepackage) {        // 将基包中的.转换为/ 才能遍历其下的文件        URL url = this.getClass().getClassLoader().getResource(replaceTo(basepackage));        String pathFile = url.getFile();// 得到绝对路径的字符串        File file = new File(pathFile);        String[] files = file.list();        for (String path : files) {            File eachFile = new File(pathFile + "/" + path);            if (eachFile.isDirectory()) {                // 递归迭代                scanPackage(basepackage + "." + eachFile.getName());            } else {                // 是文件 添加其全类名                // 返回 com.xxx.class                System.out.println("初始加载基包下的所有文件: " + basepackage + "." + eachFile.getName());                packageNames.add(basepackage + "." + eachFile.getName());            }        }    }    /**     * @Title: replaceTo     * @Description: 将路径中的 "." 转换为 "/"     */    private String replaceTo(String path) {        return path.replaceAll("\\.", "/");    }    @Override    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        doPost(req, resp);    }    @Override    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {        String uri = req.getRequestURI();        // 获取工程名字        String contextPath = req.getContextPath();        // 截取uri 去掉工程名字 /index/insert        String path = uri.replace(contextPath, "");        Method method = (Method) handlerMap.get(path);        try {            // path.split("/")=["",index,insert]            method.invoke(instanceMap.get(path.split("/")[1]), new Object[] { req, resp, null });        } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {            e.printStackTrace();        }    }}

controller 和 service

package com.controller;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import com.annotation.Controller;import com.annotation.Qualifier;import com.annotation.ResquestMapping;import com.service.IndexService;import com.service.MyService;//设计这里的index 也是相当于springMVC中RequestMapping的作用@Controller("index")public class IndexController {    @Qualifier("myServiceImpl")    private MyService myService;    @Qualifier("indexServiceImpl")    private IndexService indexService;    @ResquestMapping("insert") // 不能带有"/" 设计不带    public String insert(HttpServletRequest request, //            HttpServletResponse response, //            String param) {        // URL: http://localhost:8080/SpringMVC/index/update        // URI: /SpringMVC/index/update        System.err.println("URL: " + request.getRequestURL());        System.err.println("URI: " + request.getRequestURI());        myService.insert();        indexService.insert();        return null;    }    @ResquestMapping("delete") // 不能带有"/" 设计不带    public String delete(HttpServletRequest request, //            HttpServletResponse response, //            String param) {        System.err.println("URL: " + request.getRequestURL());        System.err.println("URI: " + request.getRequestURI());        myService.delete();        indexService.delete();        return null;    }    @ResquestMapping("update") // 不能带有"/" 设计不带    public String update(HttpServletRequest request, //            HttpServletResponse response, //            String param) {        System.err.println("URL: " + request.getRequestURL());        System.err.println("URI: " + request.getRequestURI());        myService.update();        indexService.update();        return null;    }    @ResquestMapping("select") // 不能带有"/" 设计不带    public String select(HttpServletRequest request, //            HttpServletResponse response, //            String param) {        System.err.println("URL: " + request.getRequestURL());        System.err.println("URI: " + request.getRequestURI());        myService.select();        indexService.select();        return null;    }}
package com.service;public interface IndexService {    int insert();    int delete();    int update();    int select();}package com.service;public interface MyService {    int insert();    int delete();    int update();    int select();}
package com.service.impl;import com.annotation.Service;import com.service.IndexService;@Service("indexServiceImpl")public class IndexServiceImpl implements IndexService {    @Override    public int insert() {        System.out.println("IndexServiceImpl的insert");        return 0;    }    @Override    public int delete() {        System.out.println("IndexServiceImpl的delete");        return 0;    }    @Override    public int update() {        System.out.println("IndexServiceImpl的update");        return 0;    }    @Override    public int select() {        System.out.println("IndexServiceImpl的select");        return 0;    }}package com.service.impl;import com.annotation.Service;import com.service.MyService;@Service("myServiceImpl")public class MyServiceImpl implements MyService {    @Override    public int insert() {        System.out.println("MyServiceImpl的insert");        return 0;    }    @Override    public int delete() {        System.out.println("MyServiceImpl的delete");        return 0;    }    @Override    public int update() {        System.out.println("MyServiceImpl的update");        return 0;    }    @Override    public int select() {        System.out.println("MyServiceImpl的select");        return 0;    }}

web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee     http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">    <welcome-file-list>        <welcome-file>index.jsp</welcome-file>    </welcome-file-list>    <!-- 自定义前端控制器 -->    <servlet>        <servlet-name>springmvc</servlet-name>        <servlet-class>com.servlet.DispatcherServlet</servlet-class>        <load-on-startup>1</load-on-startup>    </servlet>    <servlet-mapping>        <servlet-name>springmvc</servlet-name>        <!-- 1:*.do *.action 拦截以.do结尾的请求 (不拦截 jsp png jpg .js .css) 2:/ 拦截所有请求 (不拦截.jsp) 建议使用此种 方式 (拦截 .js.css .png) (放行静态资源) 3:/* 拦截所有请求(包括.jsp) 此种方式 不建议使用 -->        <url-pattern>/*</url-pattern>    </servlet-mapping></web-app>

OK 大功告成!!!

原创粉丝点击