手写springmvc

一、先大致了解一下SpringMVC执行流程:

  1. 用户向服务器发送请求,请求被Spring 前端控制Servelt DispatcherServlet捕获;
  2. DispatcherServlet对请求URL进行解析,得到请求资源标识符(URI)。然后根据该URI,调用HandlerMapping获得该Handler配置的所有相关的对象(包括Handler对象以及Handler对象对应的拦截器),最后以HandlerExecutionChain对象的形式返回;
  3. DispatcherServlet 根据获得的Handler,选择一个合适的HandlerAdapter。(附注:如果成功获得HandlerAdapter后,此时将开始执行拦截器的preHandler(…)方法)
  4. 提取Request中的模型数据,填充Handler入参,开始执行Handler(Controller)。 在填充Handler的入参过程中,根据你的配置,Spring将帮你做一些额外的工作:
    HttpMessageConveter: 将请求消息(如Json、xml等数据)转换成一个对象,将对象转换为指定的响应信息
    数据转换:对请求消息进行数据转换。如String转换成Integer、Double等
    数据根式化:对请求消息进行数据格式化。 如将字符串转换成格式化数字或格式化日期等
    数据验证: 验证数据的有效性(长度、格式等),验证结果存储到BindingResult或Error中
  5. Handler执行完成后,向DispatcherServlet 返回一个ModelAndView对象;
  6. 根据返回的ModelAndView,选择一个适合的ViewResolver(必须是已经注册到Spring容器中的 ViewResolver)返回给DispatcherServlet ;
  7. ViewResolver 结合Model和View,来渲染视图
  8. 将渲染结果返回给客户端。
    SpringMVC执行流程

二、直接贴代码,代码中有注释
1.首先创建一个maven web工程 添加如下依赖

<?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.lh.core</groupId>
  <artifactId>framework</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>framework Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.leoraqlx.club</url>

  <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>
    <!--servlet 依赖-->
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
     <version>3.1.0</version>
    </dependency>
    <!-- 工具类-->
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.6</version>
    </dependency>
    <!-- json 解析 -->
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.32</version>
    </dependency>
    <!-- Lombok插件 -->
    <dependency>
      <groupId>org.projectlombok</groupId>
      <artifactId>lombok</artifactId>
      <version>1.16.4</version>
    </dependency>
    <!-- yaml文件 解析 -->
    <dependency>
      <groupId>org.jyaml</groupId>
      <artifactId>jyaml</artifactId>
      <version>1.3</version>
    </dependency>

  </dependencies>

  <build>
    <finalName>framework</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.0.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.7.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.20.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-war-plugin</artifactId>
          <version>3.2.0</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>
</project>

2.编辑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>

  <!--自定义的DispatchServlet-->
  <servlet>
    <servlet-name>dispatchservlet</servlet-name>
    <servlet-class>com.lh.core.framework.servlet.DispatchServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatchservlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

3.几个需要用到的工具解析类
json解析

package com.lh.core.framework.utils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * @ProjectName: framework
 * @Package: com.lh.core.framework.utils
 * @ClassName: JsonUtil
 * @Description: 将请求参数转换为jsonobject
 * @Author: lihao
 * @CreateDate: 2018/11/7 3:36 PM
 * @UpdateDate: 2018/11/7 3:36 PM
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
public class JsonUtil {
    public static JSONObject getBody(HttpServletRequest request){
        String contentType = request.getContentType();
        StringBuilder stringBuilder = new StringBuilder();
        BufferedReader bufferedReader=null;
        try{
            InputStream inputStream = request.getInputStream();
            if(inputStream!=null){
                bufferedReader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
                char[] charBuffer = new char[128];
                int bytesRead = -1;
                while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
                    stringBuilder.append(charBuffer, 0, bytesRead);
                }
            }else{
                stringBuilder.append("");
            }
        }catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(bufferedReader!=null){
                try {
                    bufferedReader.close();
                }catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        if (contentType.equalsIgnoreCase("application/json")) {
            String jsonStr = stringBuilder.toString();
            JSONObject jsonObject = JSON.parseObject(jsonStr);
            return jsonObject;
        }
        return  null;
    }
}

