手写一个SprigMVC

简单手写一个SpringMVC,了解SpringMVC源码。
首先让我们了解一下一个SpringMVC项目的工作流程,以及所用到的方法。
在这里插入图片描述
在这里插入图片描述
下来我们进入实战。

  1. 创建一个maven的Web项目,在pom.xml引入Servlet依赖。
<dependency>
  <groupId>javax.servlet</groupId>
  <artifactId>servlet-api</artifactId>
  <version>2.5</version>
  <scope>provided</scope>
</dependency>
  1. 项目的目录是这样的。在这里插入图片描述
  2. Service接口
package com.enjoy.service;

public interface JamesService {
    String query(String name,String age);
}

实现类

package com.enjoy.service.impl;

import com.enjoy.annotation.EnjoyService;
import com.enjoy.service.JamesService;

//tomcat启动
//spring底层 扫描找到特殊注解的类JamesService ==创建对象jamesServiceImpl
//默认首字母小写 但是可以自己定义
//map.put("jamesServiceImpl",jamesServiceImpl)
//
@EnjoyService("JamesServiceImpl")
public class JamesServiceImpl implements JamesService {
    @Override
    public String query(String name, String age) {
        return "{name="+name+",age="+age+"}";
    }
}

  1. controller类
package com.enjoy.controller;

import com.enjoy.annotation.EnjoyAutowired;
import com.enjoy.annotation.EnjoyController;
import com.enjoy.annotation.EnjoyRequestMapping;
import com.enjoy.annotation.EnjoyRequestParam;
import com.enjoy.service.JamesService;

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

@EnjoyController
@EnjoyRequestMapping("/james")
public class lcController {

    @EnjoyAutowired("JamesServiceImpl")
    private JamesService jamesService;

    @EnjoyRequestMapping("/query")
    public void query(HttpServletRequest request, HttpServletResponse response,
                      @EnjoyRequestParam("name") String name,
                      @EnjoyRequestParam("age") String age){
        try {
            PrintWriter  pw = response.getWriter();
            String result=jamesService.query(name,age);
            pw.write(result);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

}

  1. 在这里的注解肯定会报错所以我们要自定义注解。
package com.enjoy.annotation;

import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)      //表示在运行时通过反射获取 载体
@Documented  //javadoc
public @interface EnjoyAutowired {
    String value() default "";
}

package com.enjoy.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)    //只能在类上使用
@Retention(RetentionPolicy.RUNTIME)      //表示在运行时通过反射获取 载体
@Documented  //javadoc
public @interface EnjoyController {
    String value() default "";
}

package com.enjoy.annotation;

import java.lang.annotation.*;
@Target({ElementType.TYPE,ElementType.METHOD})    //只能在类上使用
@Retention(RetentionPolicy.RUNTIME)      //表示在运行时通过反射获取 载体
@Documented  //javadoc
public @interface EnjoyRequestMapping {
    String value() default "";
}

package com.enjoy.annotation;

import java.lang.annotation.*;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)      //表示在运行时通过反射获取 载体
@Documented  //javadoc
public @interface EnjoyRequestParam {
    String value() default "";
}

package com.enjoy.annotation;

import java.lang.annotation.*;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)      //表示在运行时通过反射获取 载体
@Documented  //javadoc
public @interface EnjoyService {
    String value() default "";
}

  1. 自己动定义Servlet这里我命名为DisptcherServlet
package com.enjoy.servlet;

import com.enjoy.annotation.*;
import com.enjoy.controller.lcController;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
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;

public class DispatcherServlet extends HttpServlet {

    List<String> classNames = new ArrayList<String>();
    Map<String, Object> beans = new HashMap<String, Object>();
    Map<String, Object> handerMap = new HashMap<String, Object>();

    //扫描路径service.impl.JamesServiceImpl.class
    //创建对象,实列化(反射)
    //autowired
    //urlhandmapping 路径映射
    public void init(ServletConfig config) throws ServletException {
        System.out.println("hehe");
        doBasePackage("com.enjoy");
        doInstance();
        doAutowired();
        UrlHanding();
    }

