手写简易SpringMVC

思路分析:

1.启动tomcat

2.spi机制加载spring容器,扫描包,生成bean,并且将注解解析到Map<String,RequestMappingInfo> map中

3.get/post请求时,.

  • 根据url获取对应的RequestMappingInfo对象
  • 去匹配对应的适配器HandlerAdapter
  • 根据适配器类型选择合适的适配器去执行方法,返回数据
  • 将数据解析成json并写回前端

实现流程

项目结构如下

image

添加依赖pom.xml

<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>

<dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.11</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>javax.servlet-api</artifactId>
        <version>3.1.0</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.9.RELEASE</version>
    </dependency>

    <!--使用maven tomcat插件时,当前依赖需要注释掉,不然会产生冲突。-->
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-core</artifactId>
        <version>8.5.31</version>
    </dependency>
    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
        <version>8.5.31</version>
    </dependency>

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

<build>
    <finalName>customize-springmvc</finalName>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
        <plugins>
            <plugin>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.1.0</version>
            </plugin>
            <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <version>3.0.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.0</version>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.22.1</version>
            </plugin>
            <plugin>
                <artifactId>maven-war-plugin</artifactId>
                <version>3.2.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-install-plugin</artifactId>
                <version>2.5.2</version>
            </plugin>
            <plugin>
                <artifactId>maven-deploy-plugin</artifactId>
                <version>2.8.2</version>
            </plugin>
        </plugins>
    </pluginManagement>
</build>

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>Archetype Created Web Application</display-name>
  
</web-app>

启动Tomcat

package com.yoocar.springmvc;

import org.apache.catalina.startup.Tomcat;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.yoocar.springmvc")
public class Start {

    public static void main(String[] args) throws Exception {
        // 创建Tomcat应用对象
        Tomcat tomcat = new Tomcat();
        // 设置Tomcat的端口号
        tomcat.setPort(8888);
        tomcat.addWebapp("/", "D:\\workspace\\springMVC-study\\customize-springmvc\\src\\main\\webapp");
        //启动tomcat容器
        tomcat.start();
        //等待
        tomcat.getServer().await();

    }
}

三个常用注解

RequestMapping

package com.yoocar.springmvc.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 "";
}

RequestMappingInfo

package com.yoocar.springmvc.servlet;

import java.lang.reflect.Method;

/**
 * 存放RequestMapping注解信息
 */
public class RequestMappingInfo {


    //表示RequestMapping注解标识的方法
    private Method method;

    //表示RequestMapping注解的value属性,即url
    private String uri;

    //表示执行RequestMapping注解标识的方法的bean
    private Object obj;

    public Object getObj() {
        return obj;
    }

    public void setObj(Object obj) {
        this.obj = obj;
    }

    public Method getMethod() {
        return method;
    }

    public void setMethod(Method method) {
        this.method = method;
    }

    public String getUri() {
        return uri;
    }

    public void setUri(String uri) {
        this.uri = uri;
    }
}

RequestParam

package com.yoocar.springmvc.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestParam {

    String value() default "";
}

ResponseBody

package com.yoocar.springmvc.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 ResponseBody {
}

处理注解的

spi机制加载spring容器

package com.yoocar.springmvc.init;

import com.yoocar.springmvc.Start;
import com.yoocar.springmvc.servlet.DispatcherServlet;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletRegistration;
import java.util.Set;

//spi机制
public class Myinit implements ServletContainerInitializer{

    @Override
    public void onStartup(Set<Class<?>> c,ServletContext servletContext) {
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(Start.class);

        DispatcherServlet servlet = new DispatcherServlet(ac);
        ServletRegistration.Dynamic dy = servletContext.addServlet("app",servlet);
        dy.setLoadOnStartup(1);
        dy.addMapping("*.do");

    }

}

DispatcherServlet

import com.yoocar.springmvc.init.handlerAdapter.HandlerAdapter;
import com.yoocar.springmvc.init.handlerMapping.HandlerMapping;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
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.io.PrintWriter;
import java.util.Collection;
import java.util.Map;

public class DispatcherServlet extends HttpServlet {

    //适配器
    static Collection<HandlerAdapter> handlerAdapters ;

    //映射器
    static Collection<HandlerMapping> handlerMappings ;

    public DispatcherServlet() {
    }

    public DispatcherServlet(AnnotationConfigApplicationContext ac) {
        //组件初始化
        Map<String, HandlerMapping> handlerMappingMaps = ac.getBeansOfType(HandlerMapping.class);
        handlerMappings = handlerMappingMaps.values();

        Map<String, HandlerAdapter> handlerAdapterMaps = ac.getBeansOfType(HandlerAdapter.class);
        handlerAdapters = handlerAdapterMaps.values();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException, ServletException {
        //获取映射器
        Object handlerMapping = getHandlerMapping(req);
        if(handlerMapping == null){
            System.out.println("未匹配到handlerMapping");
            return;
        }
        //获取适配器
        HandlerAdapter handlerAdapter = getHandlerAdapter(handlerMapping);
        if(handlerAdapter == null){
            System.out.println("未匹配到handlerAdapter");
            return;
        }
        //使用适配器(处理器)去处理
        Object result = handlerAdapter.handle(req,resp,handlerMapping);
        PrintWriter writer = resp.getWriter();
        writer.println(result);
        writer.flush();
        writer.close();
    }

    protected Object getHandlerMapping(HttpServletRequest request) {
        if (this.handlerMappings != null) {
            for (HandlerMapping mapping : this.handlerMappings) {
                Object handler = mapping.getHandlerMapping(request.getRequestURI());
                if (handler != null) {
                    return handler;
                }
            }
        }
        return null;
    }

    protected HandlerAdapter getHandlerAdapter(Object handlerMapping) {
        if (this.handlerAdapters != null) {
            for (HandlerAdapter adapter : this.handlerAdapters) {
                boolean flag = adapter.supports(handlerMapping);
                if (flag) {
                    return adapter;
                }
            }
        }
        return null;
    }

}
posted on 2022-03-08 23:26  路仁甲  阅读(30)  评论(0编辑  收藏  举报