1. 1 不可撤销
  2. 2 小年兽 程嘉敏
  3. 3 手放开 李圣杰
  4. 4 迷人的危险3(翻自 dance flow) FAFA
  5. 5 山楂树之恋 程佳佳
  6. 6 summertime cinnamons / evening cinema
  7. 7 不谓侠(Cover 萧忆情Alex) CRITTY
  8. 8 神武醉相思(翻自 优我女团) 双笙
  9. 9 空山新雨后 音阙诗听 / 锦零
  10. 10 Wonderful U (Demo Version) AGA
  11. 11 广寒宫 丸子呦
  12. 12 陪我看日出 回音哥
  13. 13 春夏秋冬的你 王宇良
  14. 14 世界が终わるまでは… WANDS
  15. 15 多想在平庸的生活拥抱你 隔壁老樊
  16. 16 千禧 徐秉龙
  17. 17 我的一个道姑朋友 双笙
  18. 18 大鱼  (Cover 周深) 双笙
  19. 19 霜雪千年(Cover 洛天依 / 乐正绫) 双笙 / 封茗囧菌
  20. 20 云烟成雨(翻自 房东的猫) 周玥
  21. 21 情深深雨濛濛 杨胖雨
  22. 22 Five Hundred Miles Justin Timberlake / Carey Mulligan / Stark Sands
  23. 23 斑马斑马 房东的猫
  24. 24 See You Again Wiz Khalifa / Charlie Puth
  25. 25 Faded Alan Walker / Iselin Solheim
  26. 26 Natural J.Fla
  27. 27 New Soul Vox Angeli
  28. 28 ハレハレヤ(朗朗晴天)(翻自 v flower) 猫瑾
  29. 29 像鱼 王贰浪
  30. 30 Bye Bye Bye Lovestoned
  31. 31 Blame You 眠 / Lopu$
  32. 32 Believer J.Fla
  33. 33 书信 戴羽彤
  34. 34 柴 鱼 の c a l l i n g【已售】 幸子小姐拜托了
  35. 35 夜空中最亮的星(翻自 逃跑计划) 戴羽彤
  36. 36 慢慢喜欢你 LIve版(翻自 莫文蔚) 戴羽彤
  37. 37 病变(翻自 cubi) 戴羽彤
  38. 38 那女孩对我说 (完整版) Uu
  39. 39 绿色 陈雪凝
  40. 40 月牙湾 LIve版(翻自 F.I.R.) 戴羽彤
夜空中最亮的星(翻自 逃跑计划) - 戴羽彤
00:00 / 04:10

夜空中最亮的星 能否听清

那仰望的人 心底的孤独和叹息

夜空中最亮的星 能否记起

那曾与我同行 消失在风里的身影

我祈祷拥有一颗透明的心灵

和会流泪的眼睛

给我再去相信的勇气

越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请指引我靠近你

夜空中最亮的星 是否知道

那曾与我同行的身影 如今在哪里

夜空中最亮的星 是否在意

是等太阳先升起 还是意外先来临

我宁愿所有痛苦都留在心底

也不愿忘记你的眼睛

哦 给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行 哒~

我祈祷拥有一颗透明的心灵

和会流泪的眼睛 哦

给我再去相信的勇气

哦 越过谎言去拥抱你

每当我找不到存在的意义

每当我迷失在黑夜里

噢喔喔 夜空中最亮的星

请照亮我向前行

手写RequestParameter注解,实现有参方法调用

前言

昨天实现了requestMapping和controller注解,解决了请求地址与接口方法之间的映射问题,可以根据前端请求地址调用对应的接口方法。但是还不能解决有参方法的调用,今天我们就来啃下这个硬碴,解决这个最后一公里。

开肝

定义RequestParameter注解

springboot的注解是RequestParam,我们今天实现的需求就是参考RequestParam,但是我没有时间去研究springboot的源码(至少今天没有时间),就先按照自己的想法来实现了。和前面注解不一样的一点是,这个注解的target指定的是ElementType.PARAMETER,因为这个注解是加在方法的参数上的。

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequestParameter {
    String value();
}

加到方法的参数上是这样的:

@RequestMapping("/sayHello")
    public String test(@RequestParameter("name") String name) {
        return "hello," + name;
    }

是不是看着还挺像像样的。

业务端使用

目前业务处理还是在doDispatcher方法,所以今天依然是动这个方法。

