大家一起写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://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>kis</display-name>
  <welcome-file-list>
    <welcome-file>index.jsp</welcome-file>
  </welcome-file-list>
<!-- 配置action拦截器 -->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>com.keepitsimple.core.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>scan_package</param-name>
            <param-value>com.mvc</param-value>
        </init-param>
    </servlet>

    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>*.action</url-pattern>
    </servlet-mapping>
<!-- 配置action拦截器 -->
</web-app>

在web.xml里我们配置一个servlet拦截器。拦截所有的action请求。然后init-param里配置一下action所在路径,我们要进行自动扫描。这个功能就类似与spring的自动扫描装备功能。用的好像也是我们用到的写法。

然后就开始写这个servlet

在这个servlet里我们实现doGet,doPost方法,还有init方法。

init方法呢,主要作用就是装配扫描bean

代码片段如下:

@Override
    public void init(final ServletConfig config) throws ServletException
    {
        // TODO Auto-generated method stub
        super.init(config);
        String scan_package = config.getInitParameter("scan_package");
        DispatcherServletHelper.init(scan_package);
    }

可以看到,这里这里通过config.getinitParameter("scan_packge")读取web.xml中的initparam。也就是扫描包的路径。

在各种跳转过程中,我们需要一个java bean来装一些我们需要的参数。

package com.keepitsimple.core;

public class ActionContext{
    private String URL;   //调用的url,也就是actionname
    private String methodName;  //调用的方法名称
    private Class<?> cla;   //调用方法的类名
    private Object action;//类的实例
    private String result;//返回结果
    private Class<?>[] paramsType;// 调用方法的参数类型
    private String[] actionParamsName;//调用的方法参数的名称

    //getter and setter

然后我们定义一下自定义注解,让方法只扫描我们注解了的类。

package com.keepitsimple.core;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documented()
public @interface ActionAnnotate
{
 String ActionName() default "";
 String Result() default "";
}

然后我们调用Helper的init方法。init方法主要就是把上面这个类填充。初始化装载所有的action。

package com.keepitsimple.core;

import java.io.File;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;

import javassist.ClassClassPath;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.Modifier;
import javassist.bytecode.CodeAttribute;
import javassist.bytecode.LocalVariableAttribute;
import javassist.bytecode.MethodInfo;

public final class DispatcherServletHelper {

    public static Map<String, ServletListenerBean> urls = null;

    // public DispatcherServletHelper()
    // {
    // getURLs();
    // }

