[persistence,web]persistence模块添加变量表达式支持,为批量添加操作时的类似“#{index*3+1}”(index为批量索引)的表达式提供支持

This commit is contained in:
datagear 2018-11-27 20:15:22 +08:00
parent 96eb17dd34
commit c3cd0885ad
23 changed files with 1155 additions and 380 deletions

View File

@ -28,6 +28,11 @@
<artifactId>datagear-dbinfo</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>

View File

@ -0,0 +1,341 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;
import org.datagear.connection.JdbcUtil;
import org.datagear.model.Model;
import org.datagear.model.Property;
import org.datagear.model.support.MU;
import org.datagear.persistence.UnsupportedModelCharacterException;
import org.datagear.persistence.support.ExpressionResolver.Expression;
import org.springframework.core.convert.ConversionService;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* 抽象支持表达式的持久化操作类
*
* @author datagear@163.com
*
*/
public abstract class AbstractExpressionModelPersistenceOperation extends AbstractModelPersistenceOperation
{
private ConversionService conversionService;
private ExpressionResolver variableExpressionResolver;
private ExpressionResolver sqlExpressionResolver;
private SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
public AbstractExpressionModelPersistenceOperation()
{
super();
}
public AbstractExpressionModelPersistenceOperation(ConversionService conversionService,
ExpressionResolver variableExpressionResolver, ExpressionResolver sqlExpressionResolver)
{
super();
this.conversionService = conversionService;
this.variableExpressionResolver = variableExpressionResolver;
this.sqlExpressionResolver = sqlExpressionResolver;
}
public ConversionService getConversionService()
{
return conversionService;
}
public void setConversionService(ConversionService conversionService)
{
this.conversionService = conversionService;
}
public ExpressionResolver getVariableExpressionResolver()
{
return variableExpressionResolver;
}
public void setVariableExpressionResolver(ExpressionResolver variableExpressionResolver)
{
this.variableExpressionResolver = variableExpressionResolver;
}
public ExpressionResolver getSqlExpressionResolver()
{
return sqlExpressionResolver;
}
public void setSqlExpressionResolver(ExpressionResolver sqlExpressionResolver)
{
this.sqlExpressionResolver = sqlExpressionResolver;
}
public SpelExpressionParser getSpelExpressionParser()
{
return spelExpressionParser;
}
public void setSpelExpressionParser(SpelExpressionParser spelExpressionParser)
{
this.spelExpressionParser = spelExpressionParser;
}
/**
* 解析表达式属性值
* <p>
* 如果包含表达式返回计算结果否则直接返回{@code propValue}
* </p>
*
* @param cn
* @param model
* @param property
* @param expressionPropValue
* @param expressionEvaluationContext
* @return
*/
protected Object evaluatePropertyValueIfExpression(Connection cn, Model model, Property property, Object propValue,
ExpressionEvaluationContext expressionEvaluationContext)
{
List<Expression> variableExpressions = this.variableExpressionResolver.resolve(propValue);
Object evaluatedPropValue = propValue;
if (variableExpressions != null && !variableExpressions.isEmpty())
{
String strPropValue = (String) propValue;
checkValidExpressionProperty(model, property, strPropValue);
evaluatedPropValue = evaluateVariableExpressions(strPropValue, variableExpressions,
expressionEvaluationContext);
}
List<Expression> sqlExpressions = this.sqlExpressionResolver.resolve(evaluatedPropValue);
if (sqlExpressions != null && !sqlExpressions.isEmpty())
{
String strPropValue = (String) evaluatedPropValue;
checkValidExpressionProperty(model, property, strPropValue);
evaluatedPropValue = evaluateSqlExpressions(cn, strPropValue, sqlExpressions, expressionEvaluationContext);
}
if (evaluatedPropValue != propValue)
{
Class<?> propertyType = property.getModel().getType();
propValue = this.conversionService.convert(evaluatedPropValue, propertyType);
}
return propValue;
}
/**
* 计算给定变量表达式的值
*
* @param source
* 变量表达式字符串
* @param expressions
* @param expressionEvaluationContext
* @return
* @throws VariableExpressionErrorException
*/
protected Object evaluateVariableExpressions(String source, List<Expression> expressions,
ExpressionEvaluationContext expressionEvaluationContext) throws VariableExpressionErrorException
{
List<Object> expressionValues = new ArrayList<Object>();
for (int i = 0, len = expressions.size(); i < len; i++)
{
Expression expression = expressions.get(i);
if (expressionEvaluationContext.containsCachedValue(expression))
{
Object value = expressionEvaluationContext.getCachedValue(expression);
expressionValues.add(value);
}
else
{
evaluateAsVariableExpression(expression, expressionEvaluationContext, expressionValues);
}
}
String evaluated = this.variableExpressionResolver.evaluate(source, expressions, expressionValues, "");
return evaluated;
}
/**
* 计算给定SQL表达式的值
* <p>
* 如果表达式并不符合{@linkplain #isSelectSql(String)}那么此方法则会将它作为变量表达式求值这使得在不需要变量表达式内嵌SQL表达式的情况下可以仅使用SQL表达式的语法简化使用难度
* </p>
*
* @param cn
* @param source
* SQL表达式字符串
* @param expressions
* @param expressionEvaluationContext
* @return
* @throws SqlExpressionErrorException
* @throws VariableExpressionErrorException
*/
protected Object evaluateSqlExpressions(Connection cn, String source, List<Expression> expressions,
ExpressionEvaluationContext expressionEvaluationContext)
throws SqlExpressionErrorException, VariableExpressionErrorException
{
List<Object> expressionValues = new ArrayList<Object>();
for (int i = 0, len = expressions.size(); i < len; i++)
{
Expression expression = expressions.get(i);
if (expressionEvaluationContext.containsCachedValue(expression))
{
Object value = expressionEvaluationContext.getCachedValue(expression);
expressionValues.add(value);
}
else if (isSelectSql(expression.getContent()))
{
evaluateAsSelectSqlExpression(expression, expressionEvaluationContext, expressionValues, cn);
}
else
{
evaluateAsVariableExpression(expression, expressionEvaluationContext, expressionValues);
}
}
String evaluated = this.sqlExpressionResolver.evaluate(source, expressions, expressionValues, "");
return evaluated;
}
/**
* 作为SQL表达式求值
*
* @param expression
* @param expressionEvaluationContext
* @param expressionValues
* @param cn
* @throws SqlExpressionErrorException
*/
protected void evaluateAsSelectSqlExpression(Expression expression,
ExpressionEvaluationContext expressionEvaluationContext, List<Object> expressionValues, Connection cn)
throws SqlExpressionErrorException
{
Statement st = null;
ResultSet rs = null;
try
{
st = cn.createStatement();
rs = st.executeQuery(expression.getContent());
Object value = null;
if (rs.next())
value = rs.getObject(1);
expressionValues.add(value);
expressionEvaluationContext.putCachedValue(expression, value);
}
catch (SQLException e)
{
throw new SqlExpressionErrorException(expression, e);
}
finally
{
JdbcUtil.closeResultSet(rs);
JdbcUtil.closeStatement(st);
}
}
/**
* 作为变量表达式求值
*
* @param expression
* @param expressionEvaluationContext
* @param expressionValues
* @throws VariableExpressionErrorException
*/
protected void evaluateAsVariableExpression(Expression expression,
ExpressionEvaluationContext expressionEvaluationContext, List<Object> expressionValues)
throws VariableExpressionErrorException
{
try
{
Object value = this.spelExpressionParser.parseExpression(expression.getContent())
.getValue(expressionEvaluationContext.getVariableExpressionBean());
expressionValues.add(value);
expressionEvaluationContext.putCachedValue(expression, value);
}
catch (Exception e)
{
throw new VariableExpressionErrorException(expression, e);
}
}
/**
* 检查属性是否可使用表达式
*
* @param model
* @param property
* @param expressionPropValue
*/
protected void checkValidExpressionProperty(Model model, Property property, String expressionPropValue)
{
if (!isValidExpressionProperty(model, property))
throw new UnsupportedModelCharacterException("[" + model + "] 's [" + property + "] is expression ["
+ expressionPropValue + "], it must be single, concrete and primitive.");
}
/**
* 判断属性是否可使用表达式值
*
* @param model
* @param property
* @return
*/
protected boolean isValidExpressionProperty(Model model, Property property)
{
return (MU.isSingleProperty(property) && MU.isConcretePrimitiveProperty(property));
}
/**
* 判断给定对象是否是表达式
*
* @param obj
* @return
*/
protected boolean isExpression(Object obj)
{
return this.variableExpressionResolver.isExpression(obj) || this.sqlExpressionResolver.isExpression(obj);
}
/**
* 判断给定SQL语句是否是SELECT语句
*
* @param sql
* @return
*/
protected boolean isSelectSql(String sql)
{
if (sql == null || sql.isEmpty())
return false;
return Pattern.matches(SELECT_SQL_REGEX, sql);
}
protected static final String SELECT_SQL_REGEX = "^\\s*((?i)select)\\s+\\S+[\\s\\S]*$";
}

View File