先说下思路,思路也很简单,就是服务器收到前端请求后,根据requestMapping(请求地址)拿到对应的方法,从方法中拿到参数注解RequestParameter(这个注解的作用就是标记参数名,让我们可以根据参数名拿到参数),然后根据注解的value拿到参数名,然后根据参数名从requestAttributeMap拿到请求参数的值,组装方法入参列表。

/**
     * 请求分发处理
     * @throws Exception
     */
    public void doDispatcher() throws Exception{
        RequestHear requestHear = request.getRequestHear();
        Map<String, Object> requestAttributeMap = request.getRequestAttributeMap();
        logger.info("请求头信息:{}", requestHear);
        logger.info("请求信息:{}", requestAttributeMap);
        if (Objects.isNull(requestHear) || Objects.isNull(requestAttributeMap)) {
            return;
        }
        String requestMapping = requestHear.getRequestMapping();
        if (requestMappingMap.containsKey(requestMapping)) {
            Method method = requestMappingMap.get(requestMapping);
            logger.debug("method:{}", method);
            Class<?> declaringClass = method.getDeclaringClass();
            Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            Object[] parameters = new Object[parameterAnnotations.length];
            for (int i = 0; i < parameterAnnotations.length; i++) {
                RequestParameter annotation = (RequestParameter)parameterAnnotations[i][0];
                parameters[i] = requestAttributeMap.get(annotation.value());
            }
            Object o = declaringClass.newInstance();
            Object invoke = method.invoke(o, parameters);
            logger.info("invoke:{}", invoke);
            response.write(String.format("hello syskeCat, dateTime:%d\n result = %s", System.currentTimeMillis(), invoke));
        } else {
            response.write(404, String.format("resources not found :%d", System.currentTimeMillis()));
        }
        socket.close();
    }

我单独把修改部分拿出来,简单解释下。

Annotation[][] parameterAnnotations = method.getParameterAnnotations();
            Object[] parameters = new Object[parameterAnnotations.length];
            for (int i = 0; i < parameterAnnotations.length; i++) {
                RequestParameter annotation = (RequestParameter)parameterAnnotations[i][0];
                parameters[i] = requestAttributeMap.get(annotation.value());
            }
            Object o = declaringClass.newInstance();
            Object invoke = method.invoke(o, parameters);

method.getParameterAnnotations的作用是获取方法的所有参数注解,返回结果是一个二维数组,因为一个方法可以有多个参数,每个参数都可以有多个注解,所以肯定是一个二维数组。parameterAnnotations[0][0]就是第一个参数的第一个注解,parameterAnnotations[1][0]就是第二个参数的第一个注解,其他以此类推。这张图更清楚地说明了这一点:

因为获取到的注解是Annotation,并非是我们的定义的注解,所以需要进行强制转换成我们的自定义注解RequestParameter

然后通过注解的value()方法从注解中拿到参数名,根据参数名从参数map中拿到请求的值,组装成参数集合,然后反射调用。

请求参数处理这边我们也做了一些调整,主要是为了获取请求参数参数:

 Map<String, Object> attributeMap = Maps.newHashMap();
        if (requestMapping.contains("?")) {
            int endIndex = requestMapping.lastIndexOf('?');
            String requestParameterStr = requestMapping.substring(endIndex + 1);
            requestMapping = requestMapping.substring(0, endIndex);
            String[] split = requestParameterStr.split("&");
            for (String s : split) {
                String[] split1 = s.split("=");
                attributeMap.put(StringUtil.trim(split1[0]), StringUtil.trim(split1[1]));
            }

        }

主要就是在增加了请求参数的处理,把sayHello?name=yunzhongzhi&age=12处理成requestMapping和请求参数map。这块后期还需要优化,要把get请求和post请求分开,分别处理,所以目前我们的服务器只支持get请求。

测试

完成以上调整,我们的方法就已经支持有参调用了,我们来测试下吧!

效果还不错,目标完美达成。

总结

感觉有思路的话,写东西还是比较快的,这些需求都是今天早上实现的,中间被Annotation卡住了,一直无法获取到参数名,后来发现只要强转一下就行了。千里之行,始于足下,感兴趣的小伙伴肝起来。

下面是项目的开源仓库,有兴趣的小伙伴可以去看看,如果有想法的小伙伴,我真心推荐你自己动个手,自己写一下,真的感觉不错:

https://github.com/Syske/syske-boot

posted @ 2021-06-09 13:45  云中志  阅读(317)  评论(0编辑  收藏  举报