diff --git a/base/src/main/java/tk/mybatis/mapper/provider/ExampleProvider.java b/base/src/main/java/tk/mybatis/mapper/provider/ExampleProvider.java index dcd4dbca8..587eb4883 100644 --- a/base/src/main/java/tk/mybatis/mapper/provider/ExampleProvider.java +++ b/base/src/main/java/tk/mybatis/mapper/provider/ExampleProvider.java @@ -54,6 +54,9 @@ public String selectCountByExample(MappedStatement ms) { if (isCheckExampleEntityClass()) { sql.append(SqlHelper.exampleCheck(entityClass)); } + if (getConfig().isSafeSelect()) { + sql.append(SqlHelper.exampleHasAtLeastOneCriteriaCheck("_parameter")); + } sql.append(SqlHelper.exampleCountColumn(entityClass)); sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass))); sql.append(SqlHelper.exampleWhereClause()); @@ -105,6 +108,9 @@ public String selectByExample(MappedStatement ms) { if (isCheckExampleEntityClass()) { sql.append(SqlHelper.exampleCheck(entityClass)); } + if (getConfig().isSafeSelect()) { + sql.append(SqlHelper.exampleHasAtLeastOneCriteriaCheck("_parameter")); + } sql.append("distinct"); //支持查询指定列 sql.append(SqlHelper.exampleSelectColumns(entityClass)); diff --git a/base/src/main/java/tk/mybatis/mapper/provider/base/BaseDeleteProvider.java b/base/src/main/java/tk/mybatis/mapper/provider/base/BaseDeleteProvider.java index ab58a667c..748e03056 100644 --- a/base/src/main/java/tk/mybatis/mapper/provider/base/BaseDeleteProvider.java +++ b/base/src/main/java/tk/mybatis/mapper/provider/base/BaseDeleteProvider.java @@ -54,7 +54,7 @@ public String delete(MappedStatement ms) { StringBuilder sql = new StringBuilder(); //如果设置了安全删除,就不允许执行不带查询条件的 delete 方法 if (getConfig().isSafeDelete()) { - sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass))); + sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass), isNotEmpty())); } // 如果是逻辑删除,则修改为更新表,修改逻辑删除字段的值 if (SqlHelper.hasLogicDeleteColumn(entityClass)) { diff --git a/base/src/main/java/tk/mybatis/mapper/provider/base/BaseSelectProvider.java b/base/src/main/java/tk/mybatis/mapper/provider/base/BaseSelectProvider.java index 051c62f69..002c4dcd3 100644 --- a/base/src/main/java/tk/mybatis/mapper/provider/base/BaseSelectProvider.java +++ b/base/src/main/java/tk/mybatis/mapper/provider/base/BaseSelectProvider.java @@ -25,6 +25,7 @@ package tk.mybatis.mapper.provider.base; import org.apache.ibatis.mapping.MappedStatement; +import tk.mybatis.mapper.mapperhelper.EntityHelper; import tk.mybatis.mapper.mapperhelper.MapperHelper; import tk.mybatis.mapper.mapperhelper.MapperTemplate; import tk.mybatis.mapper.mapperhelper.SqlHelper; @@ -51,6 +52,9 @@ public String selectOne(MappedStatement ms) { //修改返回值类型为实体类型 setResultType(ms, entityClass); StringBuilder sql = new StringBuilder(); + if (getConfig().isSafeSelect()) { + sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass), isNotEmpty())); + } sql.append(SqlHelper.selectAllColumns(entityClass)); sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass))); sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty())); @@ -68,6 +72,9 @@ public String select(MappedStatement ms) { //修改返回值类型为实体类型 setResultType(ms, entityClass); StringBuilder sql = new StringBuilder(); + if (getConfig().isSafeSelect()) { + sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass), isNotEmpty())); + } sql.append(SqlHelper.selectAllColumns(entityClass)); sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass))); sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty())); @@ -110,6 +117,9 @@ public String selectByPrimaryKey(MappedStatement ms) { public String selectCount(MappedStatement ms) { Class entityClass = getEntityClass(ms); StringBuilder sql = new StringBuilder(); + if (getConfig().isSafeSelect()) { + sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getColumns(entityClass), isNotEmpty())); + } sql.append(SqlHelper.selectCount(entityClass)); sql.append(SqlHelper.fromTable(entityClass, tableName(entityClass))); sql.append(SqlHelper.whereAllIfColumns(entityClass, isNotEmpty())); diff --git a/base/src/main/java/tk/mybatis/mapper/provider/base/BaseUpdateProvider.java b/base/src/main/java/tk/mybatis/mapper/provider/base/BaseUpdateProvider.java index 9f2e8335d..9fe1e106a 100644 --- a/base/src/main/java/tk/mybatis/mapper/provider/base/BaseUpdateProvider.java +++ b/base/src/main/java/tk/mybatis/mapper/provider/base/BaseUpdateProvider.java @@ -25,6 +25,7 @@ package tk.mybatis.mapper.provider.base; import org.apache.ibatis.mapping.MappedStatement; +import tk.mybatis.mapper.mapperhelper.EntityHelper; import tk.mybatis.mapper.mapperhelper.MapperHelper; import tk.mybatis.mapper.mapperhelper.MapperTemplate; import tk.mybatis.mapper.mapperhelper.SqlHelper; @@ -48,6 +49,9 @@ public BaseUpdateProvider(Class mapperClass, MapperHelper mapperHelper) { public String updateByPrimaryKey(MappedStatement ms) { Class entityClass = getEntityClass(ms); StringBuilder sql = new StringBuilder(); + if (getConfig().isSafeUpdate()) { + sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getPKColumns(entityClass), isNotEmpty())); + } sql.append(SqlHelper.updateTable(entityClass, tableName(entityClass))); sql.append(SqlHelper.updateSetColumns(entityClass, null, false, false)); sql.append(SqlHelper.wherePKColumns(entityClass, true)); @@ -63,6 +67,9 @@ public String updateByPrimaryKey(MappedStatement ms) { public String updateByPrimaryKeySelective(MappedStatement ms) { Class entityClass = getEntityClass(ms); StringBuilder sql = new StringBuilder(); + if (getConfig().isSafeUpdate()) { + sql.append(SqlHelper.notAllNullParameterCheck("_parameter", EntityHelper.getPKColumns(entityClass), isNotEmpty())); + } sql.append(SqlHelper.updateTable(entityClass, tableName(entityClass))); sql.append(SqlHelper.updateSetColumns(entityClass, null, true, isNotEmpty())); sql.append(SqlHelper.wherePKColumns(entityClass, true)); diff --git a/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByFieldTest.java b/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByFieldTest.java index fb6112950..1e9ed2ee7 100644 --- a/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByFieldTest.java +++ b/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByFieldTest.java @@ -15,6 +15,7 @@ public class SafeDeleteByFieldTest extends BaseTest { protected Config getConfig() { Config config = super.getConfig(); config.setSafeDelete(true); + config.setNotEmpty(true); return config; } @@ -40,6 +41,19 @@ public void testSafeDeleteNull() { } } + @Test(expected = PersistenceException.class) + public void testSafeDeleteEmptyString() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Country country = new Country(); + country.setCountryname(""); + mapper.delete(country); + } finally { + sqlSession.close(); + } + } + @Test(expected = PersistenceException.class) public void testSafeDeleteByExample() { SqlSession sqlSession = getSqlSession(); @@ -62,4 +76,17 @@ public void testSafeDeleteByExampleNull() { } } + @Test(expected = PersistenceException.class) + public void testSafeDeleteByExampleWithEmptyStringCriterion() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Example example = new Example(Country.class); + example.createCriteria().andEqualTo("countryname", ""); + mapper.deleteByExample(example); + } finally { + sqlSession.close(); + } + } + } diff --git a/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByMethodTest.java b/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByMethodTest.java index 8259de8b2..be026d4c9 100644 --- a/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByMethodTest.java +++ b/base/src/test/java/tk/mybatis/mapper/base/delete/SafeDeleteByMethodTest.java @@ -15,6 +15,7 @@ public class SafeDeleteByMethodTest extends BaseTest { protected Config getConfig() { Config config = super.getConfig(); config.setSafeDelete(true); + config.setNotEmpty(true); //和 SafeDeleteByFieldTest 测试的区别在此,这里将会使后面调用 EntityField.getValue 时,使用 getter 方法获取值 config.setEnableMethodAnnotation(true); return config; @@ -42,6 +43,19 @@ public void testSafeDeleteNull() { } } + @Test(expected = PersistenceException.class) + public void testSafeDeleteEmptyString() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Country country = new Country(); + country.setCountryname(""); + mapper.delete(country); + } finally { + sqlSession.close(); + } + } + @Test(expected = PersistenceException.class) public void testSafeDeleteByExample() { @@ -65,6 +79,19 @@ public void testSafeDeleteByExampleNull() { } } + @Test(expected = PersistenceException.class) + public void testSafeDeleteByExampleWithEmptyStringCriterion() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Example example = new Example(Country.class); + example.createCriteria().andEqualTo("countryname", ""); + mapper.deleteByExample(example); + } finally { + sqlSession.close(); + } + } + @Test(expected = PersistenceException.class) public void testSafeDeleteByExampleWithNullValueCriterion() { SqlSession sqlSession = getSqlSession(); diff --git a/base/src/test/java/tk/mybatis/mapper/base/select/SafeSelectByFieldTest.java b/base/src/test/java/tk/mybatis/mapper/base/select/SafeSelectByFieldTest.java new file mode 100644 index 000000000..f036eeef5 --- /dev/null +++ b/base/src/test/java/tk/mybatis/mapper/base/select/SafeSelectByFieldTest.java @@ -0,0 +1,142 @@ +package tk.mybatis.mapper.base.select; + +import org.apache.ibatis.exceptions.PersistenceException; +import org.apache.ibatis.session.SqlSession; +import org.junit.Assert; +import org.junit.Test; +import tk.mybatis.mapper.base.BaseTest; +import tk.mybatis.mapper.base.Country; +import tk.mybatis.mapper.base.CountryMapper; +import tk.mybatis.mapper.entity.Config; +import tk.mybatis.mapper.entity.Example; +import tk.mybatis.mapper.entity.model.CountryExample; + +public class SafeSelectByFieldTest extends BaseTest { + + @Override + protected Config getConfig() { + Config config = super.getConfig(); + config.setSafeSelect(true); + config.setNotEmpty(true); + return config; + } + + @Test(expected = PersistenceException.class) + public void testSafeSelect() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.select(new Country()); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeSelectNull() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.select(null); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeSelectEmptyString() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Country country = new Country(); + country.setCountryname(""); + mapper.select(country); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeSelectCountEmptyString() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Country country = new Country(); + country.setCountryname(""); + mapper.selectCount(country); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeSelectByExample() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.selectByExample(new Example(Country.class)); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeSelectByExampleNull() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.selectByExample(null); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeSelectByExampleWithEmptyStringCriterion() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Example example = new Example(Country.class); + example.createCriteria().andEqualTo("countryname", ""); + mapper.selectByExample(example); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeSelectByGeneratedExampleWithEmptyStringCriterion() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + CountryExample example = new CountryExample(); + example.createCriteria().andCountrynameEqualTo(""); + mapper.selectByExample(example); + } finally { + sqlSession.close(); + } + } + + @Test + public void testSafeSelectWithCondition() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Country country = new Country(); + country.setCountryname("China"); + Assert.assertEquals(1, mapper.select(country).size()); + + Example example = new Example(Country.class); + example.createCriteria().andEqualTo("countryname", "China"); + Assert.assertEquals(1, mapper.selectByExample(example).size()); + + CountryExample generatedExample = new CountryExample(); + generatedExample.createCriteria().andCountrynameEqualTo("China"); + Assert.assertEquals(1, mapper.selectByExample(generatedExample).size()); + + Assert.assertEquals(183, mapper.selectAll().size()); + } finally { + sqlSession.close(); + } + } +} diff --git a/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByFieldTest.java b/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByFieldTest.java index a2689de79..d5d66f45e 100644 --- a/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByFieldTest.java +++ b/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByFieldTest.java @@ -18,6 +18,28 @@ protected Config getConfig() { return config; } + @Test(expected = PersistenceException.class) + public void testSafeUpdateByPrimaryKeyNull() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.updateByPrimaryKey(new Country()); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeUpdateByPrimaryKeySelectiveNull() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.updateByPrimaryKeySelective(new Country()); + } finally { + sqlSession.close(); + } + } + @Test(expected = PersistenceException.class) public void testSafeUpdate() { SqlSession sqlSession = getSqlSession(); @@ -29,6 +51,19 @@ public void testSafeUpdate() { } } + @Test(expected = PersistenceException.class) + public void testSafeUpdateWithEmptyStringCriterion() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Example example = new Example(Country.class); + example.createCriteria().andEqualTo("countryname", ""); + mapper.updateByExample(new Country(), example); + } finally { + sqlSession.close(); + } + } + @Test(expected = PersistenceException.class) public void testSafeUpdateNull() { SqlSession sqlSession = getSqlSession(); diff --git a/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByMethodTest.java b/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByMethodTest.java index 002a508d0..723934e4d 100644 --- a/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByMethodTest.java +++ b/base/src/test/java/tk/mybatis/mapper/base/update/SafeUpdateByMethodTest.java @@ -20,6 +20,28 @@ protected Config getConfig() { return config; } + @Test(expected = PersistenceException.class) + public void testSafeUpdateByPrimaryKeyNull() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.updateByPrimaryKey(new Country()); + } finally { + sqlSession.close(); + } + } + + @Test(expected = PersistenceException.class) + public void testSafeUpdateByPrimaryKeySelectiveNull() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + mapper.updateByPrimaryKeySelective(new Country()); + } finally { + sqlSession.close(); + } + } + @Test(expected = PersistenceException.class) public void testSafeUpdate() { SqlSession sqlSession = getSqlSession(); @@ -31,6 +53,19 @@ public void testSafeUpdate() { } } + @Test(expected = PersistenceException.class) + public void testSafeUpdateWithEmptyStringCriterion() { + SqlSession sqlSession = getSqlSession(); + try { + CountryMapper mapper = sqlSession.getMapper(CountryMapper.class); + Example example = new Example(Country.class); + example.createCriteria().andEqualTo("countryname", ""); + mapper.updateByExample(new Country(), example); + } finally { + sqlSession.close(); + } + } + @Test(expected = PersistenceException.class) public void testSafeUpdateNull() { SqlSession sqlSession = getSqlSession(); diff --git a/core/src/main/java/tk/mybatis/mapper/entity/Config.java b/core/src/main/java/tk/mybatis/mapper/entity/Config.java index da0c06139..610331e3e 100644 --- a/core/src/main/java/tk/mybatis/mapper/entity/Config.java +++ b/core/src/main/java/tk/mybatis/mapper/entity/Config.java @@ -86,6 +86,10 @@ public class Config { * 安全更新,开启后,不允许更新全表,如 update table set xx=? */ private boolean safeUpdate; + /** + * 安全查询,开启后,不允许执行不带查询条件的条件查询方法 + */ + private boolean safeSelect; /** * 控制通过主键进行操作(select, update, delete)时,是否拼接逻辑删除字段的条件(默认 true,保持兼容) *

@@ -318,6 +322,14 @@ public void setSafeUpdate(boolean safeUpdate) { this.safeUpdate = safeUpdate; } + public boolean isSafeSelect() { + return safeSelect; + } + + public void setSafeSelect(boolean safeSelect) { + this.safeSelect = safeSelect; + } + public boolean isLogicDeleteByKey() { return logicDeleteByKey; } @@ -423,6 +435,8 @@ public void setProperties(Properties properties) { this.safeDelete = Boolean.valueOf(properties.getProperty("safeDelete")); //safeUpdate this.safeUpdate = Boolean.valueOf(properties.getProperty("safeUpdate")); + //safeSelect + this.safeSelect = Boolean.valueOf(properties.getProperty("safeSelect")); // 控制通过主键进行操作(select, update, delete)时,是否拼接逻辑删除字段的条件(默认 true,保持兼容) String logicDeleteByKey = properties.getProperty("logicDeleteByKey"); if (StringUtil.isNotEmpty(logicDeleteByKey)) { diff --git a/core/src/main/java/tk/mybatis/mapper/mapperhelper/SqlHelper.java b/core/src/main/java/tk/mybatis/mapper/mapperhelper/SqlHelper.java index 080189153..dac7d7121 100644 --- a/core/src/main/java/tk/mybatis/mapper/mapperhelper/SqlHelper.java +++ b/core/src/main/java/tk/mybatis/mapper/mapperhelper/SqlHelper.java @@ -576,6 +576,18 @@ public static String updateSetColumnsIgnoreVersion(Class entityClass, String * @return */ public static String notAllNullParameterCheck(String parameterName, Set columnSet) { + return notAllNullParameterCheck(parameterName, columnSet, false); + } + + /** + * 不是所有参数都是 null 或空字符串的检查 + * + * @param parameterName 参数名 + * @param columnSet 需要检查的列 + * @param notEmpty 是否判断 String 类型 != '' + * @return + */ + public static String notAllNullParameterCheck(String parameterName, Set columnSet, boolean notEmpty) { StringBuilder sql = new StringBuilder(); sql.append(""); + sql.append("', "); + sql.append(notEmpty); + sql.append(")\"/>"); return sql.toString(); } @@ -598,9 +612,22 @@ public static String notAllNullParameterCheck(String parameterName, Set"); + sql.append(parameterName).append(", "); + sql.append(notEmpty); + sql.append(")\"/>"); return sql.toString(); } diff --git a/core/src/main/java/tk/mybatis/mapper/util/OGNL.java b/core/src/main/java/tk/mybatis/mapper/util/OGNL.java index 2fe0b38af..4e67e8ba9 100644 --- a/core/src/main/java/tk/mybatis/mapper/util/OGNL.java +++ b/core/src/main/java/tk/mybatis/mapper/util/OGNL.java @@ -32,6 +32,7 @@ import tk.mybatis.mapper.mapperhelper.EntityHelper; import tk.mybatis.mapper.mapperhelper.SqlHelper; +import java.lang.reflect.Array; import java.lang.reflect.Method; import java.util.*; @@ -71,18 +72,32 @@ public static boolean checkExampleEntityClass(Object parameter, String entityFul * @return */ public static boolean notAllNullParameterCheck(Object parameter, String fields) { + return notAllNullParameterCheck(parameter, fields, false); + } + + /** + * 检查 parameter 对象中指定的 fields 是否全是 null 或空字符串,如果是则抛出异常 + * + * @param parameter + * @param fields + * @param notEmpty + * @return + */ + public static boolean notAllNullParameterCheck(Object parameter, String fields, boolean notEmpty) { if (parameter != null) { try { Set columns = EntityHelper.getColumns(parameter.getClass()); Set fieldSet = new HashSet(Arrays.asList(fields.split(","))); for (EntityColumn column : columns) { - if (fieldSet.contains(column.getProperty())) { + if (fieldSet.contains(column.getProperty()) && !isLogicDeleteColumn(column)) { Object value = column.getEntityField().getValue(parameter); - if (value != null) { + if (isEffectiveValue(value, notEmpty)) { return true; } } } + } catch (MapperException e) { + throw e; } catch (Exception e) { throw new MapperException(SAFE_DELETE_ERROR, e); } @@ -111,31 +126,26 @@ public static boolean notEmptyCollectionCheck(Object parameter, String error) { * @return */ public static boolean exampleHasAtLeastOneCriteriaCheck(Object parameter) { + return exampleHasAtLeastOneCriteriaCheck(parameter, true); + } + + public static boolean exampleHasAtLeastOneCriteriaCheck(Object parameter, boolean notEmpty) { if (parameter != null) { try { - if (parameter instanceof Example) { - List criteriaList = ((Example) parameter).getOredCriteria(); - if (criteriaList != null && criteriaList.size() > 0) { - for (Example.Criteria criteria : criteriaList) { - if (criteria != null && criteria.isValid()) { - return true; - } + List criteriaList = getOredCriteria(parameter); + if (criteriaList != null && criteriaList.size() > 0) { + boolean hasCriterion = false; + for (Object criteria : criteriaList) { + if (criteriaHasCriterion(criteria, notEmpty)) { + hasCriterion = true; } } - } else { - Method getter = parameter.getClass().getDeclaredMethod("getOredCriteria"); - Object list = getter.invoke(parameter); - if (list != null && list instanceof List) { - List criteriaList = (List) list; - if (criteriaList.size() > 0) { - for (Object criteria : criteriaList) { - if (criteria instanceof Example.Criteria && ((Example.Criteria) criteria).isValid()) { - return true; - } - } - } + if (hasCriterion) { + return true; } } + } catch (MapperException e) { + throw e; } catch (Exception e) { throw new MapperException(SAFE_DELETE_ERROR, e); } @@ -143,6 +153,120 @@ public static boolean exampleHasAtLeastOneCriteriaCheck(Object parameter) { throw new MapperException(SAFE_DELETE_EXCEPTION); } + private static List getOredCriteria(Object parameter) throws Exception { + if (parameter instanceof Example) { + return ((Example) parameter).getOredCriteria(); + } + Method getter = parameter.getClass().getMethod("getOredCriteria"); + if (!getter.isAccessible()) { + getter.setAccessible(true); + } + Object list = getter.invoke(parameter); + if (list instanceof List) { + return (List) list; + } + return null; + } + + private static boolean criteriaHasCriterion(Object criteria, boolean notEmpty) throws Exception { + if (criteria == null) { + return false; + } + List criterionList = getCriteriaList(criteria); + if (criterionList != null) { + boolean hasCriterion = false; + for (Object criterion : criterionList) { + if (criterion != null) { + emptyCriterionValueCheck(criterion, notEmpty); + hasCriterion = true; + } + } + return hasCriterion; + } + Boolean valid = invokeBoolean(criteria, "isValid"); + return valid != null && valid; + } + + private static List getCriteriaList(Object criteria) throws Exception { + if (criteria instanceof Example.Criteria) { + return ((Example.Criteria) criteria).getAllCriteria(); + } + Object list = invoke(criteria, "getAllCriteria"); + if (list instanceof List) { + return (List) list; + } + list = invoke(criteria, "getCriteria"); + if (list instanceof List) { + return (List) list; + } + return null; + } + + private static void emptyCriterionValueCheck(Object criterion, boolean notEmpty) throws Exception { + Boolean noValue = invokeBoolean(criterion, "isNoValue"); + if (Boolean.TRUE.equals(noValue)) { + return; + } + Boolean singleValue = invokeBoolean(criterion, "isSingleValue"); + if (Boolean.TRUE.equals(singleValue) && isEmptyConditionValue(invoke(criterion, "getValue"), notEmpty)) { + throw new MapperException(SAFE_DELETE_EXCEPTION); + } + Boolean betweenValue = invokeBoolean(criterion, "isBetweenValue"); + if (Boolean.TRUE.equals(betweenValue) + && (isEmptyConditionValue(invoke(criterion, "getValue"), notEmpty) + || isEmptyConditionValue(invoke(criterion, "getSecondValue"), notEmpty))) { + throw new MapperException(SAFE_DELETE_EXCEPTION); + } + Boolean listValue = invokeBoolean(criterion, "isListValue"); + if (Boolean.TRUE.equals(listValue) && isEmptyConditionValue(invoke(criterion, "getValue"), notEmpty)) { + throw new MapperException(SAFE_DELETE_EXCEPTION); + } + } + + private static Boolean invokeBoolean(Object target, String methodName) throws Exception { + Object value = invoke(target, methodName); + if (value instanceof Boolean) { + return (Boolean) value; + } + return null; + } + + private static Object invoke(Object target, String methodName) throws Exception { + try { + Method method = target.getClass().getMethod(methodName); + if (!method.isAccessible()) { + method.setAccessible(true); + } + return method.invoke(target); + } catch (NoSuchMethodException e) { + return null; + } + } + + private static boolean isLogicDeleteColumn(EntityColumn column) { + return column.getEntityField().isAnnotationPresent(LogicDelete.class); + } + + private static boolean isEffectiveValue(Object value, boolean notEmpty) { + return !isEmptyConditionValue(value, notEmpty); + } + + private static boolean isEmptyConditionValue(Object value, boolean notEmpty) { + if (value == null) { + return true; + } + if (notEmpty && value instanceof String && StringUtil.isEmpty((String) value)) { + return true; + } + if (value instanceof Collection && ((Collection) value).isEmpty()) { + return true; + } + if (value.getClass().isArray() && Array.getLength(value) == 0) { + return true; + } + return false; + } + /** * 是否包含自定义查询列 *