`
Jatula
  • 浏览: 278395 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

运用Filter,ThreadLocal和Reflection,实现form到bean的填充

阅读更多

开发者在线 Builder.com.cn 更新时间:2008-02-28作者:Nurhachi Jang 来源:CSDN

做过web开发的人可能都有这种感觉,不时的需要从request中提取参数及数据,如果有一种方式可以省却这一步骤,是否会令你的开发工作更愉悦呢?本文在此做了如下的探讨。

很显然,从request中提取参数需要一个尽职尽责的,但是又很优雅的让我们感觉不到它的辛苦工作的模块来实现,它的任务就是,1)截取所有的 request,2)从request取出数据并填充到bean留给其他人使用。大概你也会想到Filter,它的特性符合要求。

Filter截取了请求如何处理呢? 我想到了2种方式(当然,还有其它的),

1)request参数需要指明本次提交的数据要填充至哪个bean,且参数与bean的field严格匹配,这样利用 Reflection ,取出bean的field,然后从request.getParameter(field)取得数据进行填充。
2)采取配置文件进行request 的form数据到bean的映射,方式也是采用Reflection来完成填充工作。

2种方式各有优缺点,方式1不够灵活,方式2则对于某些人看来则是烦琐,毕竟还需要配置,也失去了本文简化request form处理的目的。因此本人推荐第一种方式,即使存在某些情况,也可以在bean中增加新方法来处理。

数据的有效性检查也放在bean里做,将数据无效的信息放在bean的error hashmap里,在filter填充完bean后,检查bean是否有效,有无效的数据,则直接返回客户端;否则,调用chain.doFilter (request, response)继续处理,并将这个bean放入ThreadLocal中,留待后续class访问,当这个线程结束后,bean会被垃圾收集器清除。

Filter样例:

/*
 * SimpleFilter.java
 *
 * Created on 2006年9月20日, 下午2:54
 */

package org.openthoughts.testings;

import Java.io.*;
import Java.lang.reflect.Field;
import Java.lang.reflect.InvocationTargetException;
import Java.lang.reflect.Method;
import Java.util.HashMap;
import javax.servlet.*;
import javax.servlet.http.*;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.openthoughts.util.Form2BeanUtil;

/**
 * Stuff a bean specified by request with form data.
 *
 * @author <a href="guangquanzhang@gmail.com">javafuns</a>
 * @version
 */

public class SimpleFilter implements Filter {
   
    // The filter configuration object we are associated with.  If
    // this value is null, this filter instance is not currently
    // configured.
    private FilterConfig filterConfig = null;
   
    public SimpleFilter() {
    }
   
    /**
     * Init method for this filter
     *
     */
    public void init(FilterConfig filterConfig) {
        this.filterConfig = filterConfig;
    }
 /**
     * Do actual work for filling.
     *
     * @param request The servlet request we are processing
     * @param result The servlet response we are creating
     * @param chain The filter chain we are processing
     *
     * @exception IOException if an input/output error occurs
     * @exception ServletException if a servlet error occurs
     */
    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain)
            throws IOException, ServletException {
        String beanName = ((HttpServletRequest)request).getParameter("formbean");
System.err.println(" form bean is " + beanName);
        Class beanClazz = null;
        Object beanObject = null;
        boolean isValid = false;
       
        if(beanName != null) {
            try {
                beanClazz = Class.forName(beanName);
                if(beanClazz != null) {
                    beanObject = beanClazz.newInstance();
                }
            } catch (ClassNotFoundException ex) {
                request.setAttribute("MainErrMsg", beanName + " not found");
                this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                return;
            } catch (InstantiationException ex) {
                request.setAttribute("MainErrMsg", beanName + " can not be instantiated");
                this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                return;
            } catch (IllegalAccessException ex) {
                request.setAttribute("MainErrMsg", beanName + " not access");
                this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                return;
            }
        }
               
        if(beanObject != null) {
            Field[] fields = beanClazz.getDeclaredFields();

            for(Field field : fields) {
                Method beanMethod = null;
                String fieldName = field.getName();
                String fieldValue = ((HttpServletRequest)request).getParameter(fieldName);
                StringBuilder sb = new StringBuilder();
                sb.append("set");
                sb.append(fieldName.substring(0, 1).toUpperCase());
                sb.append(fieldName.substring(1));
               
                try {
                    beanMethod = beanClazz.getDeclaredMethod(sb.toString(), String.class);
                } catch (SecurityException ex) {
                    request.setAttribute("MainErrMsg", " Security reason ");
                    this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                    return;
                } catch (NoSuchMethodException ex) {
                    request.setAttribute("MainErrMsg", beanName + " does not have method named " + sb.toString());
                    this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                    return;
                }

if(beanMethod != null) {
                    try {
                        beanMethod.invoke(beanObject, fieldValue);
                    } catch (IllegalArgumentException ex) {
                        request.setAttribute("MainErrMsg", "illegal argument for the method " + sb.toString() + " of " + beanName);
                        this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                        return;
                    } catch (InvocationTargetException ex) {
                        request.setAttribute("MainErrMsg", beanName + " invoke target exception ");
                        this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                        return;
                    } catch (IllegalAccessException ex) {
                        request.setAttribute("MainErrMsg", beanName + " illegal access to " + sb.toString());
                        this.filterConfig.getServletContext().getRequestDispatcher("/index.jsp").forward(request, response);
                        return;
                    }
                }
            }
            Form2BeanUtil.put(beanObject);
           
            Method getAllErrors = null;
            try {
                getAllErrors = beanClazz.getDeclaredMethod("getAllErrors");
            } catch (SecurityException ex) {
                System.err.println("Security exception when call getAllErrors()");
            } catch (NoSuchMethodException ex) {
                System.err.println("No such method named getAllErrors()");
            }
           
            if(getAllErrors != null) {
                try {
                    isValid = ((HashMap)getAllErrors.invoke(beanObject)).isEmpty();
                } catch (IllegalArgumentException ex) {
                    System.err.println("Illegal argument for getAllErrors()");
                } catch (IllegalAccessException ex) {
                    System.err.println("Illegal Access to getAllErrors()");
                } catch (InvocationTargetException ex) {
                    System.err.println("Invocation target exception");
                }
            }
        }
       
        if(beanName == null || isValid) {
            chain.doFilter(request, response);
        } else {
            if(beanObject != null) {
                request.setAttribute("formbean", beanObject);
            }
            this.filterConfig.getServletContext().getRequestDispatcher(getRequestURI(request)).forward(request, response);
        }
    }

    /**
     * Destroy method for this filter
     *
     */
    public void destroy() {
    }

    public String getRequestURI(ServletRequest request) {
        String requestURI = ((HttpServletRequest)request).getRequestURI();
        String queryString = ((HttpServletRequest)request).getQueryString();
        return requestURI + queryString;
    }
   
    /**
     * Return a String representation of this object.
     */
    public String toString() {
       
        if (filterConfig == null) return ("SimpleFilter()");
        StringBuffer sb = new StringBuffer("SimpleFilter(");
        sb.append(filterConfig);
        sb.append(")");
        return (sb.toString());
    }

}

Bean样例:

/*
 * SimpleBean.java
 *
 * Created on 2006年9月20日, 下午5:51
 */

package org.openthoughts.beans;

import Java.io.Serializable;
import Java.util.HashMap;

/**
 * @author Administrator
 */
public class SimpleBean implements Serializable {
   
    private String userName;
   
    private String password;
   
    public SimpleBean() {
       
    }
   
    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;
    }
   
    //错误信息
    public HashMap getAllErrors() {
        return new HashMap();
    }
}



ThreadLocal实现:

/*
 * Form2BeanUtil.java
 *
 * Created on 2006年9月20日, 下午4:51
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.openthoughts.util;

/**
 * Hold formbean for appropriate thread via ThreadLocal.
 *
 * @author <a href="guangquanzhang@gmail.com">javafuns</a>
 */
public class Form2BeanUtil {
   
    private static final ThreadLocal container = new ThreadLocal();
   
    /**
     * Put the form bean to ThreadLocal.
     */
    public static void put(Object object) {
        container.set(object);
    }
   
    /**
     * Get the current thread's form bean.
     */
    public static Object get() {
        return container.get();
    }
}


PS: 类似的方式在很多框架都有实现,比如struts的formbean

分享到:
评论

相关推荐

    ThreadLocal应用示例及理解

    假设我们需要一个线程安全的计数器,可以使用ThreadLocal实现: ```java public class ThreadLocalCounter { private static ThreadLocal&lt;Integer&gt; counter = new ThreadLocal(); public static void increment...

    ThreadLocal

    - 不是线程安全的:尽管ThreadLocal提供了线程隔离,但它本身并不保证线程安全性,如果在`set`和`get`操作之间有其他线程修改了ThreadLocal实例,仍需进行同步控制。 在使用ThreadLocal时,理解其工作原理和限制是...

    线程ThreadLocal机制实现例子

    本例以序列号生成的程序为例,展示ThreadLocal的使用

    从ThreadLocal的使用到Spring的事务管理

    结合ThreadLocal和Spring事务管理,我们可以在多线程环境中实现高效且一致的业务处理。例如,Spring在处理每个HTTP请求时,会为每个请求分配一个单独的线程。我们可以通过ThreadLocal来保存请求相关的状态信息,而...

    ThreadLocal和事务

    通过ThreadLocal,我们可以确保每个请求的Model层操作都在自己的事务范围内,这样即使在处理过程中出现异常,也不会影响到其他请求的事务状态,从而实现了MVC三层结构之间的良好隔离。 总结来说,这个小型练习展示...

    事务的封装和Threadlocal实例

    总的来说,结合JDBC的事务管理和ThreadLocal,我们可以在多线程环境中更好地实现数据库操作,确保数据的一致性,并提高代码的可复用性和安全性。通过使用ThreadLocal,我们可以创建线程安全的变量,使得每个线程都能...

    java事务 - threadlocal

    Java事务和ThreadLocal是两种在Java编程中至关重要的概念,它们分别用于处理多线程环境下的数据一致性问题和提供线程局部变量。 首先,我们来深入理解Java事务。在数据库操作中,事务是一系列操作的集合,这些操作...

    ThreadLocal整理.docx

    ThreadLocal 的工作机制是通过计算Hash值来确定在数组中的下标位置,然后将对应的 key 和 value 存储在数组中。 在 ThreadLocal 中,解决 Hash 冲突的机制是通过斐波那契数来实现的,使得 Hash 值均匀分布在数组...

    threadLocal

    在Java的`ThreadLocal`实现中,每个线程都有一个`ThreadLocalMap`,它是`ThreadLocal`的一个内部类,用于存储线程局部变量。`ThreadLocalMap`使用弱引用作为键,目的是在线程不再引用ThreadLocal对象时,允许垃圾...

    java 简单的ThreadLocal示例

    Java中的ThreadLocal是一个非常重要的工具类,它在多线程编程中扮演着独特角色,尤其在处理线程间数据隔离和共享时。ThreadLocal不是线程本身,而是为每个线程提供一个独立的变量副本,使得每个线程都可以独立地改变...

    JDK的ThreadLocal理解(一)使用和测试

    **标题:“JDK的ThreadLocal理解(一)使用和测试”** **正文:** ThreadLocal是Java中的一个非常重要的线程安全工具类,它在多线程编程中扮演着独特的角色。通过创建ThreadLocal实例,我们可以为每个线程提供一个...

    Synchronized与ThreadLocal

    ### Synchronized与ThreadLocal #### 一、Synchronized机制详解 **Synchronized** 是 Java 中一个非常重要的关键字,主要用于实现线程同步。它通过在对象上加锁来确保多个线程能够安全地访问共享资源。 - **作用...

    ThreadLocal原理及在多层架构中的应用.pdf

    在Java中,ThreadLocal被广泛应用于Web中间件、服务端编程和微服务架构中,用以解决多线程环境下的数据隔离问题。 首先,ThreadLocal原理是基于每个线程创建一个私有的数据存储结构(ThreadLocalMap),使得线程...

    ThreadLocal的几种误区

    ThreadLocal是Java编程中一种非常特殊的变量类型,它主要用于在多线程环境下为每个线程提供独立的变量副本,从而避免了线程间的数据共享和冲突。然而,ThreadLocal在理解和使用过程中容易产生一些误区,这里我们将...

    理解ThreadLocal

    理解ThreadLocal 理解ThreadLocal 理解ThreadLocal 理解ThreadLocal

    设计模式及ThreadLocal资料

    设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的模板。...在实际开发中,灵活运用设计模式可以提高代码质量,而ThreadLocal则为处理多线程环境下的数据隔离提供了一种有效手段。

    java中ThreadLocal详解

    接着,将`ThreadLocal`对象作为键,对应的值作为值,存储到`ThreadLocalMap`中。 #### 四、ThreadLocal的内存泄漏问题及其解决方案 尽管使用弱引用来避免内存泄漏,但在某些情况下,仍然可能引起内存泄漏。例如,...

Global site tag (gtag.js) - Google Analytics