专栏首页用户1096981的专栏简单实现springmvc中的请求处理

简单实现springmvc中的请求处理

自定义MVC框架中的一些元素

一些注解

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Controller {
    String value () default "";
}

@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestMapping {
    String value () default "";
}

@Documented
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Service {
    String value () default "";
}

@Documented
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
    String value () default "";
}

处理对象封装

public class Handler {

    private Object controller;//Controller对应的类
    private Method method;//执行业务的方法
    private Pattern pattern;//uri
    private Map<String,Integer> paramIndexMapping;//参数和位置的映射

    public Handler(Object controller, Method method, Pattern pattern) {
        this.controller = controller;
        this.method = method;
        this.pattern = pattern;
        this.paramIndexMapping = new HashMap<>();
    }

    public Object getController() {
        return controller;
    }

    public void setController(Object controller) {
        this.controller = controller;
    }

    public Method getMethod() {
        return method;
    }

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

    public Pattern getPattern() {
        return pattern;
    }

    public void setPattern(Pattern pattern) {
        this.pattern = pattern;
    }

    public Map<String, Integer> getParamIndexMapping() {
        return paramIndexMapping;
    }

    public void setParamIndexMapping(Map<String, Integer> paramIndexMapping) {
        this.paramIndexMapping = paramIndexMapping;
    }
}

自定义DisptchServelet处理代码