@ -4,23 +4,6 @@
package org.datagear.persistence.support;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
import org.datagear.connection.JdbcUtil;
import org.datagear.model.Model;
import org.datagear.model.Property;
import org.datagear.model.support.MU;
import org.datagear.persistence.UnsupportedModelCharacterException;
import org.datagear.persistence.support.ExpressionResolver.Expression;
import org.springframework.core.convert.ConversionService;
/**
* 抽象持久化操作类
* <p>
@ -42,91 +25,4 @@ public abstract class AbstractModelPersistenceOperation extends AbstractModelDat
super();
}
/**
* 计算给定表达式的真正属性值
*
* @param cn
* @param model
* @param property
* @param expressionPropValue
* @param expressions
* @param expressionValueCache
* @param conversionService
* @param expressionResolver
* @return
*/
protected Object evaluatePropertyValueForQueryExpressions(Connection cn, Model model, Property property,
String expressionPropValue, List<Expression> expressions, Map<String, Object> expressionValueCache,
ConversionService conversionService, ExpressionResolver expressionResolver)
{
if (!MU.isSingleProperty(property) || !MU.isConcretePrimitiveProperty(property))
throw new UnsupportedModelCharacterException("[" + model + "] 's [" + property + "] is sql expression ["
+ expressionPropValue + "], it must be single, concrete and primitive.");
List<Object> expressionValues = new ArrayList<Object>();
for (int i = 0, len = expressions.size(); i < len; i++)
{
Expression expression = expressions.get(i);
String cacheKey = (expression.hasName() ? expression.getName() : expression.getContent());
if (expressionValueCache.containsKey(cacheKey))
{
Object value = expressionValueCache.get(cacheKey);
expressionValues.add(value);
}
else if (!isSelectSql(expression.getContent()))
{
expressionValues.add(expression.getExpression());
}
else
{
Statement st = null;
ResultSet rs = null;
try
{
st = cn.createStatement();
rs = st.executeQuery(expression.getContent());
Object value = null;
if (rs.next())
value = rs.getObject(1);
expressionValues.add(value);
expressionValueCache.put(cacheKey, value);
}
catch (SQLException e)
{
throw new SqlExpressionErrorException(expression, e);
}
finally
{
JdbcUtil.closeResultSet(rs);
JdbcUtil.closeStatement(st);
}
}
}
String evaluated = expressionResolver.evaluate(expressionPropValue, expressions, expressionValues, "");
return conversionService.convert(evaluated, property.getModel().getType());
}
/**
* 判断给定SQL语句是否是SELECT语句
*
* @param sql
* @return
*/
protected boolean isSelectSql(String sql)
{
if (sql == null || sql.isEmpty())
return false;
return Pattern.matches(SELECT_SQL_REGEX, sql);
}
protected static final String SELECT_SQL_REGEX = "^\\s*((?i)select)\\s+\\S+[\\s\\S]*$";
}

View File

@ -38,7 +38,9 @@ public class DefaultPersistenceManager extends AbstractModelDataAccessObject imp
private ConversionService conversionService;
private ExpressionResolver expressionResolver;
private ExpressionResolver variableExpressionResolver;
private ExpressionResolver sqlExpressionResolver;
private InsertPersistenceOperation insertPersistenceOperation;
@ -59,12 +61,20 @@ public class DefaultPersistenceManager extends AbstractModelDataAccessObject imp
this.dialectSource = dialectSource;
this.conversionService = conversionService;
this.expressionResolver = new ExpressionResolver();
this.variableExpressionResolver = new VariableExpressionResolver();
this.sqlExpressionResolver = new SqlExpressionResolver();
this.insertPersistenceOperation = new InsertPersistenceOperation(this.conversionService,
this.expressionResolver);
this.variableExpressionResolver, this.sqlExpressionResolver);
this.deletePersistenceOperation = new DeletePersistenceOperation();
this.updatePersistenceOperation = new UpdatePersistenceOperation(this.insertPersistenceOperation,
this.deletePersistenceOperation, this.conversionService, this.expressionResolver);
this.deletePersistenceOperation, this.conversionService, this.variableExpressionResolver,
this.sqlExpressionResolver);
this.selectPersistenceOperation = new SelectPersistenceOperation();
}
@ -90,16 +100,28 @@ public class DefaultPersistenceManager extends AbstractModelDataAccessObject imp
this.updatePersistenceOperation.setConversionService(conversionService);
}
public ExpressionResolver getExpressionResolver()
public ExpressionResolver getVariableExpressionResolver()
{
return expressionResolver;
return variableExpressionResolver;
}
public void setExpressionResolver(ExpressionResolver expressionResolver)
public void setVariableExpressionResolver(ExpressionResolver variableExpressionResolver)
{
this.expressionResolver = expressionResolver;
this.insertPersistenceOperation.setExpressionResolver(expressionResolver);
this.updatePersistenceOperation.setExpressionResolver(expressionResolver);
this.variableExpressionResolver = variableExpressionResolver;
this.insertPersistenceOperation.setVariableExpressionResolver(variableExpressionResolver);
this.updatePersistenceOperation.setVariableExpressionResolver(variableExpressionResolver);
}
public ExpressionResolver getSqlExpressionResolver()
{
return sqlExpressionResolver;
}
public void setSqlExpressionResolver(ExpressionResolver sqlExpressionResolver)
{
this.sqlExpressionResolver = sqlExpressionResolver;
this.insertPersistenceOperation.setSqlExpressionResolver(sqlExpressionResolver);
this.updatePersistenceOperation.setSqlExpressionResolver(sqlExpressionResolver);
}
public InsertPersistenceOperation getInsertPersistenceOperation()

View File

@ -0,0 +1,38 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
import org.datagear.persistence.PersistenceException;
import org.datagear.persistence.support.ExpressionResolver.Expression;
/**
* {@linkplain Expression}执行出错异常
*
* @author datagear@163.com
*
*/
public class ExpressionErrorException extends PersistenceException
{
private static final long serialVersionUID = 1L;
private Expression expression;
public ExpressionErrorException(Expression expression)
{
super();
this.expression = expression;
}
public ExpressionErrorException(Expression expression, Throwable cause)
{
super("Evaluate expression [" + expression.getContent() + "] error", cause);
this.expression = expression;
}
public Expression getExpression()
{
return expression;
}
}

View File

@ -0,0 +1,147 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
import java.util.HashMap;
import java.util.Map;
import org.datagear.persistence.support.ExpressionResolver.Expression;
/**
* {@linkplain Expression}计算上下文
* <p>
* 为了方便支持批量添加操作此类的实例默认会添加{@linkplain #VARIABLE_INDEX}变量并且初值为{@code 0}
* </p>
*
* @author datagear@163.com
*
*/
public class ExpressionEvaluationContext
{
/** 变量名index */
public static final String VARIABLE_INDEX = "index";
/** 值缓存 */
private Map<String, Object> valueCache = new HashMap<String, Object>();
/** 变量表达式求值Bean */
private VariableExpressionBean variableExpressionBean = new VariableExpressionBean();
public ExpressionEvaluationContext()
{
super();
this.variableExpressionBean.setIndex(0);
}
public Map<String, Object> getValueCache()
{
return valueCache;
}
public void setValueCache(Map<String, Object> valueCache)
{
this.valueCache = valueCache;
}
public VariableExpressionBean getVariableExpressionBean()
{
return variableExpressionBean;
}
public void setVariableExpressionBean(VariableExpressionBean variableExpressionBean)
{
this.variableExpressionBean = variableExpressionBean;
}
/**
* 是否包含指定{@linkplain Expression}的缓存值
*
* @param expression
* @return
*/
public boolean containsCachedValue(Expression expression)
{
String cacheKey = getCachedValueKey(expression);
return this.valueCache.containsKey(cacheKey);
}
/**
* 获取指定{@linkplain Expression}的缓存值
*
* @param expression
* @return
*/
public Object getCachedValue(Expression expression)
{
String cacheKey = getCachedValueKey(expression);
return this.valueCache.get(cacheKey);
}
/**
* 将指定{@linkplain Expression}的值加入缓存
*
* @param expression
* @param value
*/
public void putCachedValue(Expression expression, Object value)
{
String cacheKey = getCachedValueKey(expression);
this.valueCache.put(cacheKey, value);
}
/**
* 获取{@linkplain #getVariableExpressionBean()}{@linkplain VariableExpressionBean#getIndex()}的值
*
* @return
*/
public int getVariableIndex()
{
return this.variableExpressionBean.getIndex();
}
/**
* 设置{@linkplain #getVariableExpressionBean()}{@linkplain VariableExpressionBean#getIndex()}的值
*
* @param value
*/
public void setVariableIndex(int value)
{
this.variableExpressionBean.setIndex(value);
}
/**
* {@linkplain #getVariableExpressionBean()}{@linkplain VariableExpressionBean#getIndex()}的值加{@code 1}并返回
*
* @return
*/
public int incrementVariableIndex()
{
int v = getVariableIndex() + 1;
setVariableIndex(v);
return v;
}
/**
* 获取缓存值关键字
* <p>
* 为了使{@linkplain ExpressionResolver#DEFAULT_START_IDENTIFIER_DOLLAR}
* {@linkplain ExpressionResolver#DEFAULT_START_IDENTIFIER_SHARP}的表达式能使用同一个{@linkplain ExpressionEvaluationContext}
* 此方法会生成<code>"${...}"</code><code>"#{...}"</code>格式的关键字
* </p>
*
* @param expression
*
* @return
*/
protected String getCachedValueKey(Expression expression)
{
return expression.getStartIdentifier() + (expression.hasName() ? expression.getName() : expression.getContent())
+ expression.getEndIdentifier();
}
}

