前言:今天测试提了一个优化,在表单提交审批的时候,验证一下表单正确性,在不符合条件的情况下alert出来,并不需要刷新页面(原先因为是从产品上改的项目,存在问题颇多,这个页面alert之后会刷新一遍),一看是这样的问题,我回他分分钟搞定。
。。。。。。
现在我的脸已经被打得很肿了,在我把刷新的js代码去掉之后,点击提交审批,弹出验证,关闭验证,页面没有刷新,“不错,不错,完美!!!”,内心比了个(金女士?先生?)的手势,并顺手又点了一下提交,“嗯?”验证信息没有弹出来。。。emmmmm。。。可能是没点上,又点了一遍,还是没有。。。好吧,debug吧。
然后开始了排查工作,F6一步一步摁着看,发现在保存表单信息的时候,第一次点击提交按钮不报错,第二次这会报
org.springframework.orm.hibernate4.HibernateOptimisticLockingFailureException
这样的错,没遇到过,看信息应该是hibernate的问题,只能问度娘了。
百度的结果大体上是这三种:
1、由于主键设置为自增长,在我们插入记录的时候设置了Id的值,Hibernate的映射配置文件中,把id 的class改为assigned类型。
2、使用了hibernate的saveOrUpdata方法进行保存实例,saveOrUpdate要求:只有Id为null才能执行save,其他情况下执行update,在保存实例的时候是新增,但如果id不为null,所有的执行都是update操作,可是数据库没有主键对应的值,所以出现了异常,解决办法:unsaved-value="null"是否设置
3、在Hibernate映射一对多,多对一,多对多的时候新增常常会出现异常
java代码:下面的beanutils是apache包下的
public void saveFunctionCell(FunctionCell functionCell,Integer pid)(
System.out.print("现在进行新增操作");
FunctionCell fc = new FunctionCell();
try{
BeanUtils.copyProperties(fc,functionCell);
fc.setFunCellID(null);
functionCellDao.saveFunctionCell(fc);
}catch(Exception e){
e.printStackTrace();
}
}
关键是beanutils的用法!!!!
注意特别标识出来的这个地方,BeanUtils拷贝Bean属性的时候,它会将你的Integer类型全部设置为0,在这里设置一个空null,这样就不会抛出错误了。
结论:结合上面这些可能性进行尝试,发现在id为null的情况下保存没有问题,可能的原因就是在执行保存的时候,前一次的保存事物影响了下面一次的保存,需要在id不为空的情况下重新new一个对象进行保存。
解决办法:
一看我需要保存的这个对象,一下子懵逼了,大致数数有100多个属性,这样一个一个的set值到什么时候,这时候就需要我们用目标对象替换源对象的值,直接把Object的值全部放到新new的Object中。
/**
* 比较用目标对象替换源对象的值
* @param source 源对象
* @param target 目标对象
* @return 最新源对象
* @see
*/
public static Object getObjectByCompareWith(Object source, Object target) {
Class<?> srcClass = source.getClass();
Field[] fields = srcClass.getDeclaredFields();
for (Field field : fields) {
String nameKey = field.getName();
//获取源对象中的属性值
String srcValue = getClassValue(source, nameKey) == null ? "" : getClassValue(source, nameKey).toString();
//获取目标对象中的属性值
String tarValue = getClassValue(target, nameKey) == null ? "" : getClassValue(target, nameKey).toString();
//比较两个属性值,不相等的时候进行赋值
if (!srcValue.equals(tarValue)) {
source = setClassValue(source, nameKey, tarValue);
}
}
return source;
}
/**
* 根据字段名称取值
* @param obj 指定对象
* @param fieldName 字段名称
* @return 指定对象
*/
public static Object getClassValue(Object obj, String fieldName) {
if (obj == null) {
return null;
}
Class beanClass = obj.getClass();
Method[] ms = beanClass.getMethods();
for (int i = 0; i < ms.length; i++ ) {
// 非get方法不取
if (!ms[i].getName().startsWith("get")) {
continue;
}
Object objValue = null;
try {
objValue = ms[i].invoke(obj, new Object[] {});
} catch (Exception e) {
continue;
}
if (objValue == null) {
continue;
}
if (ms[i].getName().toUpperCase().equals(fieldName.toUpperCase())
|| ms[i].getName().substring(3).toUpperCase().equals(fieldName.toUpperCase())) {
return objValue;
}
}
return null;
}
/**
* 给对象的字段赋指定的值
* @param obj 指定对象
* @param fieldName 属性
* @param value 值
* @return
* @see
*/
public static Object setClassValue(Object obj, String fieldName, Object value) {
if (obj == null) {
return null;
}
if(Constant.STRING_NULL.equals(value)) {
value = null;
}
Class beanClass = obj.getClass();
Method[] ms = beanClass.getMethods();
for (int i = 0; i < ms.length; i++) {
try {
if (ms[i].getName().startsWith("set")) {
if(ms[i].getName().toUpperCase().equals(fieldName.toUpperCase())
|| ms[i].getName().substring(3).toUpperCase().equals(fieldName.toUpperCase())) {
String pt = ms[i].getParameterTypes()[0].toString();
if(value != null) {
ms[i].invoke(obj, transVal(value.toString(), pt.substring(pt.lastIndexOf(".")+1)));
} else {
ms[i].invoke(obj, new Object[]{null});
}
break;
}
}
} catch (Exception e) {
continue;
}
}
return obj;
}
/**
* 根据属性类型赋值
* @param value 值
* @param paramsType 属性类型
* @return
* @see
*/
public static Object transVal(String value, String paramsType) {
if(ColumnType.String.toString().equals(paramsType)) {
return new String(value);
}
if(ColumnType.Double.toString().equals(paramsType)) {
return Double.parseDouble(value);
}
if(ColumnType.Integer.toString().equals(paramsType)) {
return Integer.parseInt(value);
}
if(ColumnType.Long.toString().equals(paramsType)) {
return Long.parseLong(value);
}
if(ColumnType.BigDecimal.toString().equals(paramsType)) {
return new BigDecimal(value);
}
return value;
}
package com.xxx.utils;
/**
* <简述> 定义类型枚举
* <详细描述>
* @author xxx
* @version $Id$
* @since
* @see
*/
public enum ColumnType {
String, Double, Integer, Long, BigDecimal;
}
直接调用方法
xxxNew = (Xxx)ObjectCompareUtils.getObjectByCompareWith(xxxNew, xxx);
即可把源对象的值替换成目标对象的值。
这样再提交保存该表单,完美执行,每次点击都能出现验证信息。