大家一起写mvc(二)
上一篇已经看了,我想大家都明白了mvc的原理,今天我们来说一下要写自己mvc框架必须要会的技术。
mvc的目录是这样的
src目录是我们核心的mvc代码。这个代码明天讲,今天主要讲的代码都在test目录下。
在第一章我已经说了,写mvc技术需要用的就是java的反射原理,还有自定义注解。
现在我们先讲一下注解的用处,可能这个自定义注解听着挺高深的,等你看完这个就会明白,其实很简单,就是xml的另一种方法。
讲解我就都放在代码的注解里了,这样写比较方便。
annotation注解:
- package com.test;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- /**
- * jdk1.5以上
- * @Target 描述注解的使用范围
- * @Retention 注解生命周期
- * @Documented 文档相关
- * @Inherited 阐述了某个被标注的类型是被继承的
- * 关于注解的详细信息可以看下面这个博客。
- * http://www.cnblogs.com/peida/archive/2013/04/24/3036689.html
- * 这篇文章写的很好,我就不重复的叨逼叨了。。
- * 在mvc里 我们就用两个注解属性
- * @Target 标注使用范围,这个我们标注为method。即这个注解我们要用在方法级别上。
- * @Retention 生命周期,即运行时,Runtime
- * @author wanglong
- *
- */
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface TestAnno {
- public String ActionName() default "";
- public String Result() default "";
- }
现在我们定义注解了,我们要用在哪呢,就用在Action的方法上,比如我们写一个Action
- package com.test;
- public class TestAction {
- @Anno(ActionName="test.action",Result="index.jsp")
- public void TestAnno(User user)
- {
- System.out.println(user.getUsername());
- }
- }
这样我们就在TestAction里的TestAnno方法上加上了我们自定义的注解。
我们怎么获得注解里的值呢,就是通过反射。下面的代码是Junit4的一个testcase。
- public void testAnno() throws Exception{
- Class clazz = Class.forName("com.test.TestAction");
- Method[] methods = clazz.getDeclaredMethods();
- for (Method method : methods)
- {
- if(method.isAnnotationPresent(com.test.Anno.class))
- {
- Anno anno = method.getAnnotation(com.test.Anno.class);
- System.out.println(anno.ActionName()); //test.action
- System.out.println(anno.Result()); //index.jsp
- }
- }
- }
恩,这里我们已经获取到了,大家也知道该怎么用了吧,也知道在mvc里应该用在哪里了。注解我们就讲到这里。下面我们说反射
java反射
我也不知道大家会不会反射。。我这也不知道说到什么程度合适,所以我就把要在mvc中用到的反射方法说一下吧。
首页,我们有一个登录页面-login.jsp
- <%@ page language="java" contentType="text/html; charset=UTF-8"
- pageEncoding="UTF-8"%>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
- <title>Insert title here</title>
- </head>
- <body>
- <form action="test.action" method="post">
- <input type="text" value="admin" name="user.userName">
- <input type="text" value="adminPassword" name="user.password">
- <input type="submit" value="登录"/>
- </form>
- </body>
- </html>
然后我们还要有一个user类
- package com.test;
- public class User {
- private String username;
- private String password;
- public String getUsername()
- {
- return username;
- }
- public void setUsername(String username)
- {
- this.username = username;
- }
- public String getPassword()
- {
- return password;
- }
- public void setPassword(String password)
- {
- this.password = password;
- }
- }
我们看到login.jsp请求action是test.action.里面的参数分别是user.username跟user.password,我们通过servlet拦截后,可以通过java的自定义注解也就是我们上面的Anno这个注解来获取到test.action注解的这个(TestAnno)方法,但是我们怎么把页面上的这两个参数传给action呢,所以我们就用到反射,通过反射,我们把页面上user封装,然后在通过反射来调用TestAnno方法。
首先,我们要通过反射获取到TestAnno这个方法的参数类型。
- /*
- * 反射获取方法参数类型
- */
- @org.junit.Test
- public void testActionParamType() throws Exception{
- Class clazz = Class.forName("com.test.TestAction");
- Method[] methods = clazz.getDeclaredMethods();
- for (Method method : methods)
- {
- Class[] params = method.getParameterTypes();
- for (int i = 0; i < params.length; i++)
- {
- System.out.println(method.getName());//获取的是方法的名称 也就是 TestAnno
- System.out.println(params[i]);//方法参数类型 这里打印 class com.test.User 说明这个方法只有一个参数
- }
- }
- }
利用jdk的反射,我们获取不到方法的参数名称,也就是public void Test(String s){...}
现在我们能获取到String类型,但是如果想获取这个s,利用jdk的反射是获取不到的,所以我们借助第三方jar包 javassist,这个jar包是对java反射的增强。下载地址百度找吧,如果找不到,可以去这个地址找 https://jarfiles.pandaidea.com/ 这是个很不错网站 大家可以收藏~就不用到处去求包了。下面是利用javassist来获取方法参数名称。
- /**
- * 利用javassist获取方法参数名称
- * @throws Exception
- */
- @org.junit.Test
- public void testGetParam() throws Exception{
- Class clazz = Class.forName("com.test.TestAction");
- String methodName = "TestAnno";
- ClassPool pool=ClassPool.getDefault();
- CtClass ctClass = pool.get("com.test.TestAction");
- CtMethod ctMethod = ctClass.getDeclaredMethod(methodName);
- MethodInfo methodInfo = ctMethod.getMethodInfo();
- CodeAttribute codeAttr = methodInfo.getCodeAttribute();
- LocalVariableAttribute attr = (LocalVariableAttribute) codeAttr.getAttribute(LocalVariableAttribute.tag);
- if(attr==null){
- System.out.println("没有属性");
- }
- String[] paramsName = new String[ctMethod.getParameterTypes().length];
- int pos =Modifier.isStatic(ctMethod.getModifiers())?0:1;
- for (int i = 0; i < paramsName.length; i++)
- {
- paramsName[i] = attr.variableName(i+pos);
- }
- for (int i = 0; i < paramsName.length; i++)
- {
- System.out.println(paramsName[i]);
- }
- }
这样我们就能获取到方法所需要的一切了。然后通过反射的invoke来调用方法就可以了。下面演示一下怎么使用invoke来调用方法及传参。
首先我们新建一个测试类。我们来调用这个类的say方法
- package com.test;
- public class TestInvoke {
- public void say(String i ){
- System.out.println(i);
- }
- }
然后我们在junit测试里添加测试方法。
- /**
- * 测试方法调用
- * @throws Exception
- */
- @org.junit.Test
- public void testInvoke() throws Exception{
- Class clazz = Class.forName("com.test.TestInvoke");
- Object obj = clazz.newInstance();
- /**
- * getMethod(方法名,方法参数类型).invoke(调用类的实例,方法参数);
- */
- clazz.getMethod("say", String.class).invoke(obj, "this is a test");
- }
在控制台会打出this is a test。
在补充一个反射的用法。获取类的属性,属性的类型。
- /**
- * 获取类的field 和类型
- * @throws Exception
- */
- @org.junit.Test
- public void testFieldType() throws Exception
- {
- Class clazz = Class.forName("com.test.User");
- Object o = clazz.newInstance();
- Field[] fields = clazz.getDeclaredFields();
- for (Field f : fields)
- {
- System.out.println(f.getName());
- System.out.println(f.getType());
- /**
- 控制台打印:
- username
- class java.lang.String
- password
- class java.lang.String
- */
- }
- }
总结一下,通过今天的学习我们都得到了什么。
1.通过annotation,我们可以获得注解的名称,以及其他属性,以及注解的方法
2.通过反射:我们可以获得一个类都有哪些方法,方法的参数类型,类的属性,类属性的类型。不知道这么说大家能不能明白。下面截个图给大家看一下。
可以看到 画方框的,我们通过反射(javassist)都可以获取到,既然我们都能获取到,那我们是不是就能封装,转发调用了呢?
一个简单的mvc就用到这些技术,所以上面这些看懂了的话,你也能写一个mvc了。
给大家留一个问题:
怎么通过反射把页面传过来的参数 user 封装起来。
如果你能封装起来,我想就能通过invoke来调用action参数了吧?
如果不明白没问题,我后面会教大家怎么做。如果会的话,就继续做用invoke来调用action方法吧。
提示:
1.反射
2.request.getParameterMap
写这么多实在太累了。。。
明天可能会有一更,周五至周末要去参加婚礼,所以没时间更了。。。
希望大家把代码都自己写一遍。不要copy。能记住才是自己的。。。
谢谢观看。。。
ps:有多少人看?
大家一起写mvc(二)的更多相关文章
- 手写MVC框架(二)-代码实现和使用示例
--------上一篇:手写MVC框架(一)-再出发----- 背景 书接上文,之前整理了实现MVC框架需要写哪些东西.这周粗看了一下,感觉也没多少工作量,所以就计划一天时间来完成.周末的时间,哪会那 ...
- 七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递
通过第一天的学习之后,我们相信您已经对MVC有一些基本了解. 本节所讲的内容是在上节的基础之上,因此需要确保您是否掌握了上一节的内容.本章的目标是在今天学习结束时利用最佳实践解决方案创建一个小型的MV ...
- 七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递 【转】
http://www.cnblogs.com/powertoolsteam/p/MVC_two.html 通过第一天的学习之后,我们相信您已经对MVC有一些基本了解. 本节所讲的内容是在上节的基础之上 ...
- 手写MVC框架(一)-再出发
背景 前段时间把之前写的DAO框架(手写DAO框架(一)-从“1”开始)整理了一下,重构了一版.整理过程中看以前写的代码,只是为了了解实现,只是为了实现,代码写的有点粗糙.既然已经整理了DAO框架,索 ...
- 60行以内写mvc
标题党.几天前看到一个30行写mvc的文章,东施效颦,也动手写了个60行的,功能上略微扩充一些,记录下来,后面有时间可以继续优化. mvc其实是一个观察者模式.view来监听model,所以当mode ...
- paip.简化字-手写参考二简字..共98个
paip.简化字-手写参考二简字..共98个 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog.csdn.net/a ...
- 大家一起写mvc(三)_结束
上一篇介绍到要写mvc的所用的核心技术,这一篇我们就开始真正的开始写mvc,其实就是把昨天写过的代码进行一些组装就可以了. 我们用eclipse新建一个web项目.然后web.xml如下 <?x ...
- 源码分析系列 | 从零开始写MVC框架
1. 前言 2. 为什么要自己手写框架 3. 简单MVC框架设计思路 4. 课程目标 5. 编码实战 5.1 配置阶段 web.xml配置 config.properties 自定义注解 5.2 初始 ...
- Spring MVC(二)--Spring MVC登陆实例
本文通过一个简单的登陆实例实现Spring MVC的流程,同时整合 MyBatis使用,流程是这样的: 1.访问一个URL进入登陆界面 2.输入正确的用户名和密码,成功则进入index页面,否则留在登 ...
随机推荐
- tabbar底部标题和子控制器标题为什么会保持一致?
原因: 1.当self.navigationItem.title,self.tabBarItem.title没有赋值情况下值和self.title一致. 2.当切换到该控制器页面的时候自己设置的sel ...
- jquery星级评论打分组件
<!DOCTYPE HTML><html> <head> <meta charset="utf-8"><title>jq ...
- linux 系统下开机自动启动oracle 监听和实例 (亲测有效)
[oracle@oracle11g ~]$ dbstartORACLE_HOME_LISTNER is not SET, unable to auto-start Oracle Net Listene ...
- 本地调试webapi
1.新建iis站点,路径关联到代码站点下D:\work\易解科技\程序源码\YQJ\trunk\YQJOpenAPI\YQJOpenAPI 2.vs以管理员身份启动 3.附加到进程 w3wp.exe ...
- 关于MySql数据库设计表与查询耗时分析
本地建一张表persons,使用脚本插入了1000万条数据 下面比较几种查询方法的耗时(查询9000000到9000005这中间5条数据) 查询结果: 1: SELECT * FROM test.pe ...
- JS-字符串操作,查找显示高亮
<!DOCTYPE HTML><html><head><meta http-equiv="Content-Type" content=&q ...
- cach
为程序使用内存缓存(MemoryCache) oscache Guava cache 一种解决方法是配一个listener,在里面启动定时器. 简单缓存可以封装LinkedHashMap,因为它是有顺 ...
- python基础语法(2)
2. 元组 tuple和list十分相似,但是tuple是不可变的,即不能修改tuple,元组通过圆括号中用逗号分割的项定义:支持索引和切片操作:可以使用 in 查看一个元素是否在tuple中.空元组 ...
- 【动态规划】bzoj1669 [Usaco2006 Oct]Hungry Cows饥饿的奶牛
#include<cstdio> #include<algorithm> using namespace std; int n,a[5001],b[5001],en; int ...
- Powershell-入门
什么是Powershell 中文博客:http://www.pstips.net/ 百度百科:是一种命令行外壳程序和脚本环境,使命令行用户和脚本编写者可以利用 .NET Framework 的强大功能 ...