View File

@ -20,7 +20,11 @@ import java.util.List;
*/
public class ExpressionResolver
{
public static final String DEFAULT_START_IDENTIFIER = "${";
/** "${"起始标识符 */
public static final String DEFAULT_START_IDENTIFIER_DOLLAR = "${";
/** "#{"起始标识符 */
public static final String DEFAULT_START_IDENTIFIER_SHARP = "#{";
public static final String DEFAULT_END_IDENTIFIER = "}";
@ -28,7 +32,7 @@ public class ExpressionResolver
public static final char DEFAULT_ESCAPER = '\\';
private String startIdentifier = DEFAULT_START_IDENTIFIER;
private String startIdentifier = DEFAULT_START_IDENTIFIER_DOLLAR;
private String endIdentifier = DEFAULT_END_IDENTIFIER;
@ -36,7 +40,7 @@ public class ExpressionResolver
private char escaper = DEFAULT_ESCAPER;
private transient char[] _startIdentifierChars = DEFAULT_START_IDENTIFIER.toCharArray();
private transient char[] _startIdentifierChars = DEFAULT_START_IDENTIFIER_DOLLAR.toCharArray();
private transient char[] _endIdentifierChars = DEFAULT_END_IDENTIFIER.toCharArray();
@ -142,9 +146,27 @@ public class ExpressionResolver
*/
public List<Expression> resolve(String source)
{
List<Expression> expressions = new ArrayList<Expression>();
if (source == null || source.isEmpty())
return Collections.emptyList();
resolve(source, expressions);
List<Expression> expressions = null;
char[] cs = source.toCharArray();
Expression next = null;
int startIndex = 0;
while ((next = resolveNextExpression(cs, startIndex)) != null)
{
if (expressions == null)
expressions = new ArrayList<Expression>();
expressions.add(next);
startIndex = next.getEnd();
}
if (expressions == null)
expressions = Collections.emptyList();
return expressions;
}
@ -192,29 +214,6 @@ public class ExpressionResolver
return result.toString();
}
/**
* 解析源字符串中的{@linkplain Expression}并写入给定列表
*
* @param source
* @param expressions
*/
protected void resolve(String source, List<Expression> expressions)
{
if (source == null || source.isEmpty())
return;
char[] cs = source.toCharArray();
Expression next = null;
int startIndex = 0;
while ((next = resolveNextExpression(cs, startIndex)) != null)
{
expressions.add(next);
startIndex = next.getEnd();
}
}
/**
* 从给定起始位置解析下一个{@linkplain Expression}
* <p>
@ -252,12 +251,12 @@ public class ExpressionResolver
if (cj == escaper)
{
if (cj < source.length - 1)
if (j < source.length - 1)
{
if (second != null)
second.append(cj);
second.append(source[j + 1]);
else
first.append(cj);
first.append(source[j + 1]);
}
j += 1;
@ -295,7 +294,8 @@ public class ExpressionResolver
content = second.toString().trim();
}
return new Expression(new String(source, i, j + 1 - i), i, j + 1, name, content);
return new Expression(this.getStartIdentifier(), this.endIdentifier,
new String(source, i, j + 1 - i), i, j + 1, name, content);
}
}
}
@ -331,7 +331,7 @@ public class ExpressionResolver
/**
* 表达式
* <p>
* 格式为#{name:content}#{content}
* 格式为${name:content}${content}#{name:content}#{content}
* </p>
*
* @author datagear@163.com
@ -341,6 +341,12 @@ public class ExpressionResolver
{
private static final long serialVersionUID = 1L;
/** 起始标识符 */
private String startIdentifier;
/** 结束标识符 */
private String endIdentifier;
/** 表达式字符串 */
private String expression;
@ -356,18 +362,24 @@ public class ExpressionResolver
/** 表达式内容 */
private String content;
public Expression(String expression, int start, int end, String content)
public Expression(String startIdentifier, String endIdentifier, String expression, int start, int end,
String content)
{
super();
this.startIdentifier = startIdentifier;
this.endIdentifier = endIdentifier;
this.expression = expression;
this.start = start;
this.end = end;
this.content = content;
}
public Expression(String expression, int start, int end, String name, String content)
public Expression(String startIdentifier, String endIdentifier, String expression, int start, int end,
String name, String content)
{
super();
this.startIdentifier = startIdentifier;
this.endIdentifier = endIdentifier;
this.expression = expression;
this.start = start;
this.end = end;
@ -375,6 +387,26 @@ public class ExpressionResolver
this.content = content;
}
public String getStartIdentifier()
{
return startIdentifier;
}
protected void setStartIdentifier(String startIdentifier)
{
this.startIdentifier = startIdentifier;
}
public String getEndIdentifier()
{
return endIdentifier;
}
protected void setEndIdentifier(String endIdentifier)
{
this.endIdentifier = endIdentifier;
}
public String getExpression()
{
return expression;

View File

@ -6,9 +6,7 @@ package org.datagear.persistence.support;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.datagear.model.Model;
import org.datagear.model.Property;
@ -24,7 +22,6 @@ import org.datagear.persistence.mapper.ModelTableMapper;
import org.datagear.persistence.mapper.PropertyModelMapper;
import org.datagear.persistence.mapper.PropertyTableMapper;
import org.datagear.persistence.mapper.RelationMapper;
import org.datagear.persistence.support.ExpressionResolver.Expression;
import org.springframework.core.convert.ConversionService;
/**
@ -33,42 +30,17 @@ import org.springframework.core.convert.ConversionService;
* @author datagear@163.com
*
*/
public class InsertPersistenceOperation extends AbstractModelPersistenceOperation
public class InsertPersistenceOperation extends AbstractExpressionModelPersistenceOperation
{
private ConversionService conversionService;
private ExpressionResolver expressionResolver;
public InsertPersistenceOperation()
{
super();
}
public InsertPersistenceOperation(ConversionService conversionService, ExpressionResolver expressionResolver)
public InsertPersistenceOperation(ConversionService conversionService,
ExpressionResolver variableExpressionResolver, ExpressionResolver sqlExpressionResolver)
{
super();
this.conversionService = conversionService;
this.expressionResolver = expressionResolver;
}
public ConversionService getConversionService()
{
return conversionService;
}
public void setConversionService(ConversionService conversionService)
{
this.conversionService = conversionService;
}
public ExpressionResolver getExpressionResolver()
{
return expressionResolver;
}
public void setExpressionResolver(ExpressionResolver expressionResolver)
{
this.expressionResolver = expressionResolver;
super(conversionService, variableExpressionResolver, sqlExpressionResolver);
}
/**
@ -83,7 +55,24 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
*/
public int insert(Connection cn, Dialect dialect, String table, Model model, Object obj)
{
return insert(cn, dialect, table, model, obj, null, null, null, new HashMap<String, Object>());
return insert(cn, dialect, table, model, obj, null, null, null, new ExpressionEvaluationContext());
}
/**
* 插入对象到指定表
*
* @param cn
* @param dialect
* @param table
* @param model
* @param obj
* @param expressionEvaluationContext
* @return
*/
public int insert(Connection cn, Dialect dialect, String table, Model model, Object obj,
ExpressionEvaluationContext expressionEvaluationContext)
{
return insert(cn, dialect, table, model, obj, null, null, null, expressionEvaluationContext);
}
/**
@ -97,15 +86,34 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param property
* @param relationMapper
* @param propertyValue
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @return
*/
public int insertPropertyTableData(Connection cn, Dialect dialect, String table, Model model, Object obj,
Property property, Object propertyValue)
{
return insertPropertyTableData(cn, dialect, table, model, obj, property, getRelationMapper(model, property),
propertyValue, new HashMap<String, Object>());
propertyValue, new ExpressionEvaluationContext());
}
/**
* 插入属性表数据
*
* @param cn
* @param dialect
* @param table
* @param model
* @param obj
* @param property
* @param relationMapper
* @param propertyValue
* @param expressionEvaluationContext
* @return
*/
public int insertPropertyTableData(Connection cn, Dialect dialect, String table, Model model, Object obj,
Property property, Object propertyValue, ExpressionEvaluationContext expressionEvaluationContext)
{
return insertPropertyTableData(cn, dialect, table, model, obj, property, getRelationMapper(model, property),
propertyValue, expressionEvaluationContext);
}
/**
@ -122,18 +130,17 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* 附加列值允许为{@code null}
* @param ignorePropertyName
* 忽略的属性名称用于处理双向关联时允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
*
*/
protected int insert(Connection cn, Dialect dialect, String table, Model model, Object obj,
String[] extraColumnNames, Object[] extraColumnValues, String ignorePropertyName,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
int count = insertModelTableData(cn, dialect, table, model, obj, extraColumnNames, extraColumnValues,
ignorePropertyName, expressionValueCache);
ignorePropertyName, expressionEvaluationContext);
insertPropertyTableData(cn, dialect, table, model, obj, ignorePropertyName, expressionValueCache);
insertPropertyTableData(cn, dialect, table, model, obj, ignorePropertyName, expressionEvaluationContext);
return count;
}
@ -155,13 +162,12 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* 附加列值允许为{@code null}
* @param ignorePropertyName
* 忽略的属性名称允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
*
*/
protected int insertModelTableData(Connection cn, Dialect dialect, String table, Model model, Object obj,
String[] extraColumnNames, Object[] extraColumnValues, String ignorePropertyName,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
Property[] properties = model.getProperties();
Object[] propertyValues = MU.getPropertyValues(model, obj, properties);
@ -179,14 +185,14 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
Object propertyValue = propertyValues[i];
List<Expression> expressions = this.expressionResolver.resolve(propertyValue);
if (expressions != null && !expressions.isEmpty())
{
propertyValue = evaluatePropertyValueForQueryExpressions(cn, model, property, (String) propertyValue,
expressions, expressionValueCache, this.conversionService, this.expressionResolver);
Object evalPropertyValue = evaluatePropertyValueIfExpression(cn, model, property, propertyValue,
expressionEvaluationContext);
propertyValues[i] = propertyValue;
property.set(obj, propertyValue);
if (evalPropertyValue != propertyValue)
{
propertyValue = evalPropertyValue;
propertyValues[i] = evalPropertyValue;
property.set(obj, evalPropertyValue);
}
}
@ -275,11 +281,10 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param obj
* @param ignorePropertyName
* 忽略的属性名称用于处理双向关联时允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
*/
protected void insertPropertyTableData(Connection cn, Dialect dialect, String table, Model model, Object obj,
String ignorePropertyName, Map<String, Object> expressionValueCache)
String ignorePropertyName, ExpressionEvaluationContext expressionEvaluationContext)
{
Property[] properties = model.getProperties();
@ -295,7 +300,7 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
continue;
insertPropertyTableData(cn, dialect, table, model, obj, property, getRelationMapper(model, property),
propertyValue, expressionValueCache);
propertyValue, expressionEvaluationContext);
}
}
@ -310,17 +315,16 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param property
* @param relationMapper
* @param propertyValue
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int insertPropertyTableData(Connection cn, Dialect dialect, String table, Model model, Object obj,
Property property, RelationMapper relationMapper, Object propertyValue,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
if (this.expressionResolver.isExpression(propertyValue))
if (isExpression(propertyValue))
{
return PERSISTENCE_IGNORED;
}
@ -330,7 +334,7 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
propertyValue);
return insertPropertyTableData(cn, dialect, table, model, obj, property, propertyModelMapper,
toArray(propertyValue), null, expressionValueCache);
toArray(propertyValue), null, expressionEvaluationContext);
}
else
{
@ -351,7 +355,7 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
int myCount = insertPropertyTableData(cn, dialect, table, model, obj, property,
PropertyModelMapper.valueOf(property, relationMapper, propertyModel), myPropValues,
myPropValueIdexes, expressionValueCache);
myPropValueIdexes, expressionEvaluationContext);
if (myCount > 0)
count += myCount;
@ -374,12 +378,11 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param propValues
* @param propValueOrders
* 允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
*/
protected int insertPropertyTableData(Connection cn, Dialect dialect, String table, Model model, Object obj,
Property property, PropertyModelMapper<?> propertyModelMapper, Object[] propValues, long[] propValueOrders,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
if (propertyModelMapper.isModelTableMapperInfo())
{
@ -396,21 +399,21 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
throw new IllegalArgumentException();
return insertPropertyTableDataForCompositeModelTableMapper(cn, dialect, table, model, obj, property, mpmm,
propValues[0], expressionValueCache);
propValues[0], expressionEvaluationContext);
}
else if (propertyModelMapper.isPropertyTableMapperInfo())
{
PropertyModelMapper<PropertyTableMapper> ppmm = propertyModelMapper.castPropertyTableMapperInfo();
return insertPropertyTableDataForPropertyTableMapper(cn, dialect, table, model, obj, property, ppmm,
propValues, propValueOrders, expressionValueCache);
propValues, propValueOrders, expressionEvaluationContext);
}
else if (propertyModelMapper.isJoinTableMapperInfo())
{
PropertyModelMapper<JoinTableMapper> jpmm = propertyModelMapper.castJoinTableMapperInfo();
return insertPropertyTableDataForJoinTableMapper(cn, dialect, table, model, obj, property, jpmm, propValues,
propValueOrders, expressionValueCache);
propValueOrders, expressionEvaluationContext);
}
else
throw new UnsupportedOperationException();
@ -427,13 +430,12 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param property
* @param propertyModelMapper
* @param propValue
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
*
*/
protected int insertPropertyTableDataForCompositeModelTableMapper(Connection cn, Dialect dialect, String table,
Model model, Object obj, Property property, PropertyModelMapper<ModelTableMapper> propertyModelMapper,
Object propValue, Map<String, Object> expressionValueCache)
Object propValue, ExpressionEvaluationContext expressionEvaluationContext)
{
Model propertyModel = propertyModelMapper.getModel();
@ -441,7 +443,7 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
return PERSISTENCE_IGNORED;
return insert(cn, dialect, getTableName(propertyModel), propertyModel, propValue, null, null, null,
expressionValueCache);
expressionEvaluationContext);
}
/**
@ -457,25 +459,24 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param propValues
* @param propValueOrders
* 允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int insertPropertyTableDataForPropertyTableMapper(Connection cn, Dialect dialect, String table,
Model model, Object obj, Property property, PropertyModelMapper<PropertyTableMapper> propertyModelMapper,
Object[] propValues, long[] propValueOrders, Map<String, Object> expressionValueCache)
Object[] propValues, long[] propValueOrders, ExpressionEvaluationContext expressionEvaluationContext)
{
PropertyTableMapper mapper = propertyModelMapper.getMapper();
if (mapper.isPrimitivePropertyMapper())
{
return insertPropertyTableDataForPrimitiveValuePropertyTableMapper(cn, dialect, table, model, obj, property,
propertyModelMapper, propValues, propValueOrders, expressionValueCache);
propertyModelMapper, propValues, propValueOrders, expressionEvaluationContext);
}
else
{
return insertPropertyTableDataForCompositePropertyTableMapper(cn, dialect, table, model, obj, property,
propertyModelMapper, propValues, propValueOrders, expressionValueCache);
propertyModelMapper, propValues, propValueOrders, expressionEvaluationContext);
}
}
@ -492,14 +493,13 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param propValues
* @param propValueOrders
* 允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
*
*/
protected int insertPropertyTableDataForPrimitiveValuePropertyTableMapper(Connection cn, Dialect dialect,
String table, Model model, Object obj, Property property,
PropertyModelMapper<PropertyTableMapper> propertyModelMapper, Object[] propValues, long[] propValueOrders,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
@ -531,11 +531,13 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
{
Object propertyValue = propValues[i];
List<Expression> expressions = this.expressionResolver.resolve(propertyValue);
if (expressions != null && !expressions.isEmpty())
Object evalPropertyValue = evaluatePropertyValueIfExpression(cn, model, property, propertyValue,
expressionEvaluationContext);
if (evalPropertyValue != propertyValue)
{
propertyValue = evaluatePropertyValueForQueryExpressions(cn, model, property, (String) propertyValue,
expressions, expressionValueCache, this.conversionService, this.expressionResolver);
propertyValue = evalPropertyValue;
propValues[i] = evalPropertyValue;
}
Object columnValue = getColumnValue(cn, model, property, propertyModelMapper, propertyValue);
@ -569,13 +571,12 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param propValues
* @param propValueOrders
* 允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int insertPropertyTableDataForCompositePropertyTableMapper(Connection cn, Dialect dialect, String table,
Model model, Object obj, Property property, PropertyModelMapper<PropertyTableMapper> propertyModelMapper,
Object[] propValues, long[] propValueOrders, Map<String, Object> expressionValueCache)
Object[] propValues, long[] propValueOrders, ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
@ -596,7 +597,7 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
(propValueOrders == null ? null : propValueOrders[i]));
int myCount = insert(cn, dialect, ptable, propertyModel, propValues[i], allMapperColumNames,
allMapperColumnValues, getMappedByWith(mapper), expressionValueCache);
allMapperColumnValues, getMappedByWith(mapper), expressionEvaluationContext);
if (myCount > 0)
count += myCount;
@ -693,13 +694,12 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
* @param propValues
* @param propValueOrders
* 允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
*
*/
protected int insertPropertyTableDataForJoinTableMapper(Connection cn, Dialect dialect, String table, Model model,
Object obj, Property property, PropertyModelMapper<JoinTableMapper> propertyModelMapper,
Object[] propValues, long[] propValueOrders, Map<String, Object> expressionValueCache)
Object[] propValues, long[] propValueOrders, ExpressionEvaluationContext expressionEvaluationContext)
{
Model propertyModel = propertyModelMapper.getModel();
@ -709,7 +709,8 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
{
if (PMU.isPrivate(model, property, propertyModel))
{
insert(cn, dialect, ptable, propertyModel, propValues[i], null, null, null, expressionValueCache);
insert(cn, dialect, ptable, propertyModel, propValues[i], null, null, null,
expressionEvaluationContext);
}
}
@ -844,7 +845,7 @@ public class InsertPersistenceOperation extends AbstractModelPersistenceOperatio
if (valueGenerator != null)
propValue = valueGenerator.generate(model, property, obj);
if (propValue != null && this.expressionResolver.isExpression(propValue))
if (propValue != null && isExpression(propValue))
property.set(obj, propValue);
}
}

