struts2 模型驱动要注意的一个问题

本贴最后更新于 3719 天前,其中的信息可能已经时移世异

先来说一下模型驱动,在struts2的默认拦截器栈struts-default包中有一个 ModelDriverInterceptor拦截器,如果有我们的action实现ModerDriver接口,即可实现模型驱动。action如下代码

public abstract class BaseAction<T> extends ActionSupport implements ModelDriven<T>,SessionAware,ServletRequestAware{

/** model 的支持 */
protected T model;

public void setModel(T model) { this.model = model; } public BaseAction() { ParameterizedType genericSuperclass = (ParameterizedType) this.getClass().getGenericSuperclass(); Class&lt;T&gt; clazz=(Class&lt;T&gt;) (genericSuperclass.getActualTypeArguments()[0]); try { model=clazz.newInstance(); log.info(&quot;BaseAction model:&quot;+model); } catch (Exception e) { //throw new RuntimeException(e); } } @Override public T getModel() { return model; }<br />//部分代码省略<br />}</pre>

从代码上看,每次都new了一个对象, 如果我们用 XXXService.update(model)的话,会将空值、默认值也会更新进去,显示这不是我们想要的。
,可以采用这一种方式:先通过id查找到这个对象,然后将model的非空属性赋值给这个对象,最后更新对象。

public String edit() throws Exception {        
        log.info("修改用户:"+model);
        User u=userService.getById(model.getId());        
        if (StrUtils.notNull(model.getPassword())) {
            model.setPassword(DigestUtils.md5Hex(model.getPassword()));
        }
        BeanUtils.copyNotNullProperties(model, u);
        userService.update(u);

//省略部分代码...

}

最后上一个BeanUtils工具类:

package core.utils;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.FatalBeanException;
import org.springframework.util.Assert;

/**

  • 扩展 spring 的 BeanUtils,增加拷贝属性排除 null 值的功能(注:String 为 null 不考虑)
  • 扩展 Apache Commons BeanUtils, 提供一些反射方面缺失功能的封装.
  • @author shollin

/
public class BeanUtils extends org.springframework.beans.BeanUtils {
/
* logger. */
private static Logger logger = LoggerFactory.getLogger(BeanUtils.class);

/** getter prefix length. */

public static final int LENGTH_GETTER_PREFIX = "get".length();

/** 保护的构造方法. */
protected BeanUtils() {
}

public static void copyNotNullProperties(Object source, Object target, String[] ignoreProperties) throws BeansException { copyNotNullProperties(source, target, null, ignoreProperties); } public static void copyNotNullProperties(Object source, Object target, Class&lt;?&gt; editable) throws BeansException { copyNotNullProperties(source, target, editable, null); } public static void copyNotNullProperties(Object source, Object target) throws BeansException { copyNotNullProperties(source, target, null, null); } private static void copyNotNullProperties(Object source, Object target, Class&lt;?&gt; editable, String[] ignoreProperties) throws BeansException { Assert.notNull(source, &quot;Source must not be null&quot;); Assert.notNull(target, &quot;Target must not be null&quot;); Class&lt;?&gt; actualEditable = target.getClass(); if (editable != null) { if (!editable.isInstance(target)) { throw new IllegalArgumentException(&quot;Target class [&quot; + target.getClass().getName() + &quot;] not assignable to Editable class [&quot; + editable.getName() + &quot;]&quot;); } actualEditable = editable; } PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable); List&lt;String&gt; ignoreList = (ignoreProperties != null) ? Arrays.asList(ignoreProperties) : null; for (PropertyDescriptor targetPd : targetPds) { if (targetPd.getWriteMethod() != null &amp;&amp; (ignoreProperties == null || (!ignoreList.contains(targetPd.getName())))) { PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName()); if (sourcePd != null &amp;&amp; sourcePd.getReadMethod() != null) { try { Method readMethod = sourcePd.getReadMethod(); if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) { readMethod.setAccessible(true); } Object value = readMethod.invoke(source); if (value != null || readMethod.getReturnType().getName().equals(&quot;java.lang.String&quot;)) {// 这里判断以下value是否为空,当然这里也能进行一些特殊要求的处理 例如绑定时格式转换等等,如果是String类型,则不需要验证是否为空 boolean isEmpty = false; if (value instanceof Set) { Set s = (Set) value; if (s == null || s.isEmpty()) { isEmpty = true; } } else if (value instanceof Map) { Map m = (Map) value; if (m == null || m.isEmpty()) { isEmpty = true; } } else if (value instanceof List) { List l = (List) value; if (l == null || l.size() &lt; 1) { isEmpty = true; } } else if (value instanceof Collection) { Collection c = (Collection) value; if (c == null || c.size() &lt; 1) { isEmpty = true; } } if (!isEmpty) { Method writeMethod = targetPd.getWriteMethod(); if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) { writeMethod.setAccessible(true); } writeMethod.invoke(target, value); } } } catch (Throwable ex) { throw new FatalBeanException(&quot;Could not copy properties from source to target&quot;, ex); } } } } } /** * 循环向上转型,获取对象的DeclaredField. * * @param object * 对象实例 * @param propertyName * 属性名 * @return 返回对应的Field * @throws NoSuchFieldException * 如果没有该Field时抛出 */ public static Field getDeclaredField(Object object, String propertyName) throws NoSuchFieldException { Assert.notNull(object); Assert.hasText(propertyName); return getDeclaredField(object.getClass(), propertyName); } /** * 循环向上转型,获取对象的DeclaredField. * * @param clazz * 类型 * @param propertyName * 属性名 * @return 返回对应的Field * @throws NoSuchFieldException * 如果没有该Field时抛出. */ public static Field getDeclaredField(Class clazz, String propertyName) throws NoSuchFieldException { Assert.notNull(clazz); Assert.hasText(propertyName); for (Class superClass = clazz; superClass != Object.class; superClass = superClass .getSuperclass()) { try { return superClass.getDeclaredField(propertyName); } catch (NoSuchFieldException ex) { // Field不在当前类定义,继续向上转型 logger.debug(ex.getMessage(), ex); } } throw new NoSuchFieldException(&quot;No such field: &quot; + clazz.getName() + '.' + propertyName); } /** * 暴力获取对象变量值,忽略private,protected修饰符的限制. * * @param object * 对象实例 * @param propertyName * 属性名 * @return 强制获得属性值 * @throws NoSuchFieldException * 如果没有该Field时抛出. */ public static Object forceGetProperty(Object object, String propertyName) throws NoSuchFieldException, IllegalAccessException { return getFieldValue(object, propertyName, true); } public static Object safeGetFieldValue(Object object, String fieldName) { return safeGetFieldValue(object, fieldName, true); } public static Object safeGetFieldValue(Object object, String fieldName, boolean targetAccessible) { try { return getFieldValue(object, fieldName, targetAccessible); } catch (NoSuchFieldException ex) { logger.warn(&quot;&quot;, ex); } catch (IllegalAccessException ex) { logger.warn(&quot;&quot;, ex); } return null; } public static Object getFieldValue(Object object, String fieldName) throws NoSuchFieldException, IllegalAccessException { return getFieldValue(object, fieldName, false); } public static Object getFieldValue(Object object, String fieldName, boolean targetAccessible) throws NoSuchFieldException, IllegalAccessException { Assert.notNull(object); Assert.hasText(fieldName); Field field = getDeclaredField(object, fieldName); boolean accessible = field.isAccessible(); field.setAccessible(targetAccessible); Object result = field.get(object); field.setAccessible(accessible); return result; } /** * 暴力设置对象变量值,忽略private,protected修饰符的限制. * * @param object * 对象实例 * @param propertyName * 属性名 * @param newValue * 赋予的属性值 * @throws NoSuchFieldException * 如果没有该Field时抛出. */ public static void forceSetProperty(Object object, String propertyName, Object newValue) throws NoSuchFieldException, IllegalAccessException { setFieldValue(object, propertyName, newValue, true); } public static void safeSetFieldValue(Object object, String fieldName, Object newValue) { safeSetFieldValue(object, fieldName, newValue, true); } public static void safeSetFieldValue(Object object, String fieldName, Object newValue, boolean targetAccessible) { try { setFieldValue(object, fieldName, newValue, targetAccessible); } catch (NoSuchFieldException ex) { logger.warn(&quot;&quot;, ex); } catch (IllegalAccessException ex) { logger.warn(&quot;&quot;, ex); } } public static void setFieldValue(Object object, String propertyName, Object newValue, boolean targetAccessible) throws NoSuchFieldException, IllegalAccessException { Assert.notNull(object); Assert.hasText(propertyName); Field field = getDeclaredField(object, propertyName); boolean accessible = field.isAccessible(); field.setAccessible(targetAccessible); field.set(object, newValue); field.setAccessible(accessible); } /** * 暴力调用对象函数,忽略private,protected修饰符的限制. * * @param object * 对象实例 * @param methodName * 方法名 * @param params * 方法参数 * @return Object 方法调用返回的结果对象 * @throws NoSuchMethodException * 如果没有该Method时抛出. */ public static Object invokePrivateMethod(Object object, String methodName, Object... params) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return invokeMethod(object, methodName, true, params); } public static Object safeInvokeMethod(Object object, Method method, Object... params) { try { return method.invoke(object, params); } catch (IllegalAccessException ex) { logger.warn(&quot;&quot;, ex); } catch (InvocationTargetException ex) { logger.warn(&quot;&quot;, ex); } return null; } public static Object safeInvokeMethod(Object object, String methodName, Object... params) { try { return invokeMethod(object, methodName, params); } catch (NoSuchMethodException ex) { logger.warn(&quot;&quot;, ex); } catch (IllegalAccessException ex) { logger.warn(&quot;&quot;, ex); } catch (InvocationTargetException ex) { logger.warn(&quot;&quot;, ex); } return null; } public static Object invokeMethod(Object object, String methodName, Object... params) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { return invokeMethod(object, methodName, false, params); } public static Object invokeMethod(Object object, String methodName, boolean targetAccessible, Object... params) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException { Assert.notNull(object); Assert.hasText(methodName); Class[] types = new Class[params.length]; for (int i = 0; i &lt; params.length; i++) { types[i] = params[i].getClass(); } Class clazz = object.getClass(); Method method = null; for (Class superClass = clazz; superClass != Object.class; superClass = superClass .getSuperclass()) { try { method = superClass.getDeclaredMethod(methodName, types); break; } catch (NoSuchMethodException ex) { // 方法不在当前类定义,继续向上转型 logger.debug(ex.getMessage(), ex); } } if (method == null) { throw new NoSuchMethodException(&quot;No Such Method : &quot; + clazz.getSimpleName() + &quot;.&quot; + methodName + Arrays.asList(types)); } boolean accessible = method.isAccessible(); method.setAccessible(targetAccessible); Object result = method.invoke(object, params); method.setAccessible(accessible); return result; } /** * 按Field的类型取得Field列表. * * @param object * 对象实例 * @param type * 类型 * @return 属性对象列表 */ public static List&lt;Field&gt; getFieldsByType(Object object, Class type) { List&lt;Field&gt; list = new ArrayList&lt;Field&gt;(); Field[] fields = object.getClass().getDeclaredFields(); for (Field field : fields) { if (field.getType().isAssignableFrom(type)) { list.add(field); } } return list; } /** * 按FieldName获得Field的类型. * * @param type * 类型 * @param name * 属性名 * @return 属性的类型 * @throws NoSuchFieldException * 指定属性不存在时,抛出异常 */ public static Class getPropertyType(Class type, String name) throws NoSuchFieldException { return getDeclaredField(type, name).getType(); } /** * 获得field的getter函数名称. * * @param type * 类型 * @param fieldName * 属性名 * @return getter方法名 * @throws NoSuchFieldException * field不存在时抛出异常 * * @todo: 使用reflectUtils里的方法更合适,这里的实现方式,必须先有field才能有method,逻辑上有问题 实际上,即使没有field也可以单独有method。 */ public static String getGetterName(Class type, String fieldName) throws NoSuchFieldException { Assert.notNull(type, &quot;Type required&quot;); Assert.hasText(fieldName, &quot;FieldName required&quot;); Class fieldType = getDeclaredField(type, fieldName).getType(); if ((fieldType == boolean.class) || (fieldType == Boolean.class)) { return &quot;is&quot; + StrUtils.capitalize(fieldName); } else { return &quot;get&quot; + StrUtils.capitalize(fieldName); } } /** * 获得field的getter函数,如果找不到该方法,返回null. * * @param type * 类型 * @param fieldName * 属性名 * @return getter方法对象 */ public static Method getGetterMethod(Class type, String fieldName) { try { return type.getMethod(getGetterName(type, fieldName)); } catch (NoSuchMethodException ex) { logger.error(ex.getMessage(), ex); } catch (NoSuchFieldException ex) { logger.error(ex.getMessage(), ex); } return null; } public static String getFieldName(String methodName) { String fieldName = methodName.substring(LENGTH_GETTER_PREFIX); return fieldName.substring(0, 1).toLowerCase() + fieldName.substring(1); }

}

 

 

  • Struts2
    13 引用 • 14 回帖 • 1 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...

推荐标签 标签

  • HTML

    HTML5 是 HTML 下一个的主要修订版本,现在仍处于发展阶段。广义论及 HTML5 时,实际指的是包括 HTML、CSS 和 JavaScript 在内的一套技术组合。

    108 引用 • 295 回帖
  • etcd

    etcd 是一个分布式、高可用的 key-value 数据存储,专门用于在分布式系统中保存关键数据。

    6 引用 • 26 回帖 • 544 关注
  • CloudFoundry

    Cloud Foundry 是 VMware 推出的业界第一个开源 PaaS 云平台,它支持多种框架、语言、运行时环境、云平台及应用服务,使开发人员能够在几秒钟内进行应用程序的部署和扩展,无需担心任何基础架构的问题。

    5 引用 • 18 回帖 • 181 关注
  • 自由行
  • SEO

    发布对别人有帮助的原创内容是最好的 SEO 方式。

    35 引用 • 200 回帖 • 29 关注
  • NetBeans

    NetBeans 是一个始于 1997 年的 Xelfi 计划,本身是捷克布拉格查理大学的数学及物理学院的学生计划。此计划延伸而成立了一家公司进而发展这个商用版本的 NetBeans IDE,直到 1999 年 Sun 买下此公司。Sun 于次年(2000 年)六月将 NetBeans IDE 开源,直到现在 NetBeans 的社群依然持续增长。

    78 引用 • 102 回帖 • 704 关注
  • ZeroNet

    ZeroNet 是一个基于比特币加密技术和 BT 网络技术的去中心化的、开放开源的网络和交流系统。

    1 引用 • 21 回帖 • 648 关注
  • Ngui

    Ngui 是一个 GUI 的排版显示引擎和跨平台的 GUI 应用程序开发框架,基于
    Node.js / OpenGL。目标是在此基础上开发 GUI 应用程序可拥有开发 WEB 应用般简单与速度同时兼顾 Native 应用程序的性能与体验。

    7 引用 • 9 回帖 • 397 关注
  • 又拍云

    又拍云是国内领先的 CDN 服务提供商,国家工信部认证通过的“可信云”,乌云众测平台认证的“安全云”,为移动时代的创业者提供新一代的 CDN 加速服务。

    20 引用 • 37 回帖 • 574 关注
  • 印象笔记
    3 引用 • 16 回帖
  • Excel
    31 引用 • 28 回帖
  • 友情链接

    确认过眼神后的灵魂连接,站在链在!

    24 引用 • 373 回帖 • 1 关注
  • 周末

    星期六到星期天晚,实行五天工作制后,指每周的最后两天。再过几年可能就是三天了。

    14 引用 • 297 回帖
  • BookxNote

    BookxNote 是一款全新的电子书学习工具,助力您的学习与思考,让您的大脑更高效的记忆。

    笔记整理交给我,一心只读圣贤书。

    1 引用 • 1 回帖
  • IDEA

    IDEA 全称 IntelliJ IDEA,是一款 Java 语言开发的集成环境,在业界被公认为最好的 Java 开发工具之一。IDEA 是 JetBrains 公司的产品,这家公司总部位于捷克共和国的首都布拉格,开发人员以严谨著称的东欧程序员为主。

    181 引用 • 400 回帖 • 1 关注
  • SQLServer

    SQL Server 是由 [微软] 开发和推广的关系数据库管理系统(DBMS),它最初是由 微软、Sybase 和 Ashton-Tate 三家公司共同开发的,并于 1988 年推出了第一个 OS/2 版本。

    21 引用 • 31 回帖
  • 单点登录

    单点登录(Single Sign On)是目前比较流行的企业业务整合的解决方案之一。SSO 的定义是在多个应用系统中,用户只需要登录一次就可以访问所有相互信任的应用系统。

    9 引用 • 25 回帖 • 1 关注
  • 代码片段

    代码片段分为 CSS 与 JS 两种代码,添加在 [设置 - 外观 - 代码片段] 中,这些代码会在思源笔记加载时自动执行,用于改善笔记的样式或功能。

    用户在该标签下分享代码片段时需在帖子标题前添加 [css] [js] 用于区分代码片段类型。

    164 引用 • 1120 回帖 • 1 关注
  • Love2D

    Love2D 是一个开源的, 跨平台的 2D 游戏引擎。使用纯 Lua 脚本来进行游戏开发。目前支持的平台有 Windows, Mac OS X, Linux, Android 和 iOS。

    14 引用 • 53 回帖 • 555 关注
  • API

    应用程序编程接口(Application Programming Interface)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。

    79 引用 • 431 回帖
  • FreeMarker

    FreeMarker 是一款好用且功能强大的 Java 模版引擎。

    23 引用 • 20 回帖 • 468 关注
  • Eclipse

    Eclipse 是一个开放源代码的、基于 Java 的可扩展开发平台。就其本身而言,它只是一个框架和一组服务,用于通过插件组件构建开发环境。

    76 引用 • 258 回帖 • 628 关注
  • 人工智能

    人工智能(Artificial Intelligence)是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门技术科学。

    167 引用 • 314 回帖
  • iOS

    iOS 是由苹果公司开发的移动操作系统,最早于 2007 年 1 月 9 日的 Macworld 大会上公布这个系统,最初是设计给 iPhone 使用的,后来陆续套用到 iPod touch、iPad 以及 Apple TV 等产品上。iOS 与苹果的 Mac OS X 操作系统一样,属于类 Unix 的商业操作系统。

    89 引用 • 150 回帖
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    143 引用 • 442 回帖
  • FlowUs

    FlowUs.息流 个人及团队的新一代生产力工具。

    让复杂的信息管理更轻松、自由、充满创意。

    1 引用 • 1 关注
  • CodeMirror
    2 引用 • 17 回帖 • 162 关注