public class DispatchServelet extends HttpServlet {
    private Properties properties = new Properties();
    private List<String> classNames = new ArrayList<>();
    private Map<String,Object> ioc =new HashMap<>();
    private List<Handler> handlerMapping = new ArrayList<>();
    @Override
    public void init(ServletConfig config) throws ServletException {
        //加载配置文件
        String contextConfigLocation = config.getInitParameter("contextConfigLocation");
        doLoadConfig(contextConfigLocation);
        //扫描相关的类,扫描注解
        doScan(properties.getProperty("scanPackage"));
        //初始化bean,基于注解
        doInstance();
        //实现依赖注入
        doAutoWired();
        //实现处理器映射器,将url和method进行关联
        initHandlerMapping();
        System.out.println("mvc 初始化完成");

    }
    //执行的是方法和url方法映射
    private void initHandlerMapping() {
        if (ioc.isEmpty()){
            return;
        }
        for (Map.Entry<String,Object> entry :ioc.entrySet()){
            Class<?> aClass = entry.getValue().getClass();
            if (!aClass.isAnnotationPresent(Controller.class)){
                continue;
            }
            String baseUrl = "";
            if (aClass.isAnnotationPresent(RequestMapping.class)){
                RequestMapping requestMapping = aClass.getAnnotation(RequestMapping.class);
                baseUrl=requestMapping.value();
            }
            Method[] methods= aClass.getMethods();
            for (int i=0;i<methods.length;i++){
                Method method = methods[i];
                if (!method.isAnnotationPresent(RequestMapping.class)){
                    continue;
                }
                RequestMapping requestMapping = method.getAnnotation(RequestMapping.class);
                String methodUrl = requestMapping.value();
                String url = baseUrl+methodUrl;
                Handler handler = new Handler(entry.getValue(),method, Pattern.compile(url));
                Parameter[] parameters = method.getParameters();
                for (int j=0;j<parameters.length;j++){
                    Parameter parameter = parameters[j];
                    if (parameter.getType().equals(HttpServletRequest.class)||parameter.getType().equals(HttpServletResponse.class)){
                        handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),j);
                    }else {
                        handler.getParamIndexMapping().put(parameter.getName(),j);
                    }
                }
                //完成方法和url的映射关系
                handlerMapping.add(handler);
            }
        }
    }
    //执行注入部分,同样是做的ioc的部分功能
    private void doAutoWired() {
        if (ioc.isEmpty()){
            return;
        }
        for (Map.Entry<String,Object> entry :ioc.entrySet()){
            Field[] declareFields = entry.getValue().getClass().getDeclaredFields();
            for (int i=0;i<declareFields.length;i++){
                Field declareField = declareFields[i];
                if (!declareField.isAnnotationPresent(Autowired.class)){
                    continue;
                }
                Autowired autowired = declareField.getAnnotation(Autowired.class);
                String beanName = autowired.value();
                if ("".equals(beanName.trim())){
                    beanName=declareField.getType().getName();
                }
                declareField.setAccessible(true);
                try {
                    //直接将这个字段的值设置为ioc中已经示例化的类,
                    // 即是完成了ioc中的实例化交给容器来管理的情况
                    declareField.set(entry.getValue(),ioc.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }

        }
    }

    //执行的是符合要求的类的初始化,实际上是实现的一部分ioc的功能
    private void doInstance()  {
        if (classNames.size()==0){
            return;
        }
        try {
            for (int i=0;i<classNames.size();i++){
                String className = classNames.get(i);
                Class<?> clazz = Class.forName(className);
                if (clazz.isAnnotationPresent(Controller.class)){
                    String simpleName = clazz.getSimpleName();
                    String lowerFirst = lowerFirst(simpleName);
                    Object o = clazz.newInstance();
                    //因为controller无别名,所以简单设置成首字母小写就行
                    ioc.put(lowerFirst,o);
                }else if (clazz.isAnnotationPresent(Service.class)){
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName =service.value();
                    if (!"".equals(beanName.trim())){
                        ioc.put(beanName,clazz.newInstance());
                    }else {
                        beanName = lowerFirst(clazz.getSimpleName());
                        ioc.put(beanName,clazz.newInstance());
                    }

                    Class<?>[] interfaces = clazz.getInterfaces();
                    for (int j=0;j<interfaces.length;j++){
                        Class<?> ainterface = interfaces[j];
                        System.out.println(ainterface.getName());
                        //将实现类和接口进行绑定
                        ioc.put(ainterface.getName(),clazz.newInstance());
                    }
                }else {
                    continue;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }

    }


    private  String lowerFirst(String className){
       char[] chars = className.toCharArray();
       if ('A'<chars[0]&&chars[0]<'Z'){
           chars[0]+=32;
       }
       return new String(chars);
    }
    private void doScan(String basePackage) {
        //获取到指定包下的所有类的类名
        String scanPackagePath= Thread.currentThread().getContextClassLoader().getResource("").getPath()+basePackage.replaceAll("\\.","/");
        File pack = new File(scanPackagePath);
        File [] files = pack.listFiles();
        for (File file:files){
            if (file.isDirectory()){
                doScan(basePackage+"."+file.getName());
            }else if (file.getName().endsWith(".class")){
                String className = basePackage+"."+file.getName().replaceAll(".class","");
                classNames.add(className);
            }
        }
    }
    //实现加载web.xml中配置的文件的路径
    private void doLoadConfig(String contextConfigLocation) {
        InputStream inputStream =this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
        try {
            properties.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }


    @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 {
        Handler handler = getHander(req);
        if (handler==null){
            resp.getWriter().write("404 not found");
            return;
        }
        Class<?> [] parameterTypes = handler.getMethod().getParameterTypes();
        Object[] paraValues = new Object[parameterTypes.length];

        Map<String,String[]> parameterMap = req.getParameterMap();
        for (Map.Entry<String,String[]> param:parameterMap.entrySet()){
            String value = StringUtils.join(param.getValue(),",");
            if (!handler.getParamIndexMapping().containsKey(param.getKey())){
                continue;
            }
            //对应实际参数的位置
            Integer index = handler.getParamIndexMapping().get(param.getKey());
            paraValues[index]=value;

        }
        //对应上req,和resp参数的位置
        int reqIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getSimpleName());
        paraValues[reqIndex]=req;
        int respIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getSimpleName());
        paraValues[respIndex]=resp;

        try {
            //实际执行的是controller中的方法
            handler.getMethod().invoke(handler.getController(),paraValues);
            System.out.println("执行controller方法成功");
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }

    private Handler getHander(HttpServletRequest req) {
        if (handlerMapping.isEmpty()){
            return null;
        }
        String url =req.getRequestURI();
        for (Handler handler:handlerMapping){
            Matcher matcher = handler.getPattern().matcher(url);
            if (!matcher.matches()){
                continue;
            }
            return handler;
        }
        return null;
    }

}

测试代码

public interface DemoService {

    String getName(String name);
}



@Service("demoService")
public class DemoServiceImpl implements DemoService {
    @Override
    public String getName(String name) {
        return name;
    }
}

@Controller
@RequestMapping("/demo")
public class DemoController {
    @Autowired
    private DemoService demoService;
    @RequestMapping("/query")
    public String query(HttpServletRequest req, HttpServletResponse resp,String name){
        return demoService.getName(name);
    }
}

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>
  <servlet>
    <servlet-name>mvc</servlet-name>
    <servlet-class>com.zhao.mvcframework.servelet.DispatchServelet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>mvc.properties</param-value>
    </init-param>
  </servlet>
  <servlet-mapping>
    <servlet-name>mvc</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

mvc.properties的配置

scanPackage=com.zhao.mvcdemo

pom文件的配置

<?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.zhao</groupId>
  <artifactId>mvc</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>war</packaging>

  <name>mvc Maven Webapp</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</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>
    <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>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>org.apache.commons</groupId>
      <artifactId>commons-lang3</artifactId>
      <version>3.10</version>
    </dependency>
  </dependencies>

  <build>
      <plugins>
        <plugin>
          <groupId>org.apache.tomcat.maven</groupId>
          <artifactId>tomcat7-maven-plugin</artifactId>
          <version>2.2</version>
          <configuration>
            <port>8080</port>
            <path>/</path>
          </configuration>

        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.1</version>
            <configuration>
              <source>1.8</source>
              <target>1.8</target>
              <encoding>utf-8</encoding>
              <compilerArgs>-parameters</compilerArgs>
            </configuration>
        </plugin>
      </plugins>
  </build>
</project>

测试时访问具体的http://localhost:8080/demo/query?name=zhaozhen 无问题

代码地址为https://github.com/zhendiao/deme-code/tree/main/mvc

文章分享自微信公众号:
微瞰技术

本文参与 腾讯云自媒体分享计划 ,欢迎热爱写作的你一起参与!

作者:赵镇
原始发表时间:2021-06-18
如有侵权,请联系 cloudcommunity@tencent.com 删除。
登录 后参与评论
0 条评论

相关文章

  • 简单实现springmvc中的请求处理

    测试时访问具体的http://localhost:8080/demo/query?name=zhaozhen 无问题

    zhaozhen
  • springMVC的请求处理流程

    1、 首先用户发送请求 http://localhost:9080/springmvc-chapter2/hello——>web 容器,web 容器根据“/he...

    一头小山猪
  • SpringMVC源码分析:POST请求中的文件处理

    本章我们来一起阅读和分析SpringMVC的部分源码,看看收到POST请求中的二进制文件后,SpingMVC框架是如何处理的;

    程序员欣宸
  • SpringMvc:spring中的请求处理过程原理分析

    下图是配置我们上篇讲到的控制器,DispatcherServlet的web.xml中的配置

    冷环渊
  • 深度学习springMVC(九)SpringMVC对Ajax请求的处理

    当浏览器发起一个ajax请求给服务器,服务器调用对应的单元方法处理ajax请求。 而ajax的请求在被处理完成后,其处理结果需要直接响应。而目前我们在单元方 ...

    一天不写程序难受
  • SpringMVC源码学习(三) - 请求处理的流程

    在最近的一篇文章中我们大概了解了SpringMVC的九大组件,以及初始化的问题。根本初始化的发起是Spring的事件机制。而这九大组件是什么?我们先回顾一下,他...

    写一点笔记
  • SpringMVC中的异常处理

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 ...

    多凡
  • springmvc之RequestMapping中的请求方式

    西西嘛呦
  • springmvc之RequestMapping中的请求参数和请求头

    西西嘛呦
  • Ajax请求过程中显示“进度”的简单实现

    Ajax在Web应用中使用得越来越频繁。在进行Ajax调用过程中一般都具有这样的做法:显示一个GIF图片动画表明后台正在工作,同时阻止用户操作本页面(比如Aja...

    蒋金楠
  • 快速学习-SpringMVC 中的异常处理

    系统中异常包括两类:预期异常和运行时异常 RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发、测试通过手段减少运行时异...

    cwl_java
  • 简单易懂的springMVC中的测试类

  • 简单易懂的udp实现简单的udp请求服务模式

    实现简单的udp请求服务模式 udp 是一种简单传输协议,实现简单,占用系统资源少 ---- 运行结果 ? 客户端 ? 服务端 服务端代码 # _*_ c...

    zhaoolee
  • 了解Flask并实现简单的HTTP请求

    结合我们822实验室开源的图像处理平台(http://822lab.top)介绍Flask后端开发,供后续学弟学妹参考,整个平台的从零搭建记录在[这里](htt...

    刘开心_1266679
  • 用Groovy处理JMeter中的请求参数

    下面分享一下Groovy如何在JMeter修改请求参数,这个在正常测试中用处还是很广的,跟设置变量不一样,很多参数可能需要校验签名,而且每一次请求的参数也不尽相...

    FunTester
  • iOS信号量处理异步请求中的同步处理

    程序员不务正业
  • Flutter网络请求的3种简单实现方法

    App几乎都离不开与服务器的交互,本文主要讲解了flutter网络请求三种方式 flutter自带的HttpClient、 第三方库http 和 第三方库Dio...

    砸漏
  • 解决在Laravel 中处理OPTIONS请求的问题

    以上这篇解决在Laravel 中处理OPTIONS请求的问题就是小编分享给大家的全部内容了,希望能给大家一个参考。

    砸漏
  • ASP.NET Core中处理中止的请求

    当用户向应用程序发出请求时,服务器将解析该请求,生成响应,然后将结果发送给客户端。用户可能会在服务器处理请求的时候中止请求。就比如说用户跳转到另一个页面中获取说...

    HueiFeng

扫码关注腾讯云开发者

领取腾讯云代金券