View File

@ -6,7 +6,6 @@ package org.datagear.persistence.support;
import java.sql.SQLException;
import org.datagear.persistence.PersistenceException;
import org.datagear.persistence.support.ExpressionResolver.Expression;
/**
@ -15,20 +14,12 @@ import org.datagear.persistence.support.ExpressionResolver.Expression;
* @author datagear@163.com
*
*/
public class SqlExpressionErrorException extends PersistenceException
public class SqlExpressionErrorException extends ExpressionErrorException
{
private static final long serialVersionUID = 1L;
private Expression expression;
public SqlExpressionErrorException(Expression expression, SQLException cause)
{
super(expression.getContent(), cause);
this.expression = expression;
}
public Expression getExpression()
{
return expression;
super(expression, cause);
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
/**
* SQL表达式解析器
* <p>
* 此类将表达式格式固化为<code>${name:value}${value}</code>用于解析SQL表达式
* </p>
*
* @author datagear@163.com
*
*/
public class SqlExpressionResolver extends ExpressionResolver
{
public SqlExpressionResolver()
{
super();
super.setStartIdentifier(DEFAULT_START_IDENTIFIER_DOLLAR);
super.setSeparator(DEFAULT_SEPARATOR);
super.setEndIdentifier(DEFAULT_END_IDENTIFIER);
}
@Override
public void setStartIdentifier(String startIdentifier)
{
throw new UnsupportedOperationException();
}
@Override
public void setEndIdentifier(String endIdentifier)
{
throw new UnsupportedOperationException();
}
@Override
public void setSeparator(String separator)
{
throw new UnsupportedOperationException();
}
}

View File

@ -6,9 +6,7 @@ package org.datagear.persistence.support;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.datagear.model.Model;
import org.datagear.model.Property;
@ -24,7 +22,6 @@ import org.datagear.persistence.mapper.ModelTableMapper;
import org.datagear.persistence.mapper.PropertyModelMapper;
import org.datagear.persistence.mapper.PropertyTableMapper;
import org.datagear.persistence.mapper.RelationMapper;
import org.datagear.persistence.support.ExpressionResolver.Expression;
import org.springframework.core.convert.ConversionService;
/**
@ -33,7 +30,7 @@ import org.springframework.core.convert.ConversionService;
* @author datagear@163.com
*
*/
public class UpdatePersistenceOperation extends AbstractModelPersistenceOperation
public class UpdatePersistenceOperation extends AbstractExpressionModelPersistenceOperation
{
/** 当记录未做修改时,返回此标识 */
public static final int UNCHANGED = PERSISTENCE_IGNORED - 1;
@ -45,10 +42,6 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
private DeletePersistenceOperation deletePersistenceOperation;
private ConversionService conversionService;
private ExpressionResolver expressionResolver;
public UpdatePersistenceOperation()
{
super();
@ -56,13 +49,11 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
public UpdatePersistenceOperation(InsertPersistenceOperation insertPersistenceOperation,
DeletePersistenceOperation deletePersistenceOperation, ConversionService conversionService,
ExpressionResolver expressionResolver)
ExpressionResolver variableExpressionResolver, ExpressionResolver sqlExpressionResolver)
{
super();
super(conversionService, variableExpressionResolver, sqlExpressionResolver);
this.insertPersistenceOperation = insertPersistenceOperation;
this.deletePersistenceOperation = deletePersistenceOperation;
this.conversionService = conversionService;
this.expressionResolver = expressionResolver;
}
public boolean isHandleMultipleProperty()
@ -95,26 +86,6 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
this.deletePersistenceOperation = deletePersistenceOperation;
}
public ConversionService getConversionService()
{
return conversionService;
}
public void setConversionService(ConversionService conversionService)
{
this.conversionService = conversionService;
}
public ExpressionResolver getExpressionResolver()
{
return expressionResolver;
}
public void setExpressionResolver(ExpressionResolver expressionResolver)
{
this.expressionResolver = expressionResolver;
}
/**
* 更新
*
@ -122,8 +93,6 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
* @param dialect
* @param table
* @param model
* @param originalCondition
* 用于确定原始数据记录的模型表条件
* @param originalObj
* 原始数据
* @param updateObj
@ -135,7 +104,30 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
SqlBuilder originalCondition = buildRecordCondition(cn, dialect, model, originalObj, null);
return update(cn, dialect, table, model, originalCondition, originalObj, updateObj, null, null, null,
new HashMap<String, Object>());
new ExpressionEvaluationContext());
}
/**
* 更新
*
* @param cn
* @param dialect
* @param table
* @param model
* @param originalObj
* 原始数据
* @param updateObj
* 待更新的数据
* @param expressionEvaluationContext
* @return
*/
public int update(Connection cn, Dialect dialect, String table, Model model, Object originalObj, Object updateObj,
ExpressionEvaluationContext expressionEvaluationContext)
{
SqlBuilder originalCondition = buildRecordCondition(cn, dialect, model, originalObj, null);
return update(cn, dialect, table, model, originalCondition, originalObj, updateObj, null, null, null,
expressionEvaluationContext);
}
/**
@ -159,7 +151,32 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
Object updatePropertyValue)
{
return updatePropertyTableData(cn, dialect, table, model, condition, property, propertyModelMapper,
originalPropertyValue, updatePropertyValue, null, true, new HashMap<String, Object>());
originalPropertyValue, updatePropertyValue, null, true, new ExpressionEvaluationContext());
}
/**
* 更新属性表数据
*
* @param cn
* @param dialect
* @param table
* @param model
* @param condition
* @param property
* @param propertyModelMapper
* @param originalPropertyValue
* 原始属性值
* @param updatePropertyValue
* 待更新的属性值允许为{@code null}
* @param expressionEvaluationContext
* @return
*/
public int updatePropertyTableData(Connection cn, Dialect dialect, String table, Model model, SqlBuilder condition,
Property property, PropertyModelMapper<?> propertyModelMapper, Object originalPropertyValue,
Object updatePropertyValue, ExpressionEvaluationContext expressionEvaluationContext)
{
return updatePropertyTableData(cn, dialect, table, model, condition, property, propertyModelMapper,
originalPropertyValue, updatePropertyValue, null, true, expressionEvaluationContext);
}
/**
@ -181,13 +198,12 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
* 附加列值允许为{@code null}
* @param ignorePropertyName
* 忽略的属性名称用于处理双向关联时允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int update(Connection cn, Dialect dialect, String table, Model model, SqlBuilder originalCondition,
Object originalObj, Object updateObj, String[] extraColumnNames, Object[] extraColumnValues,
String ignorePropertyName, Map<String, Object> expressionValueCache)
String ignorePropertyName, ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
@ -207,14 +223,14 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
Object propertyValue = updatePropertyValues[i];
List<Expression> expressions = this.expressionResolver.resolve(propertyValue);
if (expressions != null && !expressions.isEmpty())
{
propertyValue = evaluatePropertyValueForQueryExpressions(cn, model, property, (String) propertyValue,
expressions, expressionValueCache, this.conversionService, this.expressionResolver);
Object evalPropertyValue = evaluatePropertyValueIfExpression(cn, model, property, propertyValue,
expressionEvaluationContext);
updatePropertyValues[i] = propertyValue;
property.set(updateObj, propertyValue);
if (evalPropertyValue != propertyValue)
{
propertyValue = evalPropertyValue;
updatePropertyValues[i] = evalPropertyValue;
property.set(updateObj, evalPropertyValue);
}
}
@ -268,12 +284,12 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
{
int myUpdateCount = updatePropertyTableData(cn, dialect, table, model, originalCondition,
property, pmm, originalPropertyValue, updatePropertyValue, updateObj, false,
expressionValueCache);
expressionEvaluationContext);
if (myUpdateCount == 0)
insertPersistenceOperation.insertPropertyTableData(cn, dialect, table, model, updateObj,
property, pmm, new Object[] { updatePropertyValue }, null,
expressionValueCache);
expressionEvaluationContext);
}
else
{
@ -307,12 +323,12 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
int myUpdateCount = updatePropertyTableData(cn, dialect, table, model, updateCondition,
updateInfo.getProperty(), updateInfo.getPropertyModelMapper(),
originalPropertyValues[updateInfo.getPropertyIndex()], updatePropertyValue, null, false,
expressionValueCache);
expressionEvaluationContext);
if (myUpdateCount == 0)
insertPersistenceOperation.insertPropertyTableData(cn, dialect, table, model, updateObj,
updateInfo.getProperty(), updateInfo.getPropertyModelMapper(),
new Object[] { updatePropertyValue }, null, expressionValueCache);
new Object[] { updatePropertyValue }, null, expressionEvaluationContext);
}
}
@ -427,14 +443,13 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
* 需要处理外键更新的对象允许为{@code null}
* @param updateModelTable
* 是否更新模型表数据
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int updatePropertyTableData(Connection cn, Dialect dialect, String table, Model model,
SqlBuilder condition, Property property, PropertyModelMapper<?> propertyModelMapper,
Object originalPropertyValue, Object updatePropertyValue, Object keyUpdateObj, boolean updateModelTable,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
@ -443,21 +458,21 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
PropertyModelMapper<ModelTableMapper> mpmm = propertyModelMapper.castModelTableMapperInfo();
count = updatePropertyTableDataForModelTableMapper(cn, dialect, table, model, condition, property, mpmm,
originalPropertyValue, updatePropertyValue, updateModelTable, expressionValueCache);
originalPropertyValue, updatePropertyValue, updateModelTable, expressionEvaluationContext);
}
else if (propertyModelMapper.isPropertyTableMapperInfo())
{
PropertyModelMapper<PropertyTableMapper> ppmm = propertyModelMapper.castPropertyTableMapperInfo();
count = updatePropertyTableDataForPropertyTableMapper(cn, dialect, table, model, condition, property, ppmm,
originalPropertyValue, updatePropertyValue, keyUpdateObj, expressionValueCache);
originalPropertyValue, updatePropertyValue, keyUpdateObj, expressionEvaluationContext);
}
else if (propertyModelMapper.isJoinTableMapperInfo())
{
PropertyModelMapper<JoinTableMapper> jpmm = propertyModelMapper.castJoinTableMapperInfo();
count = updatePropertyTableDataForJoinTableMapper(cn, dialect, table, model, condition, property, jpmm,
originalPropertyValue, updatePropertyValue, keyUpdateObj, expressionValueCache);
originalPropertyValue, updatePropertyValue, keyUpdateObj, expressionEvaluationContext);
}
else
throw new UnsupportedOperationException();
@ -482,14 +497,13 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
* 待更新的属性值允许为{@code null}
* @param updateModelTable
* 是否更新模型表数据
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int updatePropertyTableDataForModelTableMapper(Connection cn, Dialect dialect, String table, Model model,
SqlBuilder condition, Property property, PropertyModelMapper<ModelTableMapper> propertyModelMapper,
Object originalPropertyValue, Object updatePropertyValue, boolean updateModelTable,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
@ -519,7 +533,7 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
{
count = update(cn, dialect, table, pmodel,
buildRecordCondition(cn, dialect, pmodel, originalPropertyValue, null), originalPropertyValue,
updatePropertyValue, null, null, getMappedByWith(mapper), expressionValueCache);
updatePropertyValue, null, null, getMappedByWith(mapper), expressionEvaluationContext);
if (updateModelTable)
{
@ -571,14 +585,13 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
* 待更新的属性值允许为{@code null}
* @param keyUpdateObj
* 需要处理外键更新的对象允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int updatePropertyTableDataForPropertyTableMapper(Connection cn, Dialect dialect, String table,
Model model, SqlBuilder condition, Property property,
PropertyModelMapper<PropertyTableMapper> propertyModelMapper, Object originalPropertyValue,
Object updatePropertyValue, Object keyUpdateObj, Map<String, Object> expressionValueCache)
Object updatePropertyValue, Object keyUpdateObj, ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
@ -621,15 +634,14 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
{
String columnName = toQuoteName(dialect, mapper.getPrimitiveColumnName());
List<Expression> expressions = this.expressionResolver.resolve(updatePropertyValue);
if (expressions != null && !expressions.isEmpty())
{
updatePropertyValue = evaluatePropertyValueForQueryExpressions(cn, model, property,
(String) updatePropertyValue, expressions, expressionValueCache, this.conversionService,
this.expressionResolver);
Object evalUpdatePropertyValue = evaluatePropertyValueIfExpression(cn, model, property,
updatePropertyValue, expressionEvaluationContext);
if (evalUpdatePropertyValue != updatePropertyValue)
{
updatePropertyValue = evalUpdatePropertyValue;
Object columnValue = getColumnValue(cn, model, property, propertyModelMapper,
updatePropertyValue);
evalUpdatePropertyValue);
sql.sqldSuffix(columnName, "=" + columnValue);
}
@ -653,7 +665,7 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
{
count = update(cn, dialect, getTableName(propertyModel), propertyModel, ptableCondition,
originalPropertyValue, updatePropertyValue, mkeyColumnNames, mkeyColumnValues,
getMappedByWith(propertyModelMapper.getMapper()), expressionValueCache);
getMappedByWith(propertyModelMapper.getMapper()), expressionEvaluationContext);
}
return count;
@ -675,14 +687,13 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
* 待更新的属性值允许为{@code null}
* @param keyUpdateObj
* 需要处理外键更新的对象允许为{@code null}
* @param expressionValueCache
* 用于缓存SQL表达式求值结果的映射表
* @param expressionEvaluationContext
* @return
*/
protected int updatePropertyTableDataForJoinTableMapper(Connection cn, Dialect dialect, String table, Model model,
SqlBuilder condition, Property property, PropertyModelMapper<JoinTableMapper> propertyModelMapper,
Object originalPropertyValue, Object updatePropertyValue, Object keyUpdateObj,
Map<String, Object> expressionValueCache)
ExpressionEvaluationContext expressionEvaluationContext)
{
int count = 0;
@ -701,7 +712,7 @@ public class UpdatePersistenceOperation extends AbstractModelPersistenceOperatio
{
count = update(cn, dialect, getTableName(propertyModel), propertyModel, ptableCondition,
originalPropertyValue, updatePropertyValue, null, null,
getMappedByWith(propertyModelMapper.getMapper()), expressionValueCache);
getMappedByWith(propertyModelMapper.getMapper()), expressionEvaluationContext);
if (keyUpdateObj != null)
{

View File

@ -0,0 +1,37 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
/**
* 用于变量表达式求值的Bean
*
* @author datagear@163.com
*
*/
public class VariableExpressionBean
{
private int index;
public VariableExpressionBean()
{
super();
}
public VariableExpressionBean(int index)
{
super();
this.index = index;
}
public int getIndex()
{
return index;
}
public void setIndex(int index)
{
this.index = index;
}
}

View File

@ -0,0 +1,23 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
import org.datagear.persistence.support.ExpressionResolver.Expression;
/**
* 变量表达式执行出错
*
* @author datagear@163.com
*
*/
public class VariableExpressionErrorException extends ExpressionErrorException
{
private static final long serialVersionUID = 1L;
public VariableExpressionErrorException(Expression expression, Exception cause)
{
super(expression, cause);
}
}

View File

@ -0,0 +1,43 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
/**
* 变量表达式解析器
* <p>
* 此类将表达式格式固化为<code>#{name:value}#{value}</code>用于解析变量表达式
* </p>
*
* @author datagear@163.com
*
*/
public class VariableExpressionResolver extends ExpressionResolver
{
public VariableExpressionResolver()
{
super();
super.setStartIdentifier(DEFAULT_START_IDENTIFIER_SHARP);
super.setSeparator(DEFAULT_SEPARATOR);
super.setEndIdentifier(DEFAULT_END_IDENTIFIER);
}
@Override
public void setStartIdentifier(String startIdentifier)
{
throw new UnsupportedOperationException();
}
@Override
public void setEndIdentifier(String endIdentifier)
{
throw new UnsupportedOperationException();
}
@Override
public void setSeparator(String separator)
{
throw new UnsupportedOperationException();
}
}

View File

@ -13,12 +13,12 @@ import org.junit.Test;
* @author datagear@163.com
*
*/
public class AbstractModelPersistenceOperationTest
public class AbstractExpressionModelPersistenceOperationTest
{
@Test
public void isSelectSqlTest()
{
AbstractModelPersistenceOperation persistenceOperation = new AbstractModelPersistenceOperation()
AbstractExpressionModelPersistenceOperation persistenceOperation = new AbstractExpressionModelPersistenceOperation()
{
};

View File

@ -169,6 +169,21 @@ public class ExpressionResolverTest
Assert.assertEquals("content2", e.getContent());
}
}
{
List<Expression> expressions = expressionResolver.resolve("prefix\\${content0}");
Assert.assertEquals(0, expressions.size());
}
{
List<Expression> expressions = expressionResolver.resolve("prefix${cont\\:ent\\}0}");
Assert.assertEquals(1, expressions.size());
Expression e = expressions.get(0);
Assert.assertEquals("cont:ent}0", e.getContent());
}
}
@Test

View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2018 datagear.org. All Rights Reserved.
*/
package org.datagear.persistence.support;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.expression.spel.standard.SpelExpressionParser;
/**
* {@linkplain SpelExpressionParser}测试类
*
* @author datagear@163.com
*
*/
public class SpelExpressionParserTest
{
private SpelExpressionParser spelExpressionParser = new SpelExpressionParser();
@Test
public void test()
{
{
int value = (Integer) spelExpressionParser.parseExpression("index").getValue(new TestBean());
Assert.assertEquals(0, value);
}
{
int value = (Integer) spelExpressionParser.parseExpression("index").getValue(new TestBean(2));
Assert.assertEquals(2, value);
}
{
int value = (Integer) spelExpressionParser.parseExpression("index * 5").getValue(new TestBean(2));
Assert.assertEquals(10, value);
}
}
protected static class TestBean
{
private int index;
public TestBean()
{
super();
}
public TestBean(int index)
{
super();
this.index = index;
}
public int getIndex()
{
return index;
}
public void setIndex(int index)
{
this.index = index;
}
}
}

View File

@ -23,6 +23,7 @@ import org.datagear.dbmodel.DatabaseModelResolverException;
import org.datagear.persistence.PersistenceException;
import org.datagear.persistence.UnsupportedDialectException;
import org.datagear.persistence.support.SqlExpressionErrorException;
import org.datagear.persistence.support.VariableExpressionErrorException;
import org.datagear.web.convert.IllegalSourceValueException;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindException;
@ -50,7 +51,8 @@ public class ControllerAdvice extends AbstractController
public String handleControllerMissingServletRequestParameterException(HttpServletRequest request,
HttpServletResponse response, MissingServletRequestParameterException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(MissingServletRequestParameterException.class),
exception, false);
return ERROR_PAGE_URL;
}
@ -60,7 +62,7 @@ public class ControllerAdvice extends AbstractController
public String handleControllerBindException(HttpServletRequest request, HttpServletResponse response,
BindException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(BindException.class), exception, false);
return ERROR_PAGE_URL;
}
@ -70,7 +72,8 @@ public class ControllerAdvice extends AbstractController
public String handleControllerMethodArgumentNotValidException(HttpServletRequest request,
HttpServletResponse response, MethodArgumentNotValidException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(MethodArgumentNotValidException.class), exception,
false);
return ERROR_PAGE_URL;
}
@ -80,7 +83,8 @@ public class ControllerAdvice extends AbstractController
public String handleAuthenticationFailedException(HttpServletRequest request, HttpServletResponse response,
AuthenticationFailedException exception)
{
setOperationMessageForException(request, exception, true);
setOperationMessageForThrowable(request, buildMessageCode(AuthenticationFailedException.class), exception,
true);
return ERROR_PAGE_URL;
}
@ -90,7 +94,7 @@ public class ControllerAdvice extends AbstractController
public String handleControllerIllegalInputException(HttpServletRequest request, HttpServletResponse response,
IllegalInputException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(IllegalInputException.class), exception, false);
return ERROR_PAGE_URL;
}
@ -100,7 +104,7 @@ public class ControllerAdvice extends AbstractController
public String handleControllerRecordNotFoundException(HttpServletRequest request, HttpServletResponse response,
RecordNotFoundException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(RecordNotFoundException.class), exception, false);
return ERROR_PAGE_URL;
}
@ -110,7 +114,8 @@ public class ControllerAdvice extends AbstractController
public String handleControllerRecordNotFoundOrNoPermissionException(HttpServletRequest request,
HttpServletResponse response, RecordNotFoundOrPermissionDeniedException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(RecordNotFoundOrPermissionDeniedException.class),
exception, false);
return ERROR_PAGE_URL;
}
@ -120,7 +125,7 @@ public class ControllerAdvice extends AbstractController
public String handleControllerSchemaNotFoundException(HttpServletRequest request, HttpServletResponse response,
SchemaNotFoundException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(SchemaNotFoundException.class), exception, false);
return ERROR_PAGE_URL;
}
@ -130,8 +135,8 @@ public class ControllerAdvice extends AbstractController
public String handleControllerIllegalSourceValueException(HttpServletRequest request, HttpServletResponse response,
IllegalSourceValueException exception)
{
setOperationMessageForException(request, exception, false, exception.getSourceValue(),
exception.getTargetType().getName());
setOperationMessageForThrowable(request, buildMessageCode(IllegalSourceValueException.class), exception, false,
exception.getSourceValue(), exception.getTargetType().getName());
return ERROR_PAGE_URL;
}
@ -141,7 +146,19 @@ public class ControllerAdvice extends AbstractController
public String handleControllerFileNotFoundException(HttpServletRequest request, HttpServletResponse response,
FileNotFoundException exception)
{
setOperationMessageForException(request, exception, false, exception.getFileName());
setOperationMessageForThrowable(request, buildMessageCode(FileNotFoundException.class), exception, false,
exception.getFileName());
return ERROR_PAGE_URL;
}
@ExceptionHandler(VariableExpressionErrorException.class)
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String handlePersistenceVariableExpressionErrorException(HttpServletRequest request,
HttpServletResponse response, VariableExpressionErrorException exception)
{
setOperationMessageForThrowable(request, buildMessageCode(VariableExpressionErrorException.class),
exception.getCause(), false, exception.getExpression().getContent());
return ERROR_PAGE_URL;
}
@ -151,7 +168,8 @@ public class ControllerAdvice extends AbstractController
public String handlePersistenceSqlExpressionErrorException(HttpServletRequest request, HttpServletResponse response,
SqlExpressionErrorException exception)
{
setOperationMessageForExceptionCause(request, exception);
setOperationMessageForThrowable(request, buildMessageCode(SqlExpressionErrorException.class),
exception.getCause(), true, exception.getExpression().getContent());
return ERROR_PAGE_URL;
}
@ -161,7 +179,7 @@ public class ControllerAdvice extends AbstractController
public String handlePersistenceUnsupportedDialectException(HttpServletRequest request, HttpServletResponse response,
UnsupportedDialectException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(UnsupportedDialectException.class), exception, false);
return ERROR_PAGE_URL;
}
@ -172,9 +190,10 @@ public class ControllerAdvice extends AbstractController
PersistenceException exception)
{
if (exception.getCause() instanceof SQLException)
setOperationMessageForExceptionCause(request, exception);
setOperationMessageForThrowable(request, buildMessageCode(PersistenceException.class), exception.getCause(),
true);
else
setOperationMessageForException(request, exception, true);
setOperationMessageForThrowable(request, buildMessageCode(PersistenceException.class), exception, true);
return ERROR_PAGE_URL;
}
@ -184,7 +203,8 @@ public class ControllerAdvice extends AbstractController
public String handleDbmodelDatabaseInfoResolverException(HttpServletRequest request, HttpServletResponse response,
DatabaseInfoResolverException exception)
{
setOperationMessageForException(request, exception, true);
setOperationMessageForThrowable(request, buildMessageCode(DatabaseInfoResolverException.class), exception,
true);
return ERROR_PAGE_URL;
}
@ -194,7 +214,8 @@ public class ControllerAdvice extends AbstractController
public String handleDbmodelDatabaseModelResolverException(HttpServletRequest request, HttpServletResponse response,
DatabaseModelResolverException exception)
{
setOperationMessageForException(request, exception, true);
setOperationMessageForThrowable(request, buildMessageCode(DatabaseModelResolverException.class), exception,
true);
return ERROR_PAGE_URL;
}
@ -204,7 +225,8 @@ public class ControllerAdvice extends AbstractController
public String handleDbmodelTableNotExistsException(HttpServletRequest request, HttpServletResponse response,
TableNotExistsException exception)
{
setOperationMessageForException(request, exception, false, exception.getTableName());
setOperationMessageForThrowable(request, buildMessageCode(TableNotExistsException.class), exception, false,
exception.getTableName());
return ERROR_PAGE_URL;
}
@ -214,7 +236,7 @@ public class ControllerAdvice extends AbstractController
public String handleConnectionConnectionSourceException(HttpServletRequest request, HttpServletResponse response,
ConnectionSourceException exception)
{
setOperationMessageForException(request, exception, true);
setOperationMessageForThrowable(request, buildMessageCode(ConnectionSourceException.class), exception, true);
return ERROR_PAGE_URL;
}
@ -224,7 +246,7 @@ public class ControllerAdvice extends AbstractController
public String handleConnectionDriverEntityManagerException(HttpServletRequest request, HttpServletResponse response,
DriverEntityManagerException exception)
{
setOperationMessageForException(request, exception, true);
setOperationMessageForThrowable(request, buildMessageCode(DriverEntityManagerException.class), exception, true);
return ERROR_PAGE_URL;
}
@ -234,7 +256,8 @@ public class ControllerAdvice extends AbstractController
public String handleConnectionDriverNotFoundException(HttpServletRequest request, HttpServletResponse response,
DriverNotFoundException exception)
{
setOperationMessageForException(request, exception, false, exception.getDriverClassName());
setOperationMessageForThrowable(request, buildMessageCode(DriverNotFoundException.class), exception, false,
exception.getDriverClassName());
return ERROR_PAGE_URL;
}
@ -244,7 +267,8 @@ public class ControllerAdvice extends AbstractController
public String handleConnectionDriverClassFormatErrorException(HttpServletRequest request,
HttpServletResponse response, DriverClassFormatErrorException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(DriverClassFormatErrorException.class), exception,
false);
return ERROR_PAGE_URL;
}
@ -254,7 +278,7 @@ public class ControllerAdvice extends AbstractController
public String handleConnectionURLNotAcceptedException(HttpServletRequest request, HttpServletResponse response,
URLNotAcceptedException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(URLNotAcceptedException.class), exception, false);
return ERROR_PAGE_URL;
}
@ -264,7 +288,8 @@ public class ControllerAdvice extends AbstractController
public String handleConnectionUnsupportedGetConnectionException(HttpServletRequest request,
HttpServletResponse response, UnsupportedGetConnectionException exception)
{
setOperationMessageForException(request, exception, false);
setOperationMessageForThrowable(request, buildMessageCode(UnsupportedGetConnectionException.class), exception,
false);
return ERROR_PAGE_URL;
}
@ -274,25 +299,15 @@ public class ControllerAdvice extends AbstractController
public String handleConnectionEstablishConnectionException(HttpServletRequest request, HttpServletResponse response,
EstablishConnectionException exception)
{
setOperationMessageForExceptionCause(request, exception);
setOperationMessageForThrowable(request, buildMessageCode(EstablishConnectionException.class),
exception.getCause(), true);
return ERROR_PAGE_URL;
}
protected void setOperationMessageForException(HttpServletRequest request, Exception exception,
boolean traceException, Object... messageArgs)
protected String buildMessageCode(Class<? extends Throwable> clazz)
{
String code = buildMessageCode(exception.getClass().getSimpleName());
setOperationMessageForThrowable(request, code, exception, traceException, messageArgs);
}
protected void setOperationMessageForExceptionCause(HttpServletRequest request, Exception exception,
Object... messageArgs)
{
String code = buildMessageCode(exception.getClass().getSimpleName());
setOperationMessageForThrowable(request, code, exception.getCause(), true, messageArgs);
return buildMessageCode(clazz.getSimpleName());
}
@Override