获取Java包下所有的类

package com.lh.core.framework.utils;
import java.io.File;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

/**
 * @ProjectName: framework
 * @Package: com.lh.core.framework.utils
 * @ClassName: PackageUtil
 * @Description: 获取Java包下所有的类
 * @Author: lihao
 * @CreateDate: 2018/10/24 5:41 PM
 * @UpdateDate: 2018/10/24 5:41 PM
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
public class PackageUtil {
    public static List<String> scanPackage(String packageName){
        List<String> classz=new ArrayList<>();
        URL url = Thread.currentThread().getContextClassLoader().getResource(packageName.replace(".","/"));
        if(url==null){
            return null;
        }
        String pathFile = url.getFile();
        File file = new File(pathFile);
        String fileList[] = file.list();
        for (String path : fileList) {
            File eachFile = new File(pathFile + path);
            if (eachFile.isDirectory()) {
                scanPackage(packageName + "." + eachFile.getName());
            } else {
                String name = eachFile.getName();
                classz.add(packageName + "." +name.substring(0,name.lastIndexOf(".")));
            }
        }
        return classz;
    }
}

yml文件解析

package com.lh.core.framework.utils;
import org.ho.yaml.Yaml;
import java.io.FileNotFoundException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class YmlUtil {
    /**
     * key:文件名索引
     * value:配置文件内容
     */
    private static Map<String, LinkedHashMap> ymls = new HashMap<>();
    /**
     * string:当前线程需要查询的文件名
     */
    private static ThreadLocal<String> nowFileName = new ThreadLocal<>();
    private static final String PACKAGENAME="spring.application.controller";
    private static final String FILENAME="init.yml"; //配置文件名称
    /**
     * 加载配置文件
     * @param fileName
     */
    public static void loadYml(String fileName) throws FileNotFoundException {
        nowFileName.set(fileName);
        if (!ymls.containsKey(fileName)) {
            ymls.put(fileName,Yaml.loadType(YmlUtil.class.getResourceAsStream("/" + fileName), LinkedHashMap.class));
        }

    }
    private static Object getValue(String key) throws Exception {
        // 首先将key进行拆分
        String[] keys = key.split("[.]");
        // 将配置文件进行复制
        Map ymlInfo = (Map) ymls.get(nowFileName.get()).clone();
        for (int i = 0; i < keys.length; i++) {
            Object value = ymlInfo.get(keys[i]);
            if (i < keys.length - 1) {
                ymlInfo = (Map) value;
            } else if (value == null) {
                throw new Exception("key不存在");
            } else {
                return value;
            }
        }
        throw new RuntimeException("不可能到这里的...");
    }

    public static Object getValue() throws Exception {
        // 首先加载配置文件
        loadYml(FILENAME);
        return getValue(PACKAGENAME);
    }
}

注解
Controller

package com.lh.core.framework.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @ProjectName: framework
 * @Package: com.lh.core.framework
 * @ClassName: ControllerAnnotation
 * @Description: java类作用描述
 * @Author: lihao
 * @CreateDate: 2018/10/24 5:05 PM
 * @UpdateDate: 2018/10/24 5:05 PM
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Controller {

    String value() default "";
}

RequestMapping

package com.lh.core.framework.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @ProjectName: framework
 * @Package: com.lh.core.framework.annotation
 * @ClassName: RequestMapping
 * @Description: java类作用描述
 * @Author: lihao
 * @CreateDate: 2018/10/24 5:12 PM
 * @UpdateDate: 2018/10/24 5:12 PM
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
    String value() default "";
}

RequestJson

package com.lh.core.framework.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * @ProjectName: framework
 * @Package: com.lh.core.framework.annotation
 * @ClassName: RequestJson
 * @Description: java类作用描述
 * @Author: lihao
 * @CreateDate: 2018/10/31 5:26 PM
 * @UpdateDate: 2018/10/31 5:26 PM
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestJson {
    String value() default  "";
}

DispatchServlet