    public static void init(String scan_package)
    {
        if (null == scan_package || scan_package.length() <= 0)
            System.out.println("正在扫描classpath....");
        urls = new HashMap<String, ServletListenerBean>();
        String result = DispatcherServletHelper.class.getResource("/").toString().replace("file:/", "").replace("%20", "");
        try
        {
            assembleBean(result, result.replace("/", "\\"), scan_package);
        } catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    /**
     * 扫描该路径下 所有的class文件 then 装配bean
     *
     * @param realPath
     * @param root
     *            真实路径 E:\\GitHome\\kis\\build\\classes\     * @param scan_package
     *            扫描的包
     * @return
     * @throws Exception
     * @throws
     */
    public static String assembleBean(String realPath, String root, String scan_package) throws Exception
    {
        File file = new File(realPath);
        if (file.isDirectory())
        {
            for (File f : file.listFiles())
            {
                if (f.isDirectory())
                {
                    assembleBean(f.getAbsolutePath(), root, scan_package);
                } else
                {
                    String classPath = f.getAbsolutePath().replace("\\", ".");
                    int len = classPath.length();
                    if (len > 6 && classPath.endsWith(".class"))
                    {
                        if(null!=scan_package&&scan_package.length()>0&&classPath.indexOf("classes."+scan_package)>=0){
                            classPath = classPath.substring(8+classPath.indexOf("classes."+scan_package));
                        }else{
                            continue;
                        }
                        String className = classPath.substring(0, classPath.length() - 6);
                        Class<?> clazz = Class.forName(className);
                        Method[] methods = clazz.getDeclaredMethods();
                        for (Method method : methods)
                        {
                            if (method.isAnnotationPresent(com.keepitsimple.core.ActionAnnotate.class))
                            {
                                com.keepitsimple.core.ActionAnnotate actionAnno = method.getAnnotation(com.keepitsimple.core.ActionAnnotate.class);
                                if (urls.containsKey(actionAnno.ActionName()))
                                {
                                    throw new RuntimeException("重复路径" + clazz + ":" + actionAnno.ActionName());
                                } else
                                {
                                    ActionContext bean = new ActionContext ();
                                    bean.setCla(clazz);
                                    bean.setMethodName(method.getName());
                                    bean.setURL(actionAnno.ActionName());
                                    bean.setResult(actionAnno.Result());
                                    bean.setAction(clazz.newInstance());
                                    bean.setParamsType(method.getParameterTypes());
                                    bean.setActionParamsName(Utils.getParamNames(clazz, method.getName()));
                                    urls.put(actionAnno.ActionName(), bean);
                                }
                            }
                        }
                    }
                }
            }
        }
        return "";
    }

}

上面这段代码就是整个的helper类。通过扫描文件然后装配bean。

现在这个mvc的初始化就完成了。这个里面有不少问题。希望大家能够发现,并且尝试改一下。(注1)

doGet方法我们就直接调用doPost来处理

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        doPost(request, response);
    }

doPost方法

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        request.setCharacterEncoding("utf-8");
        String path = request.getServletPath();// 获取请求action /addUser.action
        path = path.substring(1);// addUser.action
        if (DispatcherServletHelper.urls.containsKey(path))
        {
            ActionContext bean = DispatcherServletHelper.urls.get(path);
            Class<?> cla = bean.getCla();
            Object actionObject = bean.getAction();
            if (bean.getParamsType() != null)
            {
                BeanUtils beanUtils = new BeanUtils();
                Object[] params = beanUtils.getMethodParam(request, bean.getParamsType(),bean.getActionParamsName());//这里就是封装jsp传过来的参数
                System.out.println("action方法名:" + bean.getMethodName());
                System.out.println("方法参数属性:" + bean.getParamsType());
                System.out.println("action实体类:" + actionObject);
                System.out.println("action方法参数:" + params);
                try
                {
                    cla.getMethod(bean.getMethodName(), bean.getParamsType()).invoke(actionObject, params);//反射调用action方法
                } catch (IllegalArgumentException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (SecurityException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (IllegalAccessException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (InvocationTargetException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (NoSuchMethodException e)
                {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            } if (bean.getResult() != null)
            {
                request.getRequestDispatcher(bean.getResult()).forward(request, response);
            }
        }
    }

下面我们看看怎么来封装方法所需要的参数。

package com.keepitsimple.core;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;

import javax.servlet.http.HttpServletRequest;

public class BeanUtils<T> {

    private static Map<Class<?>, Class<?>> classMap = new HashMap<Class<?>, Class<?>>();
    static
    {
        classMap.put(int.class, Integer.class);
        classMap.put(short.class, Short.class);
        classMap.put(long.class, Long.class);
        classMap.put(float.class, Float.class);
        classMap.put(double.class, Double.class);
        classMap.put(char.class, Character.class);
        classMap.put(boolean.class, Boolean.class);
        classMap.put(byte.class, Byte.class);
        classMap.put(Integer.class, Integer.class);
        classMap.put(Short.class, Short.class);
        classMap.put(Long.class, Long.class);
        classMap.put(Float.class, Float.class);
        classMap.put(Double.class, Double.class);
        classMap.put(Character.class, Character.class);
        classMap.put(Boolean.class, Boolean.class);
        classMap.put(Byte.class, Byte.class);
        classMap.put(String.class, String.class);
    }

    public Object[] getMethodParam(HttpServletRequest request, Class<?>[] paramsType, String[] actionParamsName)
    {
        Object[] params = new Object[actionParamsName.length];
        for (int i = 0; i < actionParamsName.length; i++)
        {
            Map<String, String[]> requestMap = request.getParameterMap();
            Iterator<Entry<String, String[]>> it = requestMap.entrySet().iterator();
            try
            {
                Object object = paramsType[i].newInstance();
                while (it.hasNext())
                {
                    System.out.println(i);
                    if (isBasicType(paramsType[i]))
                    {
                        Entry<String, String[]> entry = it.next();
                        String value = "";
                        for (String s : entry.getValue())
                        {
                            value += s;
                        }
                        if (entry.getKey().equals(actionParamsName[i]))
                        {
                            params[i] = basicType(paramsType[i], value);

                        }
                    } else
                    {
                        Field[] fields = paramsType[i].getDeclaredFields();
                        Entry<String, String[]> entry = it.next();
                        String paramName;
                        String value = "";
                        for (String s : entry.getValue())
                        {
                            value += s;
                        }
                        if (entry.getKey().indexOf(".") > 0 && entry.getKey().split("\\.")[0].equals(actionParamsName[i]))
                        {
                            for (Field field : fields)
                            {
                                if (field.getName().equals(entry.getKey().split("\\.")[1]))
                                {
                                    paramName = entry.getKey().split("\\.")[1];
                                    String methodName = "set" + toFirstLetterUpperCase(paramName);
                                    paramsType[i].getMethod(methodName, field.getType()).invoke(object, value);
                                }
                            }
                            params[i] = object;
                        }
                    }
                }
            } catch (InstantiationException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SecurityException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvocationTargetException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchMethodException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return params;
    }

    private boolean isBasicType(Class clazz)
    {
        if (clazz.equals(int.class) || clazz.equals(Integer.class))
        {
            return true;
        } else if (clazz.equals(short.class) || clazz.equals(Short.class))
        {
            return true;
        } else if (clazz.equals(long.class) || clazz.equals(Long.class))
        {
            return true;
        } else if (clazz.equals(float.class) || clazz.equals(Float.class))
        {
            return true;
        } else if (clazz.equals(double.class) || clazz.equals(Double.class))
        {
            return true;
        } else if (clazz.equals(char.class) || clazz.equals(Character.class))
        {
            return true;
        } else if (clazz.equals(boolean.class) || clazz.equals(Boolean.class))
        {
            return true;
        } else if (clazz.equals(byte.class) || clazz.equals(Byte.class))
        {
            return true;
        } else if (clazz.equals(String.class))
        {
            return true;
        } else
        {
            return false;
        }
    }
    /**
     * 基础数据绑定
     * @param class1
     * @param value
     * @return
     */
    private Object basicType(Class<?> class1, String value)
    {
        if (isBasicType(class1))
        {
            Class<?> newClass = classMap.get(class1);
            if (newClass.equals(Integer.class))
            {
                return Integer.parseInt(value);
            } else if (newClass.equals(Short.class))
            {
                return Short.parseShort(value);
            } else if (newClass.equals(Long.class))
            {
                return Long.parseLong(value);
            } else if (newClass.equals(Float.class))
            {
                return Float.parseFloat(value);
            } else if (newClass.equals(Double.class))
            {
                return Double.parseDouble(value);
            } else if (newClass.equals(Character.class))
            {
                return value.toCharArray()[0];
            } else if (newClass.equals(Boolean.class))
            {
                return Boolean.parseBoolean(value);
            } else if (newClass.equals(Byte.class))
            {
                return Byte.parseByte(value);
            } else
            {
                return value;
            }
        } else if (class1.equals(java.util.Date.class))
        {
            try
            {
                if (value.indexOf(":") == -1)
                {
                    return new SimpleDateFormat("yyyy-MM-dd").parse(value);
                } else
                    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(value);
            } catch (Exception e)
            {
                e.printStackTrace();
                return null;
            }
        } else
        {
            return class1.cast(value);
        }
    }
    /**
     * 转换String的第一个字母
     * @param s
     * @return
     */
    public String toFirstLetterUpperCase(String s)
    {
        if (s.length() == 1)
        {
            return s.toUpperCase();
        } else if (s == null || s.length() == 0)
        {
            return "";
        } else
        {
            return s.substring(0, 1).toUpperCase() + s.substring(1);
        }
    }

}

上面这段基本都是昨天的代码。利用反射来进行封装,这里面基础数据只做了简单的封装。还不是很完整,

关于getMethodParam()方法,你们可以借助于commons-beanutils.jar包来实现,用这个方法比较简单。

但是这里为了加强大家对反射的理解跟应用,我就采用了反射来做。

刚才我的注1那里,主要的问题是,这个ActionContext是否是线程安全,是否还能改装?还有一个问题是 如果 一个action要有多种跳转结果怎么办?

至此,我们就实现了一个最简单的mvc功能。现在把他添加到tomcat里。就可以运行自己的mvc了。

这mvc系列到这就结束了,剩下的就是一些细节的处理。

这个mvc我也在写 也在一直完善。

上面的代码,大家可以在我的git里check出来。并且实现了action多个跳转结果。希望大家自己想想怎么实现。自己去实现,如果不能实现在check out我的代码。

https://git.oschina.net/sum/kis.git

关于git工具。大家可以看我的上一篇博文,里面有介绍GIT工具。

这里面大家有不明白的可以给我留言,一定会积极回复。

谢谢大家

The End

时间: 2024-08-10 02:53:12

大家一起写mvc(三)_结束的相关文章

基于j2ee的程序代写MVC架构

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

大家一起写mvc(二)

上一篇已经看了,我想大家都明白了mvc的原理,今天我们来说一下要写自己mvc框架必须要会的技术. mvc的目录是这样的 src目录是我们核心的mvc代码.这个代码明天讲,今天主要讲的代码都在test目录下. 在第一章我已经说了,写mvc技术需要用的就是java的反射原理,还有自定义注解. 现在我们先讲一下注解的用处,可能这个自定义注解听着挺高深的,等你看完这个就会明白,其实很简单,就是xml的另一种方法. 讲解我就都放在代码的注解里了,这样写比较方便. annotation注解: package

跟我一起写操作系统(三)——打印函数和qemu虚拟机

转载注明出处:http://www.cnblogs.com/lucasysfeng/p/4847662.html 上一讲地址:http://www.cnblogs.com/lucasysfeng/p/4847662.html 项目地址:https://github.com/lucasysfeng/lucasOS 本讲主要涉及以下三个方面:1. 打印函数封装:2. qemu的使用:3. 项目目录结构调整. 理由如下:1. 后续开发无疑会遇到打印变量的操作,因此有必要封装打印函数(内核开发阶段,无法

MVC 三步完成增删改查设计

1.添加模型类: public class Product { public int Id { get; set; } public string Name { get; set; } public string Category { get; set; } public decimal Price { get; set; } } 2.添加上下文类: public class ProductContext : DbContext { public ProductContext() : base(

大家一起写mvc(一)

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

七天学会ASP.NET MVC (三)——ASP.Net MVC 数据处理

注:本文为学习摘录,原文地址为:http://www.cnblogs.com/powertoolsteam/p/MVC_three.html 目录: 数据访问层 实体框架(EF)简述 什么是代码优先的方法? 实验8——在项目中添加数据访问层 关于实验8 实验9——创建数据输入屏幕 实验10——获取服务端或控制器端传递的数据. 实验11——重置及取消按钮 实验12——保存数据.库记录并更新表格 实验13——添加服务器端验证 实验14——自定义服务器端验证 结论 数据访问层 在实际开发中,如果一个项

跟我一起写Makefile(三)

书写规则---- 规则包含两个部分,一个是依赖关系,一个是生成目标的方法. 在Makefile中,规则的顺序是很重要的,因为,Makefile中只应该有一个最终目标,其它的目标都是被这个目标所连带出来的,所以一定要让make知道你的最终目标是什么.一般来说,定义在Makefile中的目标可能会有很多,但是第一条规则中的目标将被确立为最终的目标.如果第一条规则中的目标有很多个,那么,第一个目标会成为最终的目标.make所完成的也就是这个目标. 好了,还是让我们来看一看如何书写规则. 一.规则举例

MVC三个IOC注入点之Ninject使用示例

群里一个技术大牛说MVC有三个注入点,但我只会一个DefaultControllerFactory. 在群友的帮助下,我大致了解了下: IControllerFactory=>IDependencyResolver=>IControllerActivator 这三者的关系如下: 其实从上面的关系可以看出来这三个注入点,相互都存在依赖关系. 我们还是老规矩上代码: 1.IControllerFactory 注入: public class NInjectFactory:DefaultContro

S5PV210开发系列三_简易Bootloader的实现

S5PV210开发系列三 简易Bootloader的实现 象棋小子          1048272975 Bootloader是嵌入式系统上电后第一段执行的代码.对于功能简单的处理器,可能并没有Bootloader的概念,但对于应用处理器,有不同的启动方式,不同的存储设备(Nand flash.sd/mmc.DDR2.SRAM等),不同的操作系统等,往往需要一个Bootloader先初始化CPU和相关的硬件,建立内存空间映射,把内核或应用程序加载到相应的内存执行位置,最后调用内核或应用程序,释