    public void UrlHanding() {
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object instance = entry.getValue();
            Class<?> clazz = instance.getClass();
            if (clazz.isAnnotationPresent(EnjoyController.class)) {
                EnjoyRequestMapping map1 = clazz.getAnnotation(EnjoyRequestMapping.class);
                String classPath = map1.value();
                Method[] methods = clazz.getMethods();
                System.out.println("urlHanding");
                for (Method method : methods) {
                    if (method.isAnnotationPresent(EnjoyRequestMapping.class)) {
                        EnjoyRequestMapping map2 = method.getAnnotation(EnjoyRequestMapping.class);
                        String methodPath = map2.value();   //query
                        handerMap.put(classPath + methodPath, method);
                    } else {
                        continue;
                    }
                }
            }
        }
    }

    public void doAutowired() {
        for (Map.Entry<String, Object> entry : beans.entrySet()) {
            Object instance = entry.getValue();
            Class<?> clazz = instance.getClass();
            if (clazz.isAnnotationPresent(EnjoyController.class)) {
                Field[] fields = clazz.getDeclaredFields();
                System.out.println("autowired");
                for (Field field : fields) {
                    if (field.isAnnotationPresent(EnjoyAutowired.class)) {
                        EnjoyAutowired ea = field.getAnnotation(EnjoyAutowired.class);
                        String key = ea.value();
                        Object ins = beans.get(key);
                        field.setAccessible(true);
                        try {
                            field.set(instance, ins);
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    } else {
                        continue;
                    }
                }
            }
        }
    }

    public void doInstance() {
        for (String className : classNames) {
            //className=com.enjoy...Service.class
            String cn = className.replace(".class", "");
            //cn=com.emjoy...Service
            try {
                Class<?> clazz = Class.forName(cn);
                System.out.println("doInstance");
                //判断一下 是不是引用了@Controller service
                if (clazz.isAnnotationPresent(EnjoyController.class)) {
                    //控制类 实列化 map put key value
                    Object instance = clazz.newInstance();
                    //key 拿类上边的注解
                    EnjoyRequestMapping map1 = clazz.getAnnotation(EnjoyRequestMapping.class);
                    String key = map1.value();
                    //key value IOC容器==MAP
                    beans.put(key, instance);
                } else if (clazz.isAnnotationPresent(EnjoyService.class)) {
                    //控制类 实列化 map put key value
                    Object instance = clazz.newInstance();
                    //key
                    EnjoyService map1 = clazz.getAnnotation(EnjoyService.class);
                    String key = map1.value();
                    //key value IOC容器==MAP
                    beans.put(key, instance);
                } else {
                    continue;
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }

        }
    }
     //递归
    public void doBasePackage(String basePackage) {
        //e:/workspace/pro/enjoy
        URL url = this.getClass().getClassLoader().getResource("/" + basePackage.replaceAll("\\.", "/"));
        String fileStr = url.getFile();  //fileStr=e:/workspace/pro/enjoy

        File file = new File(fileStr);

        String[] fileStrs = file.list();

        for (String path : fileStrs) {
            System.out.println("package");
            File filePath = new File(fileStr + path);
            if (filePath.isDirectory()) {
                doBasePackage(basePackage + "." + path);
            } else {
                //.class结束的文件?1 2
                //.class 保存下来
                //com.enjoy.xxx.JamesService.class?
                classNames.add(basePackage + "." + filePath.getName());
            }
        }
    }

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

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

        String uri = request.getRequestURI();   //pro /james/query
        String context = request.getContextPath();          //pro
        String path = uri.replace(context, "");
        Method method = (Method) handerMap.get(path);
        System.out.println("外边");
        lcController instance = (lcController) beans.get("/" + path.split("/")[1]);
        Object args[]=hand(request,response,method);
        System.out.println("aaa");
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        try {
            method.invoke(instance,args);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    private static Object[] hand(HttpServletRequest request, HttpServletResponse response, Method method) {
        //拿到当前待执行的方法有那些参数
        Class<?>[] paramClazzs = method.getParameterTypes();
        //根据参数的个数,new 一个参数的数组,将方法里的所有参数赋值到args来
        Object[] args = new Object[paramClazzs.length];
        int args_i = 0;
        int index = 0;
        for (Class<?> paramClazz : paramClazzs) {
            if (ServletRequest.class.isAssignableFrom(paramClazz)) {
                args[args_i++] = request;
            }
            if (ServletResponse.class.isAssignableFrom(paramClazz)) {
                args[args_i++] = response;
            }
            //从0-3判断有没有Requestparam注解,很明显paramClazz为0和1时,不是
            //当为2和3时为@RequesyParam需要解析
            //{@com.enjoy.annotation.EnjoyRequestparam()[index];
            Annotation[] paramAns = method.getParameterAnnotations()[index];
            if (paramAns.length > 0) {
                for (Annotation paramAn : paramAns) {
                    if (EnjoyRequestParam.class.isAssignableFrom(paramAn.getClass())) {
                        EnjoyRequestParam rp = (EnjoyRequestParam) paramAn;
                        //找到注解里的name和age
                        args[args_i++] = request.getParameter(rp.value());
                    }
                }
            }
            index++;
        }
        return args;
    }
}

  1. 在web.xml配置
<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>commvc</display-name>
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>com.enjoy.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>0</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>
</web-app>

  1. 启动项目,访问
    在这里插入图片描述
    完美运行,不理解的可以博客下评论。求关注一下或者?一个,感谢!!!!
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值