View File

@ -33,6 +33,8 @@ import org.datagear.model.support.DefaultDynamicBean;
import org.datagear.model.support.DynamicBean;
import org.datagear.model.support.PropertyPath;
import org.datagear.persistence.support.ExpressionResolver;
import org.datagear.persistence.support.SqlExpressionResolver;
import org.datagear.persistence.support.VariableExpressionResolver;
import org.springframework.core.convert.ConversionService;
/**
@ -64,7 +66,9 @@ public abstract class AbstractDataConverter
private ConversionService conversionService;
private ExpressionResolver expressionResolver = new ExpressionResolver();
private ExpressionResolver variableExpressionResolver = new VariableExpressionResolver();
private ExpressionResolver sqlExpressionResolver = new SqlExpressionResolver();
private Map<Class<?>, Class<?>> instanceTypeMap = new HashMap<Class<?>, Class<?>>();
@ -91,14 +95,24 @@ public abstract class AbstractDataConverter
this.conversionService = conversionService;
}
public ExpressionResolver getExpressionResolver()
public ExpressionResolver getVariableExpressionResolver()
{
return expressionResolver;
return variableExpressionResolver;
}
public void setExpressionResolver(ExpressionResolver expressionResolver)
public void setVariableExpressionResolver(ExpressionResolver variableExpressionResolver)
{
this.expressionResolver = expressionResolver;
this.variableExpressionResolver = variableExpressionResolver;
}
public ExpressionResolver getSqlExpressionResolver()
{
return sqlExpressionResolver;
}
public void setSqlExpressionResolver(ExpressionResolver sqlExpressionResolver)
{
this.sqlExpressionResolver = sqlExpressionResolver;
}
public Map<Class<?>, Class<?>> getInstanceTypeMap()
@ -167,7 +181,7 @@ public abstract class AbstractDataConverter
{
String str = (String) obj;
if (this.expressionResolver.isExpression(str))
if (isExpression(str))
return (T) str;
if (str.isEmpty() && !String.class.equals(targetType))
@ -385,6 +399,11 @@ public abstract class AbstractDataConverter
return getInstanceType(instanceType);
}
protected boolean isExpression(Object obj)
{
return this.variableExpressionResolver.isExpression(obj) || this.sqlExpressionResolver.isExpression(obj);
}
/**
* 比较{@code "[xxx]"}格式字符串的大小
*

View File

@ -207,9 +207,15 @@
<bean id="selectOptions" class="org.datagear.persistence.support.SelectOptions" />
<bean id="variableExpressionResolver" class="org.datagear.persistence.support.VariableExpressionResolver" />
<bean id="sqlExpressionResolver" class="org.datagear.persistence.support.SqlExpressionResolver" />
<bean id="persistenceManager" class="org.datagear.persistence.support.DefaultPersistenceManager">
<property name="dialectSource" ref="dialectSource" />
<property name="conversionService" ref="conversionService" />
<property name="variableExpressionResolver" ref="variableExpressionResolver" />
<property name="sqlExpressionResolver" ref="sqlExpressionResolver" />
<property name="selectPersistenceOperation">
<bean class="org.datagear.persistence.support.SelectPersistenceOperation">
<property name="selectOptions" ref="selectOptions" />
@ -282,10 +288,14 @@
<bean id ="modelDataConverter" class="org.datagear.web.convert.ModelDataConverter">
<property name="conversionService" ref="conversionService" />
<property name="variableExpressionResolver" ref="variableExpressionResolver" />
<property name="sqlExpressionResolver" ref="sqlExpressionResolver" />
</bean>
<bean id ="classDataConverter" class="org.datagear.web.convert.ClassDataConverter">
<property name="conversionService" ref="conversionService" />
<property name="variableExpressionResolver" ref="variableExpressionResolver" />
<property name="sqlExpressionResolver" ref="sqlExpressionResolver" />
</bean>
<bean id="fileSerializer" class="org.datagear.web.json.fastjson.FileSerializer">

View File

@ -77,7 +77,8 @@ error.RecordNotFoundOrPermissionDeniedException=\u8BB0\u5F55\u6216\u8BB8\u5DF2\u
error.SchemaNotFoundException=\u672A\u627E\u5230\u6B64\u6570\u636E\u5E93
error.IllegalSourceValueException=\u6570\u636E\u8F6C\u6362\u51FA\u9519\uFF1A\u65E0\u6CD5\u5C06[{0}]\u8F6C\u6362\u4E3A[{1}]
error.FileNotFoundException=\u672A\u627E\u5230\u6587\u4EF6[{0}]
error.SqlExpressionErrorException=\u6267\u884CSQL\u8868\u8FBE\u5F0F\u51FA\u9519
error.VariableExpressionErrorException=\u8868\u8FBE\u5F0F\u683C\u5F0F\u6709\u8BEF\uFF1A<div class='content-value-sub'>{0}</div>
error.SqlExpressionErrorException=\u6267\u884CSQL\u8BED\u53E5\u51FA\u9519\uFF1A<div class='content-value-sub'>{0}</div>
error.UnsupportedDialectException=\u6570\u636E\u5E93\u8BBF\u95EE\u51FA\u9519\uFF0C\u7CFB\u7EDF\u4E0D\u652F\u6301\u8BBF\u95EE\u6B64\u6570\u636E\u5E93
error.PersistenceException=\u6570\u636E\u5E93\u8BBF\u95EE\u51FA\u9519
error.NotUniqueRecordException=\u65E0\u6CD5\u552F\u4E00\u786E\u5B9A\u8BB0\u5F55\uFF0C\u6570\u636E\u6709\u91CD\u590D

View File

@ -366,7 +366,8 @@
*/
tipSuccess : function(content, delayMs)
{
content = "<span class='ui-icon ui-icon-circle-check' style='margin-right:0.3em;'></span>" + content;
content = "<span class='tooltip-icon ui-icon ui-icon-circle-check'></span>"
+"<div class='content-value'>" + content +"</div>";
return $._tip("ui-state-default", content, (delayMs || 2000));
},
@ -375,8 +376,9 @@
*/
tipError : function(content, delayMs)
{
content = "<span class='ui-icon ui-icon-alert' style='margin-right:0.3em;'></span>" + content;
return $._tip("ui-state-error", content, (delayMs || 5000));
content = "<span class='tooltip-icon ui-icon ui-icon-alert'></span>"
+"<div class='content-value'>" + content +"</div>";
return $._tip("ui-state-error", content, (delayMs || 3500));
},
/**
@ -384,8 +386,9 @@
*/
tipInfo : function(content, delayMs)
{
content = "<span class='ui-icon ui-icon-info' style='margin-right:0.3em;'></span>" + content;
return $._tip("ui-state-highlight", content, (delayMs || 5000));
content = "<span class='tooltip-icon ui-icon ui-icon-info'></span>"
+"<div class='content-value'>" + content +"</div>";
return $._tip("ui-state-highlight", content, (delayMs || 3500));
},
/**
@ -412,7 +415,7 @@
*/
_tip : function(tooltipClass, content, delayMs)
{
content = "<div style='padding-left:0.5em;padding-right:0.5em; white-space: nowrap;'>" + content +"</div>";
content = "<div class='content'>" + content +"</div>";
var tooltip = $(".global-tooltip", document.body);
if(tooltip.length > 0)

View File

@ -336,9 +336,26 @@ table.dataTable tbody tr.selected .checkbox .ui-icon{
margin-left: 0.3em;
margin-right: 0.3em;
}
.ui-tooltip .ui-tooltip-content .tooltip-icon{
margin-right: 0.41em;
}
.ui-tooltip .ui-tooltip-content .error-detail-icon{
cursor: pointer;
}
.ui-tooltip .ui-tooltip-content .content{
padding-left:0.5em;
padding-right:0.5em;
white-space: nowrap;
}
.ui-tooltip .ui-tooltip-content .content .content-value{
display: inline-block;
}
.ui-tooltip .ui-tooltip-content .content .content-value .content-value-sub{
display: inline-block;
max-width: 41em;
vertical-align: bottom;
overflow: hidden;
}
/*错误消息对话框*/
.error-dialog{