From b1af0bcee46c492a96a0b7a5daff16c1e646cb09 Mon Sep 17 00:00:00 2001 From: FuriousPws002 <1938485828@qq.com> Date: Tue, 16 Apr 2024 22:04:25 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0if=E6=A0=87=E7=AD=BE?= =?UTF-8?q?=E5=92=8Ctrim=E6=A0=87=E7=AD=BE=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 5 ++ .../scripting/xmltags/DynamicContext.java | 13 +++ .../scripting/xmltags/DynamicSqlSource.java | 30 +++++++ .../ibatis/scripting/xmltags/IfSqlNode.java | 30 +++++++ .../ibatis/scripting/xmltags/TrimSqlNode.java | 89 +++++++++++++++++++ .../scripting/xmltags/XMLScriptBuilder.java | 51 +++++++++++ 6 files changed, 218 insertions(+) create mode 100644 src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java create mode 100644 src/main/java/org/apache/ibatis/scripting/xmltags/IfSqlNode.java create mode 100644 src/main/java/org/apache/ibatis/scripting/xmltags/TrimSqlNode.java diff --git a/pom.xml b/pom.xml index 1c8135f..87aaddb 100755 --- a/pom.xml +++ b/pom.xml @@ -34,6 +34,11 @@ commons-lang3 3.14.0 + + ognl + ognl + 3.4.2 + diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java index 15822b8..2e4eaf5 100644 --- a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java @@ -8,10 +8,15 @@ public class DynamicContext { private final StringJoiner sqlBuilder = new StringJoiner(" "); + private Object parameterObject; public DynamicContext() { } + public DynamicContext(Object parameterObject) { + this.parameterObject = parameterObject; + } + public void appendSql(String sql) { sqlBuilder.add(sql); } @@ -19,4 +24,12 @@ public void appendSql(String sql) { public String getSql() { return sqlBuilder.toString().trim(); } + + public Object getParameterObject() { + return parameterObject; + } + + public void setParameterObject(Object parameterObject) { + this.parameterObject = parameterObject; + } } diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java new file mode 100644 index 0000000..dd3009b --- /dev/null +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java @@ -0,0 +1,30 @@ +package org.apache.ibatis.scripting.xmltags; + +import org.apache.ibatis.builder.SqlSourceBuilder; +import org.apache.ibatis.mapping.BoundSql; +import org.apache.ibatis.mapping.SqlSource; +import org.apache.ibatis.session.Configuration; + +/** + * @author furious 2024/4/16 + */ +public class DynamicSqlSource implements SqlSource { + + private final Configuration configuration; + private final SqlNode rootSqlNode; + + public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode) { + this.configuration = configuration; + this.rootSqlNode = rootSqlNode; + } + + @Override + public BoundSql getBoundSql(Object parameterObject) { + DynamicContext context = new DynamicContext(parameterObject); + rootSqlNode.apply(context); + SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); + Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); + SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType); + return sqlSource.getBoundSql(parameterObject); + } +} diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/IfSqlNode.java b/src/main/java/org/apache/ibatis/scripting/xmltags/IfSqlNode.java new file mode 100644 index 0000000..80a2415 --- /dev/null +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/IfSqlNode.java @@ -0,0 +1,30 @@ +package org.apache.ibatis.scripting.xmltags; + +import ognl.Ognl; + +/** + * @author furious 2024/4/16 + */ +public class IfSqlNode implements SqlNode { + + private final String test; + private final SqlNode contents; + + public IfSqlNode(String test, SqlNode contents) { + this.test = test; + this.contents = contents; + } + + @Override + public boolean apply(DynamicContext context) { + try { + Object value = Ognl.getValue(Ognl.parseExpression(test), context.getParameterObject()); + if (value instanceof Boolean && (Boolean) value) { + contents.apply(context); + } + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/TrimSqlNode.java b/src/main/java/org/apache/ibatis/scripting/xmltags/TrimSqlNode.java new file mode 100644 index 0000000..1d057a4 --- /dev/null +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/TrimSqlNode.java @@ -0,0 +1,89 @@ +package org.apache.ibatis.scripting.xmltags; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; + +/** + * @author furious 2024/4/16 + */ +public class TrimSqlNode implements SqlNode { + + private final SqlNode contents; + private final String prefix; + private final List prefixesToOverride; + + public TrimSqlNode(SqlNode contents, String prefix, String prefixesToOverride) { + this.contents = contents; + this.prefix = prefix; + this.prefixesToOverride = parseOverrides(prefixesToOverride); + } + + @Override + public boolean apply(DynamicContext context) { + FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context); + boolean result = contents.apply(filteredDynamicContext); + filteredDynamicContext.applyAll(); + return result; + } + + private static List parseOverrides(String overrides) { + if (StringUtils.isEmpty(overrides)) { + return Collections.emptyList(); + } + return Arrays.stream(overrides.split("\\|")).collect(Collectors.toList()); + } + + private class FilteredDynamicContext extends DynamicContext { + private final DynamicContext delegate; + private StringBuilder sqlBuffer = new StringBuilder(); + + public FilteredDynamicContext(DynamicContext delegate) { + this.delegate = delegate; + } + + public void applyAll() { + sqlBuffer = new StringBuilder(sqlBuffer.toString().trim()); + String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(); + if (trimmedUppercaseSql.length() > 0) { + applyPrefix(sqlBuffer, trimmedUppercaseSql); + } + delegate.appendSql(sqlBuffer.toString()); + } + + @Override + public void appendSql(String sql) { + sqlBuffer.append(sql); + } + + @Override + public String getSql() { + return delegate.getSql(); + } + + @Override + public Object getParameterObject() { + return delegate.getParameterObject(); + } + + private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) { + if (Objects.nonNull(prefixesToOverride)) { + for (String remove : prefixesToOverride) { + if (trimmedUppercaseSql.startsWith(remove)) { + sql.delete(0, remove.trim().length()); + break; + } + } + } + if (prefix != null) { + sql.insert(0, " "); + sql.insert(0, prefix); + } + } + } + +} diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java b/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java index b0a82c5..5646254 100644 --- a/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java @@ -1,9 +1,12 @@ package org.apache.ibatis.scripting.xmltags; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import org.apache.ibatis.builder.BaseBuilder; +import org.apache.ibatis.builder.BuilderException; import org.apache.ibatis.mapping.SqlSource; import org.apache.ibatis.parsing.XNode; import org.apache.ibatis.scripting.defaults.RawSqlSource; @@ -18,6 +21,8 @@ public class XMLScriptBuilder extends BaseBuilder { private final XNode context; private final Class parameterType; + private boolean isDynamic; + private final Map nodeHandlerMap = new HashMap<>(); public XMLScriptBuilder(Configuration configuration, XNode context) { this(configuration, context, null); @@ -27,10 +32,15 @@ public XMLScriptBuilder(Configuration configuration, XNode context, Class par super(configuration); this.context = context; this.parameterType = parameterType; + nodeHandlerMap.put("if", new IfHandler()); + nodeHandlerMap.put("trim", new TrimHandler()); } public SqlSource parseScriptNode() { MixedSqlNode rootSqlNode = parseDynamicTags(context); + if (isDynamic) { + return new DynamicSqlSource(configuration, rootSqlNode); + } return new RawSqlSource(configuration, rootSqlNode, parameterType); } @@ -41,8 +51,49 @@ protected MixedSqlNode parseDynamicTags(XNode node) { XNode child = node.newXNode(children.item(i)); if (child.getNode().getNodeType() == Node.TEXT_NODE) { contents.add(new StaticTextSqlNode(child.getBody())); + } else if (child.getNode().getNodeType() == Node.ELEMENT_NODE) { + String nodeName = child.getNode().getNodeName(); + NodeHandler handler = nodeHandlerMap.get(nodeName); + if (handler == null) { + throw new BuilderException("not support " + nodeName + " NodeHandler"); + } + handler.handleNode(child, contents); + isDynamic = true; } } return new MixedSqlNode(contents); } + + private interface NodeHandler { + void handleNode(XNode nodeToHandle, List targetContents); + } + + /** + * 处理 标签 + */ + private class IfHandler implements NodeHandler { + + @Override + public void handleNode(XNode nodeToHandle, List targetContents) { + MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle); + String test = nodeToHandle.getAttribute("test"); + IfSqlNode ifSqlNode = new IfSqlNode(test, mixedSqlNode); + targetContents.add(ifSqlNode); + } + } + + /** + * 处理 标签 + */ + private class TrimHandler implements NodeHandler { + + @Override + public void handleNode(XNode nodeToHandle, List targetContents) { + MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle); + String prefix = nodeToHandle.getAttribute("prefix"); + String prefixOverrides = nodeToHandle.getAttribute("prefixOverrides"); + TrimSqlNode trim = new TrimSqlNode(mixedSqlNode, prefix, prefixOverrides); + targetContents.add(trim); + } + } } From 083c167c69af61c23ac52b88a811d79982653567 Mon Sep 17 00:00:00 2001 From: FuriousPws002 <1938485828@qq.com> Date: Wed, 17 Apr 2024 21:37:04 +0800 Subject: [PATCH 2/2] =?UTF-8?q?foreach=E6=A0=87=E7=AD=BE=E5=AE=9E=E7=8E=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 1 + .../org/apache/ibatis/mapping/BoundSql.java | 24 +++ .../ibatis/mapping/MappedStatement.java | 2 +- .../defaults/DefaultParameterHandler.java | 4 +- .../scripting/xmltags/DynamicContext.java | 11 ++ .../scripting/xmltags/DynamicSqlSource.java | 4 +- .../scripting/xmltags/ForeachSqlNode.java | 157 ++++++++++++++++++ .../scripting/xmltags/XMLScriptBuilder.java | 17 ++ .../org/apache/ibatis/dao/UserMapper.java | 4 + .../apache/ibatis/session/SqlSessionTest.java | 39 +++++ src/test/resources/mapper/UserMapper.xml | 24 +++ 11 files changed, 284 insertions(+), 3 deletions(-) create mode 100644 src/main/java/org/apache/ibatis/scripting/xmltags/ForeachSqlNode.java diff --git a/README.md b/README.md index ad6b791..0912090 100644 --- a/README.md +++ b/README.md @@ -7,3 +7,4 @@ [4.参数绑定](https://github.com/FuriousPws002/mini-mybatis/wiki/4.%E5%8F%82%E6%95%B0%E7%BB%91%E5%AE%9A "Markdown")
[5.resultType结果集处理](https://github.com/FuriousPws002/mini-mybatis/wiki/5.resultType%E7%BB%93%E6%9E%9C%E9%9B%86%E5%A4%84%E7%90%86 "Markdown")
[6.resultMap结果集处理](https://github.com/FuriousPws002/mini-mybatis/wiki/6.resultMap%E7%BB%93%E6%9E%9C%E9%9B%86%E5%A4%84%E7%90%86 "Markdown")
+[7.动态sql](https://github.com/FuriousPws002/mini-mybatis/wiki/7.%E5%8A%A8%E6%80%81sql "Markdown")
diff --git a/src/main/java/org/apache/ibatis/mapping/BoundSql.java b/src/main/java/org/apache/ibatis/mapping/BoundSql.java index 83ac02c..ca1c1ed 100644 --- a/src/main/java/org/apache/ibatis/mapping/BoundSql.java +++ b/src/main/java/org/apache/ibatis/mapping/BoundSql.java @@ -1,6 +1,8 @@ package org.apache.ibatis.mapping; +import java.util.HashMap; import java.util.List; +import java.util.Map; /** * @author furious 2024/4/7 @@ -10,15 +12,21 @@ public class BoundSql { private final String sql; private final List parameterMappings; private final Object parameterObject; + private final Map additionalParameters; public BoundSql(String sql) { this(sql, null, null); } public BoundSql(String sql, List parameterMappings, Object parameterObject) { + this(sql, parameterMappings, parameterObject, new HashMap<>()); + } + + public BoundSql(String sql, List parameterMappings, Object parameterObject, Map additionalParameters) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; + this.additionalParameters = additionalParameters; } public List getParameterMappings() { @@ -32,4 +40,20 @@ public Object getParameterObject() { public String getSql() { return this.sql; } + + public void setAdditionalParameter(String key, Object value) { + additionalParameters.put(key, value); + } + + public Object getAdditionalParameter(String key) { + return additionalParameters.get(key); + } + + public boolean hasAdditionalParameter(String key) { + return additionalParameters.containsKey(key); + } + + public Map getAdditionalParameters() { + return additionalParameters; + } } diff --git a/src/main/java/org/apache/ibatis/mapping/MappedStatement.java b/src/main/java/org/apache/ibatis/mapping/MappedStatement.java index ff92d84..20c37b4 100644 --- a/src/main/java/org/apache/ibatis/mapping/MappedStatement.java +++ b/src/main/java/org/apache/ibatis/mapping/MappedStatement.java @@ -28,7 +28,7 @@ public Configuration getConfiguration() { public BoundSql getBoundSql(Object parameterObject) { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); - return new BoundSql(boundSql.getSql(),boundSql.getParameterMappings(),parameterObject); + return new BoundSql(boundSql.getSql(), boundSql.getParameterMappings(), parameterObject, boundSql.getAdditionalParameters()); } public ResultMap getResultMap() { diff --git a/src/main/java/org/apache/ibatis/scripting/defaults/DefaultParameterHandler.java b/src/main/java/org/apache/ibatis/scripting/defaults/DefaultParameterHandler.java index 952dade..b3421a0 100644 --- a/src/main/java/org/apache/ibatis/scripting/defaults/DefaultParameterHandler.java +++ b/src/main/java/org/apache/ibatis/scripting/defaults/DefaultParameterHandler.java @@ -47,7 +47,9 @@ public void setParameters(PreparedStatement ps) throws SQLException { ParameterMapping parameterMapping = parameterMappings.get(i); Object value; String propertyName = parameterMapping.getProperty(); - if (Objects.isNull(parameterObject)) { + if (boundSql.hasAdditionalParameter(propertyName)) { + value = boundSql.getAdditionalParameter(propertyName); + }else if (Objects.isNull(parameterObject)) { value = null; } else if (configuration.getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass())) { value = parameterObject; diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java index 2e4eaf5..76970c4 100644 --- a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicContext.java @@ -1,5 +1,7 @@ package org.apache.ibatis.scripting.xmltags; +import java.util.HashMap; +import java.util.Map; import java.util.StringJoiner; /** @@ -9,6 +11,7 @@ public class DynamicContext { private final StringJoiner sqlBuilder = new StringJoiner(" "); private Object parameterObject; + private final Map bindings = new HashMap<>(); public DynamicContext() { } @@ -32,4 +35,12 @@ public Object getParameterObject() { public void setParameterObject(Object parameterObject) { this.parameterObject = parameterObject; } + + public Map getBindings() { + return bindings; + } + + public void bind(String key, Object value) { + bindings.put(key, value); + } } diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java index dd3009b..73041c6 100644 --- a/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/DynamicSqlSource.java @@ -25,6 +25,8 @@ public BoundSql getBoundSql(Object parameterObject) { SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration); Class parameterType = parameterObject == null ? Object.class : parameterObject.getClass(); SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType); - return sqlSource.getBoundSql(parameterObject); + BoundSql boundSql = sqlSource.getBoundSql(parameterObject); + context.getBindings().forEach(boundSql::setAdditionalParameter); + return boundSql; } } diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/ForeachSqlNode.java b/src/main/java/org/apache/ibatis/scripting/xmltags/ForeachSqlNode.java new file mode 100644 index 0000000..64447cf --- /dev/null +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/ForeachSqlNode.java @@ -0,0 +1,157 @@ +package org.apache.ibatis.scripting.xmltags; + +import java.util.Map; +import java.util.Objects; + +import org.apache.commons.lang3.StringUtils; +import org.apache.ibatis.parsing.GenericTokenParser; + +import ognl.Ognl; + +/** + * @author furious 2024/4/17 + */ +public class ForeachSqlNode implements SqlNode { + + public static final String ITEM_PREFIX = ForeachSqlNode.class.getName(); + + private final SqlNode contents; + private final String collection; + private final String item; + private final String open; + private final String close; + private final String separator; + + public ForeachSqlNode(SqlNode contents, String collection, String item, String open, String close, String separator) { + this.contents = contents; + this.collection = collection; + this.item = item; + this.open = open; + this.close = close; + this.separator = separator; + } + + @Override + @SuppressWarnings("rawtypes") + public boolean apply(DynamicContext context) { + Iterable iterable = null; + try { + Object value = Ognl.getValue(Ognl.parseExpression(collection), context.getParameterObject()); + if (value instanceof Iterable && ((Iterable) value).iterator().hasNext()) { + iterable = (Iterable) value; + } + } catch (Exception e) { + return false; + } + if (Objects.isNull(iterable)) { + return true; + } + + applyOpen(context); + int index = 0; + for (Object o : iterable) { + DynamicContext oldContext = context; + if (index == 0) { + context = new SeparatorContext(context, ""); + } else { + context = new SeparatorContext(context, separator); + } + applyItem(context, o, index); + contents.apply(new FilteredDynamicContext(context, item, index)); + context = oldContext; + index++; + } + applyClose(context); + return true; + } + + private void applyOpen(DynamicContext context) { + if (Objects.nonNull(open)) { + context.appendSql(open); + } + } + + private void applyItem(DynamicContext context, Object o, int i) { + if (Objects.nonNull(item)) { + context.bind(item, o); + context.bind(itemizeItem(item, i), o); + } + } + + private void applyClose(DynamicContext context) { + if (Objects.nonNull(close)) { + context.appendSql(close); + } + } + + private static String itemizeItem(String item, int i) { + return ITEM_PREFIX + item + "_" + i; + } + + private static class SeparatorContext extends DynamicContext { + + private final DynamicContext delegate; + private final String separator; + + public SeparatorContext(DynamicContext delegate, String separator) { + this.delegate = delegate; + this.separator = separator; + } + + @Override + public Map getBindings() { + return delegate.getBindings(); + } + + @Override + public void bind(String name, Object value) { + delegate.bind(name, value); + } + + @Override + public void appendSql(String sql) { + if (StringUtils.isNoneBlank(sql)) { + delegate.appendSql(separator); + } + delegate.appendSql(sql); + } + + @Override + public String getSql() { + return delegate.getSql(); + } + } + + private static class FilteredDynamicContext extends DynamicContext { + private final DynamicContext delegate; + private final String item; + private final int index; + + public FilteredDynamicContext(DynamicContext delegate, String item, int index) { + this.delegate = delegate; + this.item = item; + this.index = index; + } + + @Override + public Map getBindings() { + return delegate.getBindings(); + } + + @Override + public void bind(String name, Object value) { + delegate.bind(name, value); + } + + @Override + public String getSql() { + return delegate.getSql(); + } + + @Override + public void appendSql(String sql) { + GenericTokenParser parser = new GenericTokenParser("#{", "}", content -> "#{" + itemizeItem(item, index) + "}"); + delegate.appendSql(parser.parse(sql)); + } + } +} diff --git a/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java b/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java index 5646254..34ecc49 100644 --- a/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java +++ b/src/main/java/org/apache/ibatis/scripting/xmltags/XMLScriptBuilder.java @@ -34,6 +34,7 @@ public XMLScriptBuilder(Configuration configuration, XNode context, Class par this.parameterType = parameterType; nodeHandlerMap.put("if", new IfHandler()); nodeHandlerMap.put("trim", new TrimHandler()); + nodeHandlerMap.put("foreach", new ForeachHandler()); } public SqlSource parseScriptNode() { @@ -96,4 +97,20 @@ public void handleNode(XNode nodeToHandle, List targetContents) { targetContents.add(trim); } } + + private class ForeachHandler implements NodeHandler { + + @Override + public void handleNode(XNode nodeToHandle, List targetContents) { + MixedSqlNode mixedSqlNode = parseDynamicTags(nodeToHandle); + String collection = nodeToHandle.getAttribute("collection"); + String item = nodeToHandle.getAttribute("item"); + String open = nodeToHandle.getAttribute("open"); + String close = nodeToHandle.getAttribute("close"); + String separator = nodeToHandle.getAttribute("separator"); + ForeachSqlNode forEachSqlNode = new ForeachSqlNode(mixedSqlNode, collection, item, open, close, separator); + targetContents.add(forEachSqlNode); + } + } + } diff --git a/src/test/java/org/apache/ibatis/dao/UserMapper.java b/src/test/java/org/apache/ibatis/dao/UserMapper.java index 5d9a47c..570e715 100644 --- a/src/test/java/org/apache/ibatis/dao/UserMapper.java +++ b/src/test/java/org/apache/ibatis/dao/UserMapper.java @@ -35,4 +35,8 @@ public interface UserMapper { List selectResultMap(); List selectNestedResultMap(); + + List listDynamic(@Param("name") String name, @Param("age") Integer age); + + List listForeach(@Param("ids") List ids); } diff --git a/src/test/java/org/apache/ibatis/session/SqlSessionTest.java b/src/test/java/org/apache/ibatis/session/SqlSessionTest.java index b269bed..d14dd7d 100644 --- a/src/test/java/org/apache/ibatis/session/SqlSessionTest.java +++ b/src/test/java/org/apache/ibatis/session/SqlSessionTest.java @@ -1,5 +1,6 @@ package org.apache.ibatis.session; +import java.util.ArrayList; import java.util.List; import org.apache.ibatis.DataSourceBuilderTest; @@ -127,4 +128,42 @@ public void queryNestedResultMap() { Assert.assertNotNull(user.getName()); Assert.assertNotNull(user.getCarList()); } + + /** + * 动态SQL-包含trim标签和if标签 + */ + @Test + public void queryDynamicSql() { + UserMapper userMapper = getUserMapper(); + List list1 = userMapper.listDynamic(null, null); + Assert.assertNotNull(list1); + List list2 = userMapper.listDynamic("Sam", null); + Assert.assertNotNull(list2); + List list3 = userMapper.listDynamic(null, 20); + Assert.assertNotNull(list3); + List list4 = userMapper.listDynamic("Sam", 20); + Assert.assertNotNull(list4); + } + + /** + * foreach标签测试 + */ + @Test + public void queryForeachTag() { + UserMapper userMapper = getUserMapper(); + List idList = new ArrayList<>(); + idList.add(1L); + idList.add(2L); + List list = userMapper.listForeach(idList); + Assert.assertNotNull(list); + } + + private UserMapper getUserMapper() { + Configuration configuration = new Configuration(); + configuration.setDataSource(DataSourceBuilderTest.build()); + configuration.addMapper(UserMapper.class); + SqlSession sqlSession = new DefaultSqlSession(configuration); + return sqlSession.getMapper(UserMapper.class); + } + } diff --git a/src/test/resources/mapper/UserMapper.xml b/src/test/resources/mapper/UserMapper.xml index 5b7b2a4..f9909db 100644 --- a/src/test/resources/mapper/UserMapper.xml +++ b/src/test/resources/mapper/UserMapper.xml @@ -53,6 +53,30 @@ LEFT JOIN car ON relation.car_id = car.id + + \ No newline at end of file