大家一起写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:有多少人看?

时间: 2024-10-12 13:07:48

大家一起写mvc(二)的相关文章

基于j2ee的程序代写MVC架构

人力资源管理系统 完成系统静态页面设计,页面数量不少于10个,页面需用CSS进行美化,并为需要验证的信息利用JavaScript提供客户端验证.要求至少包含部门信息及部门内员工信息的添加.修改.删除和查询以及员工培训信息维护等功能页. 35 页面内容饱满.页面数量超过15个 设计数据库表部门信息表.员工信息表及员工培训信息表至少三张表,数据库信息设计合理.基于第一次作业所做静态页面使用JSP+JavaBean实现部门信息及部门内员工信息的添加.修改.删除和查询以及员工培训信息维护等功能. 40

大家一起写mvc(三)_结束

上一篇介绍到要写mvc的所用的核心技术,这一篇我们就开始真正的开始写mvc,其实就是把昨天写过的代码进行一些组装就可以了. 我们用eclipse新建一个web项目.然后web.xml如下 <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://j

ASP.NET MVC (二)——ASP.NET MVC 数据传递

一.Controller与 View之间的值传递 1.View将从从Controller获得Model中的数据. Model是MVC中 表示业务数据的层. 2.ViewData相当于数据字典,包含Controlle和View之间传递的所有数据.Controller会在该字典中添加新数据项,View从字典中读取数据. 二.使用View数据 1. 创建Model 类,在Model文件夹下新建Employee类 2. 在Controller 中获取Model,在GetView 方法中创建Employe

Spring MVC(二)--Spring MVC登陆实例

本文通过一个简单的登陆实例实现Spring MVC的流程,同时整合 MyBatis使用,流程是这样的: 1.访问一个URL进入登陆界面 2.输入正确的用户名和密码,成功则进入index页面,否则留在登陆页 一.配置web.xml 创建好WEB项目之后的第一步就是配置web.xml文件 1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app version="3.0" xmlns=&

关爱码农成长:关于写代码二三事

工作这么多年以来,一直从事软件相关领域,即使担任主管职务,也一直对技术充满热情.写代码写了这么多年,多少有些体会.我把自己对写代码这份工作的心得写下来,希望能给从事相关领域或有志于写代码的人参考. 一.你适合当程序员吗? 程序员,也叫软件工程师.程序设计师,我觉得「程序员」三个字简洁有力,是一种身份的象征. 如果你正从事这份工作,恭喜你!这是个热门行业,在可预见的将来,也不会消失.不过也别高兴太早,这一行的技术汰旧换新非常快,必须不断努力学习才行. 一点天赋 打开一个空白文档,必须创造出代码.与

大家一起写mvc(一)

关于java的mvc框架层出不穷,可能大家都会用,但是具体的原理知道不知道呢.所以我想写一个写一个简单mvc的系列博客,主要面向想了解这些原理的. 其实所谓的mvc框架,基本都是一个原理,就是配置一个filter或者servlet来拦截所有的请求,然后转发请求. 这个图就能说明mvc的工作模式 1.首先页面发送一个post请求,请求到某一个action. 2.然后由servlet或filter进行拦截,拦截固定后缀的请求,比如*.action,这里比如我们发送的请求是UserAction.act

ASP.NET MVC(二) 理解MVC

MVC模型同时提供对HTML.CSS以及JavaScript的完整控制. MVC模型通过三个逻辑层来定义WEB应用程序: (一)Business layer(业务层.模型逻辑) 模型(Model) 模型是应用程序中用于处理应用程序数据逻辑的部分 通常模型对象在数据库中存取数据. (二)Display layer(显示层.视图逻辑) View(视图) 是应用程序中处理数据显示的部分. 通常从模型数据中创建视图 (三)Input control (输入控件.控制器逻辑) 控制器(Controler)

七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递

注:本文为学习摘录,原文地址为:http://www.cnblogs.com/powertoolsteam/p/MVC_two.html Controller与 View之间的值传递 在上一节的实验二中已经创建了静态View.然而在实际使用情况下,View常用于显示动态数据.在实验三中们将在View中动态显示数据. View将从从Controller获得Model中的数据. Model是MVC中 表示业务数据的层. 实验3 ——使用View数据 ViewData相当于数据字典,包含Control

Spring MVC(二) HTTP请求数据的绑定

HTTP请求数据的绑定 通过注解绑定 @RequestParam-->绑定请求参.@RequestHeader-->绑定请求头参数.@CookieValue-->绑定Cookie的值.@PathVariable-->绑定URL中的 示例: @RequestMapping(value="/handle2")public String handle2(@CookieValue("JSESSIONID") String sessionId,@Req