package com.lh.core.framework.servlet;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.lh.core.framework.annotation.Controller;
import com.lh.core.framework.annotation.RequestJson;
import com.lh.core.framework.annotation.RequestMapping;
import com.lh.core.framework.utils.JsonUtil;
import com.lh.core.framework.utils.PackageUtil;
import com.lh.core.framework.utils.YmlUtil;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class DispatchServlet extends HttpServlet {
    List<String>classz=new ArrayList<>();//扫描包下所有的类
    Map<String,Method> mappingMethodMap=new ConcurrentHashMap<>();//url映射对应的方法
    Map<String,Object>mappingClassMap=new ConcurrentHashMap<>();//url映射对应的类
    /**
     * 初始化,装配接口映射地址
     */
    @Override
    public void init(){
        try {
            classz= PackageUtil.scanPackage((String) YmlUtil.getValue());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if(classz==null){
            return;
        }
        for (String clazz:classz) {
            String  mappingUrl="";
            try {
                Class<?> loadClass =Class.forName(clazz);
                Controller controller = loadClass.getAnnotation(Controller.class);
                if(controller==null){
                    continue;
                }
                RequestMapping controllerUrl = loadClass.getAnnotation(RequestMapping.class);
                mappingUrl=mappingUrl+controllerUrl.value();
                Method[] methods = loadClass.getMethods();
                for (Method method:methods){
                    RequestMapping methodMapping = method.getAnnotation(RequestMapping.class);
                    if(methodMapping==null){
                        continue;
                    }
                    mappingUrl=mappingUrl+methodMapping.value();
                    mappingMethodMap.put(mappingUrl,method);
                }
                Object object = loadClass.newInstance();
                mappingClassMap.put(mappingUrl,object);

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
                continue;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 执行请求,返回结果
     * @param request
     * @param response
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)  {
        String uri = request.getRequestURI();
        Method method = mappingMethodMap.get(uri);
        Object object = mappingClassMap.get(uri);
        if(method==null){
            return;
        }
        JSONObject body =JsonUtil.getBody(request);
        Parameter[] parameters = method.getParameters();
        Object[] o = buildParam(parameters, body);
        try {
            Object invoke = method.invoke(object,o);
            response.getWriter().write(invoke.toString());
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    /**
     * 封装接口方法的入参
     * @param parameters
     * @param body
     * @return
     */
    private  Object[] buildParam( Parameter[] parameters,  JSONObject body){
        Object[] objects=new Object[parameters.length];
        for (int i=0;i< parameters.length ;i++) {
            RequestJson requestJson = parameters[i].getAnnotation(RequestJson.class);
            if(requestJson==null){
                continue;
            }
            Object object = JSON.toJavaObject(body, parameters[i].getType());
            objects[i]=object;
        }
        return objects;
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doPost(req, resp);
    }
    @Override
    public void destroy() {
        super.destroy();
    }
}

自定义一个controller

package com.lh.core.framework.controller;
import com.lh.core.framework.annotation.Controller;
import com.lh.core.framework.annotation.RequestJson;
import com.lh.core.framework.annotation.RequestMapping;
import com.lh.core.framework.request.IndexRequest;
/**
 * @ProjectName: framework
 * @Package: com.lh.core.framework.controller
 * @ClassName: IndexController
 * @Description: java类作用描述
 * @Author: lihao
 * @CreateDate: 2018/11/9 3:04 PM
 * @UpdateDate: 2018/11/9 3:04 PM
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
@RequestMapping("/index")
@Controller
public class IndexController {
    @RequestMapping("/test")
    public  String test(@RequestJson IndexRequest request){
        System.out.println("request = [" + request + "]");
        return "OK";
    }
}

请求参数

package com.lh.core.framework.request;

import lombok.Data;

/**
 * @ProjectName: framework
 * @Package: com.lh.core.framework.request
 * @ClassName: IndexRequest
 * @Description: java类作用描述
 * @Author: lihao
 * @CreateDate: 2018/11/9 3:05 PM
 * @UpdateDate: 2018/11/9 3:05 PM
 * @UpdateRemark: 更新说明
 * @Version: 1.0
 */
@Data
public class IndexRequest {
    private String title;
    private Integer num;
}

请求示例:
在这里插入图片描述

源码地址 :https://github.com/lihao95/framework/tree/master/framework

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值