diff --git a/README.md b/README.md index 89bfddcf9a2122115fbb79505aef791ad1b04f87..84dd5e3ffdcbac7009fec8064f386c2eff6681c2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,6 @@ ](https://gitee.com/vonchange/spring-data-mybatis-mini) - **等同于spring data jdbc + mybatis 动态sql能力** **大道至简 极致效率 麻雀虽小 五脏俱全** @@ -35,6 +34,36 @@ close=")">#{item} ``` ![例子](https://gitee.com/vonchange/spring-data-mybatis-mini/raw/master/mini.png) +== 新增融合mybatis-spring-boot实现 只简化mybatis动态sql写法和sql写在markdown文件里 +``` +-- 依赖 详情见mybatis-sql-extend-test模块 + + com.vonchange.common + mybatis-sql-extend + ${spring.mybatis.mini} + +``` +``` + public class SimpleLanguageDriver extends XMLLanguageDriver implements LanguageDriver { + @Override + public SqlSource createSqlSource(Configuration configuration, String script, Class parameterType) { + + String sqlInXml = MybatisSqlLanguageUtil.sqlInXml("mapper",script,new MySQLDialect()); + return super.createSqlSource(configuration, sqlInXml, parameterType); + } +} +``` + +``` +-- 配置 +mybatis: + default-scripting-language-driver: com.vonchange.mybatis.test.config.SimpleLanguageDriver + configuration: + map-underscore-to-camel-case: true + +``` + + == Getting Started 1. 提供单表增删改(没有物理删除) 批量更新插入等基础方法 diff --git a/common-util/pom.xml b/common-util/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ee87c9695add01a49e2f2aff3901b692c5cffa90 --- /dev/null +++ b/common-util/pom.xml @@ -0,0 +1,28 @@ + + + + mybatis-mini-parant + com.vonchange.common + 2.3.9 + + 4.0.0 + + common-util + 2.3.9 + + + + ch.qos.logback + logback-classic + 1.2.3 + + + com.fasterxml.jackson.core + jackson-databind + 2.9.8 + provided + + + \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/Assert.java b/common-util/src/main/java/com/vonchange/common/util/Assert.java new file mode 100644 index 0000000000000000000000000000000000000000..187d68a3359f924803e799cd0e6e4acde016dab2 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/Assert.java @@ -0,0 +1,244 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.vonchange.common.util; + +import java.util.function.Supplier; + +/** + * Assertion utility class that assists in validating arguments. + * + *

Useful for identifying programmer errors early and clearly at runtime. + * + *

For example, if the contract of a public method states it does not + * allow {@code null} arguments, {@code Assert} can be used to validate that + * contract. Doing this clearly indicates a contract violation when it + * occurs and protects the class's invariants. + * + *

Typically used to validate method arguments rather than configuration + * properties, to check for cases that are usually programmer errors rather + * than configuration errors. In contrast to configuration initialization + * code, there is usually no point in falling back to defaults in such methods. + * + *

This class is similar to JUnit's assertion library. If an argument value is + * deemed invalid, an {@link IllegalArgumentException} is thrown (typically). + * For example: + * + *

+ * Assert.notNull(clazz, "The class must not be null");
+ * Assert.isTrue(i > 0, "The value must be greater than zero");
+ * + *

Mainly for internal use within the framework; consider + * Apache's Commons Lang + * for a more comprehensive suite of {@code String} utilities. + * + * @author Keith Donald + * @author Juergen Hoeller + * @author Sam Brannen + * @author Colin Sampaleanu + * @author Rob Harrop + * @since 1.1.2 + */ +public abstract class Assert { + private Assert(){ + throw new IllegalStateException("Utility class"); + } + + /** + * Assert a boolean expression, throwing an {@code IllegalStateException} + * if the expression evaluates to {@code false}. + *

Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException} + * on an assertion failure. + *

Assert.state(id == null, "The id property must not already be initialized");
+ * @param expression a boolean expression + * @param message the exception message to use if the assertion fails + * @throws IllegalStateException if {@code expression} is {@code false} + */ + public static void state(boolean expression, String message) { + if (!expression) { + throw new IllegalStateException(message); + } + } + + /** + * Assert a boolean expression, throwing an {@code IllegalStateException} + * if the expression evaluates to {@code false}. + *

Call {@link #isTrue} if you wish to throw an {@code IllegalArgumentException} + * on an assertion failure. + *

+	 * Assert.state(id == null,
+	 *     () -> "ID for " + entity.getName() + " must not already be initialized");
+	 * 
+ * @param expression a boolean expression + * @param messageSupplier a supplier for the exception message to use if the + * assertion fails + * @throws IllegalStateException if {@code expression} is {@code false} + * @since 5.0 + */ + public static void state(boolean expression, Supplier messageSupplier) { + if (!expression) { + throw new IllegalStateException(nullSafeGet(messageSupplier)); + } + } + + + + /** + * Assert a boolean expression, throwing an {@code IllegalArgumentException} + * if the expression evaluates to {@code false}. + *
Assert.isTrue(i > 0, "The value must be greater than zero");
+ * @param expression a boolean expression + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if {@code expression} is {@code false} + */ + public static void isTrue(boolean expression, String message) { + if (!expression) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert a boolean expression, throwing an {@code IllegalArgumentException} + * if the expression evaluates to {@code false}. + *
+	 * Assert.isTrue(i > 0, () -> "The value '" + i + "' must be greater than zero");
+	 * 
+ * @param expression a boolean expression + * @param messageSupplier a supplier for the exception message to use if the + * assertion fails + * @throws IllegalArgumentException if {@code expression} is {@code false} + * @since 5.0 + */ + public static void isTrue(boolean expression, Supplier messageSupplier) { + if (!expression) { + throw new IllegalArgumentException(nullSafeGet(messageSupplier)); + } + } + + + + /** + * Assert that an object is {@code null}. + *
Assert.isNull(value, "The value must be null");
+ * @param object the object to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object is not {@code null} + */ + public static void isNull( Object object, String message) { + if (object != null) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an object is {@code null}. + *
+	 * Assert.isNull(value, () -> "The value '" + value + "' must be null");
+	 * 
+ * @param object the object to check + * @param messageSupplier a supplier for the exception message to use if the + * assertion fails + * @throws IllegalArgumentException if the object is not {@code null} + * @since 5.0 + */ + public static void isNull( Object object, Supplier messageSupplier) { + if (object != null) { + throw new IllegalArgumentException(nullSafeGet(messageSupplier)); + } + } + + + + /** + * Assert that an object is not {@code null}. + *
Assert.notNull(clazz, "The class must not be null");
+ * @param object the object to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object is {@code null} + */ + public static void notNull( Object object, String message) { + if (object == null) { + throw new IllegalArgumentException(message); + } + } + + /** + * Assert that an object is not {@code null}. + *
+	 * Assert.notNull(clazz, () -> "The class '" + clazz.getName() + "' must not be null");
+	 * 
+ * @param object the object to check + * @param messageSupplier a supplier for the exception message to use if the + * assertion fails + * @throws IllegalArgumentException if the object is {@code null} + * @since 5.0 + */ + public static void notNull( Object object, Supplier messageSupplier) { + if (object == null) { + throw new IllegalArgumentException(nullSafeGet(messageSupplier)); + } + } + + + + + /** + * Assert that an array contains no {@code null} elements. + *

Note: Does not complain if the array is empty! + *

Assert.noNullElements(array, "The array must contain non-null elements");
+ * @param array the array to check + * @param message the exception message to use if the assertion fails + * @throws IllegalArgumentException if the object array contains a {@code null} element + */ + public static void noNullElements( Object[] array, String message) { + if (array != null) { + for (Object element : array) { + if (element == null) { + throw new IllegalArgumentException(message); + } + } + } + } + + /** + * Assert that an array contains no {@code null} elements. + *

Note: Does not complain if the array is empty! + *

+	 * Assert.noNullElements(array, () -> "The " + arrayType + " array must contain non-null elements");
+	 * 
+ * @param array the array to check + * @param messageSupplier a supplier for the exception message to use if the + * assertion fails + * @throws IllegalArgumentException if the object array contains a {@code null} element + * @since 5.0 + */ + public static void noNullElements( Object[] array, Supplier messageSupplier) { + if (array != null) { + for (Object element : array) { + if (element == null) { + throw new IllegalArgumentException(nullSafeGet(messageSupplier)); + } + } + } + } + + + + private static String nullSafeGet( Supplier messageSupplier) { + return (messageSupplier != null ? messageSupplier.get() : null); + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/CharSequenceUtils.java b/common-util/src/main/java/com/vonchange/common/util/CharSequenceUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..f5fa8b7162ca06da9668172dc53200ac5ab84491 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/CharSequenceUtils.java @@ -0,0 +1,198 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.common.util; + +/** + *

Operations on {@link CharSequence} that are + * {@code null} safe.

+ * + * @see CharSequence + * @since 3.0 + * @version $Id: CharSequenceUtils.java 1606051 2014-06-27 12:22:17Z ggregory $ + */ +public class CharSequenceUtils { + + private static final int NOT_FOUND = -1; + + /** + *

{@code CharSequenceUtils} instances should NOT be constructed in + * standard programming.

+ * + *

This constructor is public to permit tools that require a JavaBean + * instance to operate.

+ */ + public CharSequenceUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Returns a new {@code CharSequence} that is a subsequence of this + * sequence starting with the {@code char} value at the specified index.

+ * + *

This provides the {@code CharSequence} equivalent to {@link String#substring(int)}. + * The length (in {@code char}) of the returned sequence is {@code length() - start}, + * so if {@code start == end} then an empty sequence is returned.

+ * + * @param cs the specified subsequence, null returns null + * @param start the start index, inclusive, valid + * @return a new subsequence, may be null + * @throws IndexOutOfBoundsException if {@code start} is negative or if + * {@code start} is greater than {@code length()} + */ + public static CharSequence subSequence(final CharSequence cs, final int start) { + return cs == null ? null : cs.subSequence(start, cs.length()); + } + + //----------------------------------------------------------------------- + /** + *

Finds the first index in the {@code CharSequence} that matches the + * specified character.

+ * + * @param cs the {@code CharSequence} to be processed, not null + * @param searchChar the char to be searched for + * @param start the start index, negative starts at the string start + * @return the index where the search char was found, -1 if not found + */ + static int indexOf(final CharSequence cs, final int searchChar, int start) { + if (cs instanceof String) { + return ((String) cs).indexOf(searchChar, start); + } + final int sz = cs.length(); + if (start < 0) { + start = 0; + } + for (int i = start; i < sz; i++) { + if (cs.charAt(i) == searchChar) { + return i; + } + } + return NOT_FOUND; + } + + /** + * Used by the indexOf(CharSequence methods) as a green implementation of indexOf. + * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the {@code CharSequence} to be searched for + * @param start the start index + * @return the index where the search sequence was found + */ + static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) { + return cs.toString().indexOf(searchChar.toString(), start); + } + + /** + *

Finds the last index in the {@code CharSequence} that matches the + * specified character.

+ * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the char to be searched for + * @param start the start index, negative returns -1, beyond length starts at end + * @return the index where the search char was found, -1 if not found + */ + static int lastIndexOf(final CharSequence cs, final int searchChar, int start) { + if (cs instanceof String) { + return ((String) cs).lastIndexOf(searchChar, start); + } + final int sz = cs.length(); + if (start < 0) { + return NOT_FOUND; + } + if (start >= sz) { + start = sz - 1; + } + for (int i = start; i >= 0; --i) { + if (cs.charAt(i) == searchChar) { + return i; + } + } + return NOT_FOUND; + } + + /** + * Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf + * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the {@code CharSequence} to be searched for + * @param start the start index + * @return the index where the search sequence was found + */ + static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, final int start) { + return cs.toString().lastIndexOf(searchChar.toString(), start); + } + + /** + * Green implementation of toCharArray. + * + * @param cs the {@code CharSequence} to be processed + * @return the resulting char array + */ + static char[] toCharArray(final CharSequence cs) { + if (cs instanceof String) { + return ((String) cs).toCharArray(); + } + final int sz = cs.length(); + final char[] array = new char[cs.length()]; + for (int i = 0; i < sz; i++) { + array[i] = cs.charAt(i); + } + return array; + } + + /** + * Green implementation of regionMatches. + * + * @param cs the {@code CharSequence} to be processed + * @param ignoreCase whether or not to be case insensitive + * @param thisStart the index to start on the {@code cs} CharSequence + * @param substring the {@code CharSequence} to be looked for + * @param start the index to start on the {@code substring} CharSequence + * @param length character length of the region + * @return whether the region matched + */ + static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, + final CharSequence substring, final int start, final int length) { + if (cs instanceof String && substring instanceof String) { + return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length); + } + int index1 = thisStart; + int index2 = start; + int tmpLen = length; + + while (tmpLen-- > 0) { + final char c1 = cs.charAt(index1++); + final char c2 = substring.charAt(index2++); + + if (c1 == c2) { + continue; + } + + if (!ignoreCase) { + return false; + } + + // The same check as in String.regionMatches(): + if (Character.toUpperCase(c1) != Character.toUpperCase(c2) + && Character.toLowerCase(c1) != Character.toLowerCase(c2)) { + return false; + } + } + + return true; + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/CharUtil.java b/common-util/src/main/java/com/vonchange/common/util/CharUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..54453b076dba2a72553d22f468c8c865fc4e5a98 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/CharUtil.java @@ -0,0 +1,402 @@ +package com.vonchange.common.util; + +public class CharUtil { + + // ---------------------------------------------------------------- simple + + /** + * Converts (signed) byte to (unsigned) char. + */ + public static char toChar(final byte b) { + return (char) (b & 0xFF); + } + + /** + * Converts char array into byte array by stripping the high byte of each character. + */ + public static byte[] toSimpleByteArray(final char[] carr) { + byte[] barr = new byte[carr.length]; + for (int i = 0; i < carr.length; i++) { + barr[i] = (byte) carr[i]; + } + return barr; + } + + /** + * Converts char sequence into byte array. + * @see #toSimpleByteArray(char[]) + */ + public static byte[] toSimpleByteArray(final CharSequence charSequence) { + byte[] barr = new byte[charSequence.length()]; + for (int i = 0; i < barr.length; i++) { + barr[i] = (byte) charSequence.charAt(i); + } + return barr; + } + + /** + * Converts byte array to char array by simply extending bytes to chars. + */ + public static char[] toSimpleCharArray(final byte[] barr) { + char[] carr = new char[barr.length]; + for (int i = 0; i < barr.length; i++) { + carr[i] = (char) (barr[i] & 0xFF); + } + return carr; + } + + // ---------------------------------------------------------------- ascii + + /** + * Returns ASCII value of a char. In case of overload, 0x3F is returned. + */ + public static int toAscii(final char c) { + if (c <= 0xFF) { + return c; + } else { + return 0x3F; + } + } + + /** + * Converts char array into {@link #toAscii(char) ASCII} array. + */ + public static byte[] toAsciiByteArray(final char[] carr) { + byte[] barr = new byte[carr.length]; + for (int i = 0; i < carr.length; i++) { + barr[i] = (byte) ((int) (carr[i] <= 0xFF ? carr[i] : 0x3F)); + } + return barr; + } + + /** + * Converts char sequence into ASCII byte array. + */ + public static byte[] toAsciiByteArray(final CharSequence charSequence) { + byte[] barr = new byte[charSequence.length()]; + for (int i = 0; i < barr.length; i++) { + char c = charSequence.charAt(i); + barr[i] = (byte) ((int) (c <= 0xFF ? c : 0x3F)); + } + return barr; + } + + // ---------------------------------------------------------------- raw arrays + + /** + * Converts char array into byte array by replacing each character with two bytes. + */ + public static byte[] toRawByteArray(final char[] carr) { + byte[] barr = new byte[carr.length << 1]; + for (int i = 0, bpos = 0; i < carr.length; i++) { + char c = carr[i]; + barr[bpos++] = (byte) ((c & 0xFF00) >> 8); + barr[bpos++] = (byte) (c & 0x00FF); + } + return barr; + } + + public static char[] toRawCharArray(final byte[] barr) { + int carrLen = barr.length >> 1; + if (carrLen << 1 < barr.length) { + carrLen++; + } + char[] carr = new char[carrLen]; + int i = 0, j = 0; + while (i < barr.length) { + char c = (char) (barr[i] << 8); + i++; + + if (i != barr.length) { + c += barr[i] & 0xFF; + i++; + } + carr[j++] = c; + } + return carr; + } + + + + /** + * Match if one character equals to any of the given character. + * + * @return true if characters match any character from given array, + * otherwise false + */ + public static boolean equalsOne(final char c, final char[] match) { + for (char aMatch : match) { + if (c == aMatch) { + return true; + } + } + return false; + } + + /** + * Finds index of the first character in given array the matches any from the + * given set of characters. + * + * @return index of matched character or -1 + */ + public static int findFirstEqual(final char[] source, final int index, final char[] match) { + for (int i = index; i < source.length; i++) { + if (equalsOne(source[i], match)) { + return i; + } + } + return -1; + } + + /** + * Finds index of the first character in given array the matches any from the + * given set of characters. + * + * @return index of matched character or -1 + */ + public static int findFirstEqual(final char[] source, final int index, final char match) { + for (int i = index; i < source.length; i++) { + if (source[i] == match) { + return i; + } + } + return -1; + } + + + /** + * Finds index of the first character in given array the differs from the + * given set of characters. + * + * @return index of matched character or -1 + */ + public static int findFirstDiff(final char[] source, final int index, final char[] match) { + for (int i = index; i < source.length; i++) { + if (!equalsOne(source[i], match)) { + return i; + } + } + return -1; + } + + /** + * Finds index of the first character in given array the differs from the + * given set of characters. + * + * @return index of matched character or -1 + */ + public static int findFirstDiff(final char[] source, final int index, final char match) { + for (int i = index; i < source.length; i++) { + if (source[i] != match) { + return i; + } + } + return -1; + } + + // ---------------------------------------------------------------- is + + /** + * Returns true if character is a white space ({@code <= ' '}). + * White space definition is taken from String class (see: trim()). + * This method has different results then Character#isWhitespace." + */ + public static boolean isWhitespace(final char c) { + return c <= ' '; + } + + /** + * Returns true if specified character is lowercase ASCII. + * If user uses only ASCIIs, it is much much faster. + */ + public static boolean isLowercaseAlpha(final char c) { + return (c >= 'a') && (c <= 'z'); + } + + /** + * Returns true if specified character is uppercase ASCII. + * If user uses only ASCIIs, it is much much faster. + */ + public static boolean isUppercaseAlpha(final char c) { + return (c >= 'A') && (c <= 'Z'); + } + + public static boolean isAlphaOrDigit(final char c) { + return isDigit(c) || isAlpha(c); + } + + public static boolean isWordChar(final char c) { + return isDigit(c) || isAlpha(c) || (c == '_'); + } + + public static boolean isPropertyNameChar(final char c) { + return isDigit(c) || isAlpha(c) || (c == '_') || (c == '.') || (c == '[') || (c == ']'); + } + + // ---------------------------------------------------------------- RFC + + /** + * Indicates whether the given character is in the {@code ALPHA} set. + * + * @see RFC 3986, appendix A + */ + public static boolean isAlpha(final char c) { + return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z')); + } + + /** + * Indicates whether the given character is in the {@code DIGIT} set. + * + * @see RFC 3986, appendix A + */ + public static boolean isDigit(final char c) { + return c >= '0' && c <= '9'; + } + + /** + * Indicates whether the given character is the hexadecimal digit. + */ + public static boolean isHexDigit(final char c) { + return (c >= '0' && c <= '9') || ((c >= 'a') && (c <= 'f')) || ((c >= 'A') && (c <= 'F')); + } + + /** + * Indicates whether the given character is in the gen-delims set. + * + * @see RFC 3986, appendix A + */ + public static boolean isGenericDelimiter(final int c) { + switch (c) { + case ':': + case '/': + case '?': + case '#': + case '[': + case ']': + case '@': + return true; + default: + return false; + } + } + + /** + * Indicates whether the given character is in the sub-delims set. + * + * @see RFC 3986, appendix A + */ + public static boolean isSubDelimiter(final int c) { + switch (c) { + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + return true; + default: + return false; + } + } + + /** + * Indicates whether the given character is in the reserved set. + * + * @see RFC 3986, appendix A + */ + public static boolean isReserved(final char c) { + return isGenericDelimiter(c) || isSubDelimiter(c); + } + + /** + * Indicates whether the given character is in the unreserved set. + * + * @see RFC 3986, appendix A + */ + public static boolean isUnreserved(final char c) { + return isAlpha(c) || isDigit(c) || c == '-' || c == '.' || c == '_' || c == '~'; + } + + /** + * Indicates whether the given character is in the pchar set. + * + * @see RFC 3986, appendix A + */ + public static boolean isPchar(final char c) { + return isUnreserved(c) || isSubDelimiter(c) || c == ':' || c == '@'; + } + + + // ---------------------------------------------------------------- conversions + + /** + * Uppers lowercase ASCII char. + */ + public static char toUpperAscii(char c) { + if (isLowercaseAlpha(c)) { + c -= (char) 0x20; + } + return c; + } + + + /** + * Lowers uppercase ASCII char. + */ + public static char toLowerAscii(char c) { + if (isUppercaseAlpha(c)) { + c += (char) 0x20; + } + return c; + } + + /** + * Converts hex char to int value. + */ + public static int hex2int(final char c) { + switch (c) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + return c - '0'; + case 'A': + case 'B': + case 'C': + case 'D': + case 'E': + case 'F': + return c - 55; + case 'a': + case 'b': + case 'c': + case 'd': + case 'e': + case 'f': + return c - 87; + default: + throw new IllegalArgumentException("Not a hex: " + c); + } + } + + /** + * Converts integer digit to heck char. + */ + public static char int2hex(final int i) { + return HEX_CHARS[i]; + } + + public static final char[] HEX_CHARS = new char[] {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/ClazzUtils.java b/common-util/src/main/java/com/vonchange/common/util/ClazzUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..68f72aa44facb65f11f4a3944994b868271c1188 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/ClazzUtils.java @@ -0,0 +1,18 @@ +package com.vonchange.common.util; + +import com.vonchange.common.util.bean.convert.Converter; + +public class ClazzUtils { + private ClazzUtils() { + throw new IllegalStateException("Utility class"); + } + /** + * isBaseType + */ + public static boolean isBaseType(Class clazz) { + //||clazz== Time.class||clazz == Timestamp.class + return Converter.hasConvertKey(clazz)|| clazz.isPrimitive()||clazz.isEnum(); + } + + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/ConvertUtil.java b/common-util/src/main/java/com/vonchange/common/util/ConvertUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..d911207578238a5c626a1cb35da616a07eb16cc4 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/ConvertUtil.java @@ -0,0 +1,182 @@ +package com.vonchange.common.util; + + +import com.vonchange.common.util.bean.convert.Converter; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; + +/** + * 简单方式(效率高)实现类型转换,细节部分会不如ConvertUtils :ConvertUtils一次类型转换需要69ms 有点代价过高 + * 不过多个也大概是这个时间? + * + * @author vonchange@163.com + */ +public class ConvertUtil { + private static final String NULLSTR = "NULL"; + + private static Object toNull(Object value) { + if (null == value) { + return null; + } + if (value instanceof String) { + value = value.toString().trim(); + if (NULLSTR.equals(value)) { + return null; + } + if("".equals(value)){ + return null; + } + } + return value; + } + + public static Integer toInteger(Object value) { + value = toNull(value); + return Converter.get().toInteger(value); + } + + public static String toString(Object value) { + if (null == value) { + return null; + } + return Converter.get().toString(value); + } + + public static Long toLong(Object value) { + value = toNull(value); + return Converter.get().toLong(value); + } + + public static Boolean toBoolean(Object value) { + value = toNull(value); + return Converter.get().toBoolean(value); + } + + public static Double toDouble(Object value) { + value = toNull(value); + return Converter.get().toDouble(value); + } + + public static Float toFloat(Object value) { + value = toNull(value); + return Converter.get().toFloat(value); + } + + public static Short toShort(Object value) { + value = toNull(value); + return Converter.get().toShort(value); + } + + public static Byte toByte(Object value) { + value = toNull(value); + return Converter.get().toByte(value); + } + public static Character toCharacter(Object value){ + value = toNull(value); + return Converter.get().toCharacter(value); + } + public static BigInteger toBigInteger(Object value){ + value = toNull(value); + return Converter.get().toBigInteger(value); + } + + + + public static BigDecimal toBigDecimal(Object value) { + value = toNull(value); + return Converter.get().toBigDecimal(value); + } + + public static LocalDateTime toLocalDateTime(Object value) { + value = toNull(value); + return Converter.get().toLocalDateTime(value); + } + public static LocalDate toLocalDate(Object value) { + value = toNull(value); + return Converter.get().toLocalDate(value); + } + + public static LocalTime toLocalTime(Object value) { + value = toNull(value); + return Converter.get().toLocalTime(value); + } + + public static Date toDate(Object value) { + value = toNull(value); + return Converter.get().toDate(value); + } + + @SuppressWarnings("unchecked") + public static T toObject(Object value, Class targetType) { + if (null == value) { + return null; + } + if(value.getClass().isAssignableFrom(targetType)){ + return (T) value; + } + return toObjectDetail(value,targetType); + } + @SuppressWarnings("unchecked") + public static T toObjectDetail(Object value, Class targetType) { + if (null == value) { + return null; + } + + if (targetType.isAssignableFrom(String.class)) { + return (T) ConvertUtil.toString(value); + } + if (targetType.isAssignableFrom(Integer.class)||targetType.isAssignableFrom(int.class)) { + return (T)ConvertUtil.toInteger(value); + } + if (targetType.isAssignableFrom(Long.class)||targetType.isAssignableFrom(long.class)) { + return (T)ConvertUtil.toLong(value); + } + if (targetType.isAssignableFrom(BigDecimal.class)) { + return (T)ConvertUtil.toBigDecimal(value); + } + if (targetType.isAssignableFrom(Boolean.class)||targetType.isAssignableFrom(boolean.class)) { + return (T)ConvertUtil.toBoolean(value); + } + if (targetType.isAssignableFrom(Float.class)||targetType.isAssignableFrom(float.class)) { + return (T)ConvertUtil.toFloat(value); + } + if (targetType.isAssignableFrom(Double.class)||targetType.isAssignableFrom(double.class)) { + return (T)ConvertUtil.toDouble(value); + } + if (targetType.isAssignableFrom(Short.class)||targetType.isAssignableFrom(short.class)) { + return (T)ConvertUtil.toShort(value); + } + if (targetType.isAssignableFrom(Byte.class)||targetType.isAssignableFrom(byte.class)) { + return (T)ConvertUtil.toByte(value); + } + if (targetType.isAssignableFrom(Character.class)||targetType.isAssignableFrom(char.class)) { + return (T)ConvertUtil.toCharacter(value); + } + if (targetType.isAssignableFrom(BigInteger.class)) { + return (T)ConvertUtil.toBigInteger(value); + } + if (targetType.isAssignableFrom(Date.class)) { + return (T)ConvertUtil.toDate(value); + } + if (targetType.isAssignableFrom(LocalDateTime.class)) { + return (T)ConvertUtil.toLocalDateTime(value); + } + if (targetType.isAssignableFrom(LocalDate.class)) { + return (T)ConvertUtil.toLocalDate(value); + } + if (targetType.isAssignableFrom(LocalTime.class)) { + return (T)ConvertUtil.toLocalTime(value); + } + if (targetType.isEnum()) { + Class type = targetType; + return (T) Enum.valueOf(type, value.toString()); + } + return (T)value; + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/FileUtil.java b/common-util/src/main/java/com/vonchange/common/util/FileUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..7095d459477e7161e0c2a5e65cd3867e58a8d919 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/FileUtil.java @@ -0,0 +1,26 @@ +package com.vonchange.common.util; + + +import com.vonchange.common.util.io.UnicodeInputStream; + +import java.io.IOException; +import java.io.InputStream; + +public class FileUtil { + public static String readUTFString(final InputStream inputStream) throws IOException { + UnicodeInputStream in = null; + try { + in = new UnicodeInputStream(inputStream, null); + return StreamUtil.copy(in, detectEncoding(in)).toString(); + } finally { + StreamUtil.close(in); + } + } + private static String detectEncoding(final UnicodeInputStream in) { + String encoding = in.getDetectedEncoding(); + if (encoding == null) { + encoding = StringPool.UTF_8; + } + return encoding; + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/JsonUtil.java b/common-util/src/main/java/com/vonchange/common/util/JsonUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..c917b2d8c9f4ff01795d4cbf412bba3b9dcb7d21 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/JsonUtil.java @@ -0,0 +1,72 @@ +package com.vonchange.common.util; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class JsonUtil { + private static Logger logger = LoggerFactory.getLogger(JsonUtil.class); + private JsonUtil() { + throw new IllegalStateException("Utility class"); + } + public static String toJson(Object object) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + logger.error("序列化对象失败{}",e); + } + return null; + } + + public static T fromJson(String json, TypeReference type) { + return fromJson(json,null,type); + } + public static T evalJson(String json, TypeReference type) throws IOException { + return evalJson(json,null,type); + } + public static T evalJson(String json, Class clazz) throws IOException { + return evalJson(json,clazz,null); + } + public static T evalJson(String json, Class clazz,TypeReference type) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); + T t =null; + if(null!=clazz){ + t = mapper.readValue(json, clazz); + } + if(null!=type){ + t = mapper.readValue(json, type); + } + return t; + } + + private static T fromJson(String json, Class clazz,TypeReference type) { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); + T t =null; + try { + if(null!=clazz){ + t = mapper.readValue(json, clazz); + } + if(null!=type){ + t = mapper.readValue(json, type); + } + } catch (IOException e) { + logger.error("反序列化对象失败{}",e); + } + return t; + } + public static T fromJson(String json, Class clazz) { + return fromJson(json,clazz,null); + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/MD5Util.java b/common-util/src/main/java/com/vonchange/common/util/MD5Util.java new file mode 100644 index 0000000000000000000000000000000000000000..b8ee4f6809d5e6ac2bc5438f259db988fa08db22 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/MD5Util.java @@ -0,0 +1,36 @@ +package com.vonchange.common.util; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; + +public class MD5Util { + public static String getMD5(String str){ + return getMD5(str.getBytes()); + } + public static String getMD5(byte[] source){ + String s=null; + //用来将字节转换成16进制表示的字符 + char[] hexDigits={'0','1','2','3','4','5','6','7','8','9', + 'a','b','c','d','e','f'}; + try { + MessageDigest md=MessageDigest.getInstance("MD5"); + md.update(source); + //MD5的计算结果是一个128位的长整数,用字节表示为16个字节 + byte[] tmp=md.digest(); + //每个字节用16进制表示的话,使用2个字符(高4位一个,低4位一个),所以表示成16进制需要32个字符 + char[] str=new char[16*2]; + int k=0;//转换结果中对应的字符位置 + for(int i=0;i<16;i++){//对MD5的每一个字节转换成16进制字符 + byte byte0=tmp[i]; + str[k++]=hexDigits[byte0>>>4 & 0xf];//对字节高4位进行16进制转换 + str[k++]=hexDigits[byte0 & 0xf]; //对字节低4位进行16进制转换 + } + s=new String(str); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return s; + } + + + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/NestedExceptionUtils.java b/common-util/src/main/java/com/vonchange/common/util/NestedExceptionUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..00b1e1e412fdf49465bd77f789fb42dd87699f50 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/NestedExceptionUtils.java @@ -0,0 +1,74 @@ +/* + * Copyright 2002-2017 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.vonchange.common.util; + +public abstract class NestedExceptionUtils { + + /** + * Build a message for the given base message and root cause. + * @param message the base message + * @param cause the root cause + * @return the full exception message + */ + + public static String buildMessage( String message, Throwable cause) { + if (cause == null) { + return message; + } + StringBuilder sb = new StringBuilder(64); + if (message != null) { + sb.append(message).append("; "); + } + sb.append("nested exception is ").append(cause); + return sb.toString(); + } + + /** + * Retrieve the innermost cause of the given exception, if any. + * @param original the original exception to introspect + * @return the innermost exception, or {@code null} if none + * @since 4.3.9 + */ + + public static Throwable getRootCause( Throwable original) { + if (original == null) { + return null; + } + Throwable rootCause = null; + Throwable cause = original.getCause(); + while (cause != null && cause != rootCause) { + rootCause = cause; + cause = cause.getCause(); + } + return rootCause; + } + + /** + * Retrieve the most specific cause of the given exception, that is, + * either the innermost cause (root cause) or the exception itself. + *

Differs from {@link #getRootCause} in that it falls back + * to the original exception if there is no root cause. + * @param original the original exception to introspect + * @return the most specific cause (never {@code null}) + * @since 4.3.9 + */ + public static Throwable getMostSpecificCause(Throwable original) { + Throwable rootCause = getRootCause(original); + return (rootCause != null ? rootCause : original); + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/StreamUtil.java b/common-util/src/main/java/com/vonchange/common/util/StreamUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..8d26a798c591920e346981e930f919bfd93158d1 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/StreamUtil.java @@ -0,0 +1,144 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util; + + +import com.vonchange.common.util.io.FastCharArrayWriter; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.io.UnsupportedEncodingException; +import java.io.Writer; + + +/** + * Optimized byte and character stream utilities. + */ +public class StreamUtil { + private static final int ZERO = 0; + private static final int NEGATIVE_ONE = -1; + private static final int ALL = -1; + public static int ioBufferSizeX = 16384; + /** + * Closes silently the closable object. If it is {@link Flushable}, it + * will be flushed first. No exception will be thrown if an I/O error occurs. + */ + public static void close(final Closeable closeable) { + if (closeable != null) { + if (closeable instanceof Flushable) { + try { + ((Flushable) closeable).flush(); + } catch (IOException ignored) { + } + } + + try { + closeable.close(); + } catch (IOException ignored) { + } + } + } + + + public static FastCharArrayWriter copy(final InputStream input, final String encoding) throws IOException { + return copy(input, encoding, ALL); + } + public static FastCharArrayWriter copy(final InputStream input, final String encoding, final int count) throws IOException { + try (FastCharArrayWriter output = createFastCharArrayWriter()) { + copy(input, output, encoding, count); + return output; + } + } + private static FastCharArrayWriter createFastCharArrayWriter() { + return new FastCharArrayWriter(bufferSize()); + } + + private static int bufferSize() { + return ioBufferSizeX; + } + private static int bufferSize(final int count) { + final int ioBufferSize = ioBufferSizeX; + if (count < ioBufferSize) { + return count; + } else { + return ioBufferSize; + } + } + public static T copy(final InputStream input, final T output, final String encoding, final int count) throws IOException { + copy(inputStreamReadeOf(input, encoding), output, count); + return output; + } + public static InputStreamReader inputStreamReadeOf(final InputStream input, final String encoding) throws UnsupportedEncodingException { + return new InputStreamReader(input, encoding); + } + public static int copy(final Reader input, final Writer output, final int count) throws IOException { + if (count == ALL) { + return copy(input, output); + } + + int numToRead = count; + char[] buffer = new char[numToRead]; + + int totalRead = ZERO; + int read; + + while (numToRead > ZERO) { + read = input.read(buffer, ZERO, bufferSize(numToRead)); + if (read == NEGATIVE_ONE) { + break; + } + output.write(buffer, ZERO, read); + + numToRead = numToRead - read; + totalRead = totalRead + read; + } + + output.flush(); + return totalRead; + } + public static int copy(final Reader input, final Writer output) throws IOException { + int numToRead = bufferSize(); + char[] buffer = new char[numToRead]; + + int totalRead = ZERO; + int read; + + while ((read = input.read(buffer, ZERO, numToRead)) >= ZERO) { + output.write(buffer, ZERO, read); + totalRead = totalRead + read; + } + + output.flush(); + return totalRead; + } + + + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/StringPool.java b/common-util/src/main/java/com/vonchange/common/util/StringPool.java new file mode 100644 index 0000000000000000000000000000000000000000..968b4a061a34a9e3dcba72beec114e4ffaa69690 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/StringPool.java @@ -0,0 +1,74 @@ +// +// Source code recreated from a .class file by IntelliJ IDEA +// (powered by Fernflower decompiler) +// + +package com.vonchange.common.util; + +public interface StringPool { + String AMPERSAND = "&"; + String AND = "and"; + String AT = "@"; + String ASTERISK = "*"; + String STAR = "*"; + String BACK_SLASH = "\\"; + String COLON = ":"; + String COMMA = ","; + String DASH = "-"; + String DOLLAR = "$"; + String DOT = "."; + String DOTDOT = ".."; + String DOT_CLASS = ".class"; + String DOT_JAVA = ".java"; + String EMPTY = ""; + String EQUALS = "="; + String FALSE = "false"; + String SLASH = "/"; + String HASH = "#"; + String HAT = "^"; + String LEFT_BRACE = "{"; + String LEFT_BRACKET = "("; + String LEFT_CHEV = "<"; + String NEWLINE = "\n"; + String N = "n"; + String NO = "no"; + String NULL = "null"; + String OFF = "off"; + String ON = "on"; + String PERCENT = "%"; + String PIPE = "|"; + String PLUS = "+"; + String QUESTION_MARK = "?"; + String EXCLAMATION_MARK = "!"; + String QUOTE = "\""; + String RETURN = "\r"; + String TAB = "\t"; + String RIGHT_BRACE = "}"; + String RIGHT_BRACKET = ")"; + String RIGHT_CHEV = ">"; + String SEMICOLON = ";"; + String SINGLE_QUOTE = "'"; + String BACKTICK = "`"; + String SPACE = " "; + String TILDA = "~"; + String LEFT_SQ_BRACKET = "["; + String RIGHT_SQ_BRACKET = "]"; + String TRUE = "true"; + String UNDERSCORE = "_"; + String UTF_8 = "UTF-8"; + String US_ASCII = "US-ASCII"; + String ISO_8859_1 = "ISO-8859-1"; + String Y = "y"; + String YES = "yes"; + String ONE = "1"; + String ZERO = "0"; + String DOLLAR_LEFT_BRACE = "${"; + String CRLF = "\r\n"; + String HTML_NBSP = " "; + String HTML_AMP = "&"; + String HTML_QUOTE = """; + String HTML_LT = "<"; + String HTML_GT = ">"; + String[] EMPTY_ARRAY = new String[0]; + byte[] BYTES_NEW_LINE = "\n".getBytes(); +} diff --git a/common-util/src/main/java/com/vonchange/common/util/StringUtils.java b/common-util/src/main/java/com/vonchange/common/util/StringUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..4704205c37efe79921cd815fa76df7b3a6aaabc2 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/StringUtils.java @@ -0,0 +1,484 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.common.util; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static com.vonchange.common.util.StringPool.EMPTY; + +public class StringUtils { + public static String uuid() { + String uuid = UUID.randomUUID().toString(); + return remove(uuid, "-"); + } + public static String remove(String s, String sub) { + int c = 0; + int sublen = sub.length(); + if (sublen == 0) { + return s; + } else { + int i = s.indexOf(sub, c); + if (i == -1) { + return s; + } else { + StringBuilder sb = new StringBuilder(s.length()); + + do { + sb.append(s, c, i); + c = i + sublen; + } while((i = s.indexOf(sub, c)) != -1); + + if (c < s.length()) { + sb.append(s, c, s.length()); + } + + return sb.toString(); + } + } + } + public static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + + public static boolean isNotBlank(final CharSequence cs) { + return !isBlank(cs); + } + /** + * 简单模板实现 String str = "I'm not a {0}, age is {1,number,short}", height is + * {2,number,#.#}; + * + * @param pattern + * @param arguments + * @return String + */ + public static String format(String pattern, Object... arguments) { + MessageFormat temp = new MessageFormat(pattern); + return temp.format(arguments); + } + public static String strNums(String str, String split, int num) { + if(num==0){ + return ""; + } + StringBuilder fullStr = new StringBuilder(); + for (int i = 0; i < num; i++) { + fullStr.append(str).append(split); + } + return fullStr.substring(0, fullStr.length()-split.length()); + } + public static String strList(List strs, String split) { + if(null==strs||strs.isEmpty()){ + return ""; + } + StringBuilder fullStr = new StringBuilder(); + for (String string : strs) { + fullStr.append(string).append(split); + } + return fullStr.substring(0, fullStr.length()-split.length()); + } + public static Boolean isNull(Object obj) { + if (null == obj) { + return true; + } + String str = String.valueOf(obj); + if (isBlank(str)) { + return true; + } + return false; + } + + public static final char UNDERLINE='_'; + public static String camelToUnderline(String param){ + if (param==null||"".equals(param.trim())){ + return ""; + } + int len=param.length(); + StringBuilder sb=new StringBuilder(len); + for (int i = 0; i < len; i++) { + char c=param.charAt(i); + if (Character.isUpperCase(c)){ + sb.append(UNDERLINE); + sb.append(Character.toLowerCase(c)); + }else{ + sb.append(c); + } + } + return sb.toString(); + } + + /** + * 正则表达式 实现 + * @param tplStr + * @param data + */ + public static String tplByMap(String tplStr, Map data) { + Matcher m = Pattern.compile("\\$\\{([\\w\\.]*)\\}").matcher(tplStr); + List patternList = new ArrayList(); + List replaceStrList = new ArrayList(); + while (m.find()) { + String group = m.group(); + patternList.add(group); + group = group.replaceAll("\\$|\\{|\\}", ""); + String value = ""; + if (null != data.get(group)) { + value = String.valueOf(data.get(group)); + } + replaceStrList.add(value); + } + tplStr= replaceEach(tplStr, patternList.toArray(new String[patternList.size()]), replaceStrList.toArray(new String[replaceStrList.size()])); + return tplStr; + } + + /*public static String tpl(String tplStr, Map data) { + StringTemplateParser stp = new StringTemplateParser(); + + return stp.parse(tplStr,macroName -> { + return ConvertUtil.toString(data.get(macroName)); + }); + }*/ + + public static String capitalize(final String str) { + int strLen; + if (str == null || (strLen = str.length()) == 0) { + return str; + } + + final char firstChar = str.charAt(0); + if (Character.isTitleCase(firstChar)) { + // already capitalized + return str; + } + + return new StringBuilder(strLen) + .append(Character.toTitleCase(firstChar)) + .append(str.substring(1)) + .toString(); + } + public static boolean equals(final CharSequence cs1, final CharSequence cs2) { + if (cs1 == cs2) { + return true; + } + if (cs1 == null || cs2 == null) { + return false; + } + if (cs1 instanceof String && cs2 instanceof String) { + return cs1.equals(cs2); + } + return CharSequenceUtils.regionMatches(cs1, false, 0, cs2, 0, Math.max(cs1.length(), cs2.length())); + } + + public static String replaceEach(final String text, final String[] searchList, final String[] replacementList) { + return replaceEach(text, searchList, replacementList, false, 0); + } + private static String replaceEach( + final String text, final String[] searchList, final String[] replacementList, final boolean repeat, final int timeToLive) { + + // mchyzer Performance note: This creates very few new objects (one major goal) + // let me know if there are performance requests, we can create a harness to measure + + if (text == null || text.isEmpty() || searchList == null || + searchList.length == 0 || replacementList == null || replacementList.length == 0) { + return text; + } + + // if recursing, this shouldn't be less than 0 + if (timeToLive < 0) { + throw new IllegalStateException("Aborting to protect against StackOverflowError - " + + "output of one loop is the input of another"); + } + + final int searchLength = searchList.length; + final int replacementLength = replacementList.length; + + // make sure lengths are ok, these need to be equal + if (searchLength != replacementLength) { + throw new IllegalArgumentException("Search and Replace array lengths don't match: " + + searchLength + + " vs " + + replacementLength); + } + + // keep track of which still have matches + final boolean[] noMoreMatchesForReplIndex = new boolean[searchLength]; + + // index on index that the match was found + int textIndex = -1; + int replaceIndex = -1; + int tempIndex = -1; + + // index of replace array that will replace the search string found + // NOTE: logic duplicated below START + for (int i = 0; i < searchLength; i++) { + if (noMoreMatchesForReplIndex[i] || searchList[i] == null || + searchList[i].isEmpty() || replacementList[i] == null) { + continue; + } + tempIndex = text.indexOf(searchList[i]); + + // see if we need to keep searching for this + if (tempIndex == -1) { + noMoreMatchesForReplIndex[i] = true; + } else { + if (textIndex == -1 || tempIndex < textIndex) { + textIndex = tempIndex; + replaceIndex = i; + } + } + } + // NOTE: logic mostly below END + + // no search strings found, we are done + if (textIndex == -1) { + return text; + } + + int start = 0; + + // get a good guess on the size of the result buffer so it doesn't have to double if it goes over a bit + int increase = 0; + + // count the replacement text elements that are larger than their corresponding text being replaced + for (int i = 0; i < searchList.length; i++) { + if (searchList[i] == null || replacementList[i] == null) { + continue; + } + final int greater = replacementList[i].length() - searchList[i].length(); + if (greater > 0) { + increase += 3 * greater; // assume 3 matches + } + } + // have upper-bound at 20% increase, then let Java take over + increase = Math.min(increase, text.length() / 5); + + final StringBuilder buf = new StringBuilder(text.length() + increase); + + while (textIndex != -1) { + + for (int i = start; i < textIndex; i++) { + buf.append(text.charAt(i)); + } + buf.append(replacementList[replaceIndex]); + + start = textIndex + searchList[replaceIndex].length(); + + textIndex = -1; + replaceIndex = -1; + tempIndex = -1; + // find the next earliest match + // NOTE: logic mostly duplicated above START + for (int i = 0; i < searchLength; i++) { + if (noMoreMatchesForReplIndex[i] || searchList[i] == null || + searchList[i].isEmpty() || replacementList[i] == null) { + continue; + } + tempIndex = text.indexOf(searchList[i], start); + + // see if we need to keep searching for this + if (tempIndex == -1) { + noMoreMatchesForReplIndex[i] = true; + } else { + if (textIndex == -1 || tempIndex < textIndex) { + textIndex = tempIndex; + replaceIndex = i; + } + } + } + // NOTE: logic duplicated above END + + } + final int textLength = text.length(); + for (int i = start; i < textLength; i++) { + buf.append(text.charAt(i)); + } + final String result = buf.toString(); + if (!repeat) { + return result; + } + + return replaceEach(result, searchList, replacementList, repeat, timeToLive - 1); + } + public static boolean endsWith(final CharSequence str, final CharSequence suffix) { + return endsWith(str, suffix, false); + } + private static boolean endsWith(final CharSequence str, final CharSequence suffix, final boolean ignoreCase) { + if (str == null || suffix == null) { + return str == null && suffix == null; + } + if (suffix.length() > str.length()) { + return false; + } + final int strOffset = str.length() - suffix.length(); + return CharSequenceUtils.regionMatches(str, ignoreCase, strOffset, suffix, 0, suffix.length()); + } + + public static boolean startsWithChar(String s, char c) { + if (s.length() == 0) { + return false; + } else { + return s.charAt(0) == c; + } + } + public static boolean containsOnlyDigitsAndSigns(CharSequence string) { + int size = string.length(); + + for(int i = 0; i < size; ++i) { + char c = string.charAt(i); + if (!isDigit(c) && c != '-' && c != '+') { + return false; + } + } + + return true; + } + public static boolean isDigit(char c) { + return c >= '0' && c <= '9'; + } + public static String[] split(final String src, final String delimiter) { + int maxparts = (src.length() / delimiter.length()) + 2; // one more for the last + int[] positions = new int[maxparts]; + int dellen = delimiter.length(); + + int i, j = 0; + int count = 0; + positions[0] = - dellen; + while ((i = src.indexOf(delimiter, j)) != -1) { + count++; + positions[count] = i; + j = i + dellen; + } + count++; + positions[count] = src.length(); + + String[] result = new String[count]; + + for (i = 0; i < count; i++) { + result[i] = src.substring(positions[i] + dellen, positions[i + 1]); + } + return result; + } + + /** + * Returns true if string contains only digits. + */ + public static boolean containsOnlyDigits(final CharSequence string) { + int size = string.length(); + for (int i = 0; i < size; i++) { + char c = string.charAt(i); + if (!isDigit(c)) { + return false; + } + } + return true; + } + + /** + * Splits a string in several parts (tokens) that are separated by delimiter + * characters. Delimiter may contains any number of character and it is + * always surrounded by two strings. + * + * @param src source to examine + * @param d string with delimiter characters + * + * @return array of tokens + */ + public static String[] splitc(final String src, final String d) { + if ((d.length() == 0) || (src.length() == 0)) { + return new String[] {src}; + } + return splitc(src, d.toCharArray()); + } + /** + * Splits a string in several parts (tokens) that are separated by delimiter + * characters. Delimiter may contains any number of character and it is + * always surrounded by two strings. + * + * @param src source to examine + * @param delimiters char array with delimiter characters + * + * @return array of tokens + */ + public static String[] splitc(final String src, final char[] delimiters) { + if ((delimiters.length == 0) || (src.length() == 0) ) { + return new String[] {src}; + } + char[] srcc = src.toCharArray(); + + int maxparts = srcc.length + 1; + int[] start = new int[maxparts]; + int[] end = new int[maxparts]; + + int count = 0; + + start[0] = 0; + int s = 0, e; + if (CharUtil.equalsOne(srcc[0], delimiters)) { // string starts with delimiter + end[0] = 0; + count++; + s = CharUtil.findFirstDiff(srcc, 1, delimiters); + if (s == -1) { // nothing after delimiters + return new String[] {EMPTY, EMPTY}; + } + start[1] = s; // new start + } + while (true) { + // find new end + e = CharUtil.findFirstEqual(srcc, s, delimiters); + if (e == -1) { + end[count] = srcc.length; + break; + } + end[count] = e; + + // find new start + count++; + s = CharUtil.findFirstDiff(srcc, e, delimiters); + if (s == -1) { + start[count] = end[count] = srcc.length; + break; + } + start[count] = s; + } + count++; + String[] result = new String[count]; + for (int i = 0; i < count; i++) { + result[i] = src.substring(start[i], end[i]); + } + return result; + } +/* public static void main(String[] args) { + + String template = "Hello ${foo}. Today is ${dayName}."; + // prepare data + Map map = new HashMap<>(); + map.put("foo", "Jodd"); + map.put("dayName", "Sunday"); + }*/ +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/BeanUtil.java b/common-util/src/main/java/com/vonchange/common/util/bean/BeanUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..75a6399f22825e5fa3d2a1b444b34a2bc2c2877f --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/BeanUtil.java @@ -0,0 +1,45 @@ + +package com.vonchange.common.util.bean; + + +import com.vonchange.common.util.ConvertUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.util.Map; + +public class BeanUtil { + private static final Logger log = LoggerFactory.getLogger(BeanUtil.class); + public Object getPropertyT(Object entity,String property) throws IntrospectionException, InvocationTargetException, IllegalAccessException { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, entity.getClass()); + return propertyDescriptor.getReadMethod().invoke(entity); + } + public void setPropertyT(Object entity,String property,Object value) throws InvocationTargetException, IllegalAccessException, IntrospectionException { + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(property, entity.getClass()); + value= ConvertUtil.toObject(value,propertyDescriptor.getPropertyType()); + propertyDescriptor.getWriteMethod().invoke(entity,value); + } + public Object getProperty(Object entity,String property) { + try { + if(entity instanceof Map){ + return ((Map) entity).get(property); + } + return getPropertyT(entity, property); + } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) { + log.error("",e); + return null; + } + } + public void setProperty(Object entity,String property,Object value){ + try { + setPropertyT(entity, property, value); + } catch (IntrospectionException | InvocationTargetException | IllegalAccessException e) { + log.error("",e); + } + } + +} + diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/Converter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/Converter.java new file mode 100644 index 0000000000000000000000000000000000000000..5ec01e55aaa994e982bcd154bf3a8be87c32fd8a --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/Converter.java @@ -0,0 +1,563 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert; + + +import com.vonchange.common.util.bean.convert.impl.BigDecimalConverter; +import com.vonchange.common.util.bean.convert.impl.BigIntegerConverter; +import com.vonchange.common.util.bean.convert.impl.BooleanConverter; +import com.vonchange.common.util.bean.convert.impl.ByteArrayConverter; +import com.vonchange.common.util.bean.convert.impl.ByteConverter; +import com.vonchange.common.util.bean.convert.impl.CharacterConverter; +import com.vonchange.common.util.bean.convert.impl.DateConverter; +import com.vonchange.common.util.bean.convert.impl.DoubleConverter; +import com.vonchange.common.util.bean.convert.impl.FloatConverter; +import com.vonchange.common.util.bean.convert.impl.IntegerConverter; +import com.vonchange.common.util.bean.convert.impl.LocalDateConverter; +import com.vonchange.common.util.bean.convert.impl.LocalDateTimeConverter; +import com.vonchange.common.util.bean.convert.impl.LocalTimeConverter; +import com.vonchange.common.util.bean.convert.impl.LongConverter; +import com.vonchange.common.util.bean.convert.impl.ShortConverter; +import com.vonchange.common.util.bean.convert.impl.StringConverter; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; + +/** + * + */ +public class Converter { + + private static final Converter CONVERTER = new Converter(); + private static Map,TypeConverter> convertMap= new HashMap<>(); + static{ + convertMap.put(Boolean.class,new BooleanConverter()); + convertMap.put(BigDecimal.class,new BigDecimalConverter()); + convertMap.put(BigInteger.class,new BigIntegerConverter()); + convertMap.put(Byte.class,new ByteConverter()); + convertMap.put(Character.class,new CharacterConverter()); + convertMap.put(Double.class,new DoubleConverter()); + convertMap.put(Float.class,new FloatConverter()); + convertMap.put(Integer.class,new IntegerConverter()); + convertMap.put(Long.class,new LongConverter()); + convertMap.put(Short.class,new ShortConverter()); + convertMap.put(String.class,new StringConverter()); + convertMap.put(LocalDate.class,new LocalDateConverter()); + convertMap.put(LocalDateTime.class,new LocalDateTimeConverter()); + convertMap.put(LocalTime.class,new LocalTimeConverter()); + convertMap.put(Date.class,new DateConverter()); + convertMap.put(byte[].class,new ByteArrayConverter()); + } + + /** + * Returns default instance. + */ + public static Converter get() { + return CONVERTER; + } + + public static boolean hasConvertKey(Class type){ + return convertMap.containsKey(type); + } + @SuppressWarnings("unchecked") + public static TypeConverter getConvert(Class type) { + /* for (Map.Entry,TypeConverter> entry:convertMap.entrySet()) { + if(entry.getKey().isAssignableFrom(type)){ + return entry.getValue(); + } + }*/ + return convertMap.get(type); + } + // ---------------------------------------------------------------- boolean + + /** + * Converts value to Boolean. + */ + public Boolean toBoolean(final Object value) { + return (Boolean) getConvert(Boolean.class).convert(value); + } + + + + /** + * Converts value to Boolean. Returns default value + * when conversion result is null + */ + public Boolean toBoolean(final Object value, final Boolean defaultValue) { + final Boolean result = toBoolean(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to boolean. Returns default value + * when conversion result is null. + */ + public boolean toBooleanValue(final Object value, final boolean defaultValue) { + final Boolean result = toBoolean(value); + if (result == null) { + return defaultValue; + } + return result.booleanValue(); + } + + /** + * Converts value to boolean with common default value. + */ + public boolean toBooleanValue(final Object value) { + return toBooleanValue(value, false); + } + + // ---------------------------------------------------------------- integer + + /** + * Converts value to Integer. + */ + public Integer toInteger(final Object value) { + return (Integer) getConvert(Integer.class).convert(value); + } + + /** + * Converts value to Integer. Returns default value + * when conversion result is null + */ + public Integer toInteger(final Object value, final Integer defaultValue) { + final Integer result = toInteger(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to int. Returns default value + * when conversion result is null. + */ + public int toIntValue(final Object value, final int defaultValue) { + final Integer result = toInteger(value); + if (result == null) { + return defaultValue; + } + return result.intValue(); + } + + /** + * Converts value to int with common default value. + */ + public int toIntValue(final Object value) { + return toIntValue(value, 0); + } + + // ---------------------------------------------------------------- long + + /** + * Converts value to Long. + */ + public Long toLong(final Object value) { + return (Long) getConvert(Long.class).convert(value); + } + + /** + * Converts value to Long. Returns default value + * when conversion result is null + */ + public Long toLong(final Object value, final Long defaultValue) { + final Long result = toLong(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to long. Returns default value + * when conversion result is null. + */ + public long toLongValue(final Object value, final long defaultValue) { + final Long result = toLong(value); + if (result == null) { + return defaultValue; + } + return result.longValue(); + } + + /** + * Converts value to long with common default value. + */ + public long toLongValue(final Object value) { + return toLongValue(value, 0); + } + + // ---------------------------------------------------------------- float + + /** + * Converts value to Float. + */ + public Float toFloat(final Object value) { + return (Float) getConvert(Float.class).convert(value); + } + + /** + * Converts value to Float. Returns default value + * when conversion result is null + */ + public Float toFloat(final Object value, final Float defaultValue) { + final Float result = toFloat(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to float. Returns default value + * when conversion result is null. + */ + public float toFloatValue(final Object value, final float defaultValue) { + final Float result = toFloat(value); + if (result == null) { + return defaultValue; + } + return result.floatValue(); + } + + /** + * Converts value to float with common default value. + */ + public float toFloatValue(final Object value) { + return toFloatValue(value, 0); + } + + // ---------------------------------------------------------------- double + + /** + * Converts value to Double. + */ + public Double toDouble(final Object value) { + return (Double) getConvert(Double.class).convert(value); + } + + /** + * Converts value to Double. Returns default value + * when conversion result is null + */ + public Double toDouble(final Object value, final Double defaultValue) { + final Double result = toDouble(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to double. Returns default value + * when conversion result is null. + */ + public double toDoubleValue(final Object value, final double defaultValue) { + final Double result = toDouble(value); + if (result == null) { + return defaultValue; + } + return result.doubleValue(); + } + + /** + * Converts value to double with common default value. + */ + public double toDoubleValue(final Object value) { + return toDoubleValue(value, 0); + } + + // ---------------------------------------------------------------- short + + /** + * Converts value to Short. + */ + public Short toShort(final Object value) { + return (Short) getConvert(Short.class).convert(value); + } + + /** + * Converts value to Short. Returns default value + * when conversion result is null + */ + public Short toShort(final Object value, final Short defaultValue) { + final Short result = toShort(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to short. Returns default value + * when conversion result is null. + */ + public short toShortValue(final Object value, final short defaultValue) { + final Short result = toShort(value); + if (result == null) { + return defaultValue; + } + return result.shortValue(); + } + + /** + * Converts value to short with common default value. + */ + public short toShortValue(final Object value) { + return toShortValue(value, (short) 0); + } + + // ---------------------------------------------------------------- character + + /** + * Converts value to Character. + */ + public Character toCharacter(final Object value) { + return (Character) getConvert(Character.class).convert(value); + } + + /** + * Converts value to Character. Returns default value + * when conversion result is null + */ + public Character toCharacter(final Object value, final Character defaultValue) { + final Character result = toCharacter(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to char. Returns default value + * when conversion result is null. + */ + public char toCharValue(final Object value, final char defaultValue) { + final Character result = toCharacter(value); + if (result == null) { + return defaultValue; + } + return result.charValue(); + } + + /** + * Converts value to char with common default value. + */ + public char toCharValue(final Object value) { + return toCharValue(value, (char) 0); + } + + // ---------------------------------------------------------------- byte + + /** + * Converts value to Byte. + */ + public Byte toByte(final Object value) { + return (Byte) getConvert(Byte.class).convert(value); + } + + /** + * Converts value to Byte. Returns default value + * when conversion result is null + */ + public Byte toByte(final Object value, final Byte defaultValue) { + final Byte result = toByte(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to byte. Returns default value + * when conversion result is null. + */ + public byte toByteValue(final Object value, final byte defaultValue) { + final Byte result = toByte(value); + if (result == null) { + return defaultValue; + } + return result.byteValue(); + } + + /** + * Converts value to byte with common default value. + */ + public byte toByteValue(final Object value) { + return toByteValue(value, (byte) 0); + } + + // ---------------------------------------------------------------- array + + + + // ---------------------------------------------------------------- string + + /** + * Converts value to String. + */ + public String toString(final Object value) { + return (String) getConvert(String.class).convert(value); + } + + /** + * Converts value to String. Returns default value + * when conversion result is null + */ + public String toString(final Object value, final String defaultValue) { + final String result = toString(value); + if (result == null) { + return defaultValue; + } + return result; + } + + + // ---------------------------------------------------------------- bigs + + /** + * Converts value to BigInteger. + */ + public BigInteger toBigInteger(final Object value) { + return (BigInteger) getConvert(BigInteger.class).convert(value); + } + + /** + * Converts value to BigInteger. Returns default value + * when conversion result is null + */ + public BigInteger toBigInteger(final Object value, final BigInteger defaultValue) { + final BigInteger result = toBigInteger(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to BigDecimal. + */ + public BigDecimal toBigDecimal(final Object value) { + return (BigDecimal) getConvert(BigDecimal.class).convert(value); + } + + /** + * Converts value to BigDecimal. Returns default value + * when conversion result is null + */ + public BigDecimal toBigDecimal(final Object value, final BigDecimal defaultValue) { + final BigDecimal result = toBigDecimal(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to LocalDate. + */ + public LocalDate toLocalDate(final Object value) { + return (LocalDate) getConvert(LocalDate.class).convert(value); + } + + /** + * Converts value to LocalDate. Returns default value + * when conversion result is null + */ + public LocalDate toLocalDate(final Object value, final LocalDate defaultValue) { + final LocalDate result = toLocalDate(value); + if (result == null) { + return defaultValue; + } + return result; + } + /** + * Converts value to LocalDateTime. + */ + public LocalDateTime toLocalDateTime(final Object value) { + return (LocalDateTime) getConvert(LocalDateTime.class).convert(value); + } + + /** + * Converts value to LocalDateTime. Returns default value + * when conversion result is null + */ + public LocalDateTime toLocalDateTime(final Object value, final LocalDateTime defaultValue) { + final LocalDateTime result = toLocalDateTime(value); + if (result == null) { + return defaultValue; + } + return result; + } + + + /** + * Converts value to LocalTime. + */ + public LocalTime toLocalTime(final Object value) { + return (LocalTime) getConvert(LocalTime.class).convert(value); + } + + /** + * Converts value to LocalTime. Returns default value + * when conversion result is null + */ + public LocalTime toLocalTime(final Object value, final LocalTime defaultValue) { + final LocalTime result = toLocalTime(value); + if (result == null) { + return defaultValue; + } + return result; + } + + /** + * Converts value to Date. + */ + public Date toDate(final Object value) { + return (Date) getConvert(Date.class).convert(value); + } + + /** + * Converts value to LocalTime. Returns default value + * when conversion result is null + */ + public Date toDate(final Object value, final Date defaultValue) { + final Date result = toDate(value); + if (result == null) { + return defaultValue; + } + return result; + } +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConversionException.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConversionException.java new file mode 100644 index 0000000000000000000000000000000000000000..4a97ff05d6098b4fdffee9185ae4ed564fb2d750 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConversionException.java @@ -0,0 +1,55 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert; + + +import com.vonchange.common.util.exception.UncheckedException; + +/** + * Type conversion exception. + */ +public class TypeConversionException extends UncheckedException { + + public TypeConversionException(final Throwable t) { + super(t); + } + + public TypeConversionException(final String message) { + super(message); + } + + public TypeConversionException(final String message, final Throwable t) { + super(message, t); + } + + public TypeConversionException(final Object value) { + this("Conversion failed: " + value); + } + + public TypeConversionException(final Object value, final Throwable t) { + this("Conversion failed: " + value, t); + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConvertCommon.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConvertCommon.java new file mode 100644 index 0000000000000000000000000000000000000000..39fa19c525d5049e0418bec760ae8b156badc810 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConvertCommon.java @@ -0,0 +1,19 @@ +package com.vonchange.common.util.bean.convert; + +public abstract class TypeConvertCommon implements TypeConverter{ + + public abstract T convert(Object value); + + public T convert(final Object value, final T defaultValue){ + if (value == null) { + return defaultValue; + } + try { + return convert(value); + } + catch (Exception e) { + return defaultValue; + } + } +} + diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..7d52fa1f1520502dd4120d2819a9a9f9b9183dfa --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/TypeConverter.java @@ -0,0 +1,54 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert; + + + +/** + * Object converter interface. + * + */ +public interface TypeConverter { + + /** + * Converts object received as parameter into object of another class. + * For example, an Integer converter tries to convert given objects + * into target Integer object. Converters should try all reasonable + * ways of conversion into target object, depending on target type. + * + * @param value object to convert from + * + * @return resulting object converted to target type + * @throws TypeConversionException if conversion fails + */ + T convert(Object value); + + /** + * Converts object and returns default value if conversion fails. + */ + T convert(final Object value, final T defaultValue); + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BigDecimalConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BigDecimalConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..6812d94063ea1e6b9c1adb0b831c464d153b0f91 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BigDecimalConverter.java @@ -0,0 +1,62 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +import java.math.BigDecimal; + +/** + * Converts given object to BigDecimal. + * Conversion rules: + *

    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible
  • + *
+ */ +public class BigDecimalConverter extends TypeConvertCommon implements TypeConverter { + + @Override + public BigDecimal convert(final Object value) { + if (value == null) { + return null; + } + + if (value instanceof BigDecimal) { + return (BigDecimal) value; + } + try { + return new BigDecimal(value.toString().trim()); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BigIntegerConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BigIntegerConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..434371ef7dfa607a284faa3a7b10149c2816313d --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BigIntegerConverter.java @@ -0,0 +1,64 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +import java.math.BigInteger; + +/** + * Converts given object to BigInteger. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible
  • + *
+ */ +public class BigIntegerConverter extends TypeConvertCommon implements TypeConverter { + + public BigInteger convert(final Object value) { + if (value == null) { + return null; + } + + if (value instanceof BigInteger) { + return (BigInteger) value; + } + if (value instanceof Number) { + return new BigInteger(String.valueOf(((Number)value).longValue())); + } + try { + return new BigInteger(value.toString().trim()); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BooleanConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BooleanConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..3cc7b005468c70f6687db9c9c55a1ce464e62a30 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/BooleanConverter.java @@ -0,0 +1,90 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +import static com.vonchange.common.util.StringPool.FALSE; +import static com.vonchange.common.util.StringPool.N; +import static com.vonchange.common.util.StringPool.NO; +import static com.vonchange.common.util.StringPool.OFF; +import static com.vonchange.common.util.StringPool.ON; +import static com.vonchange.common.util.StringPool.ONE; +import static com.vonchange.common.util.StringPool.TRUE; +import static com.vonchange.common.util.StringPool.Y; +import static com.vonchange.common.util.StringPool.YES; +import static com.vonchange.common.util.StringPool.ZERO; + +/** + * Converts given object to Boolean. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed. Then common boolean strings are matched: + * "yes", "y", "true", "on", "1" for true; and opposite values + * for false.
  • + *
+ */ +public class BooleanConverter extends TypeConvertCommon implements TypeConverter { + + public Boolean convert(final Object value) { + if (value == null) { + return null; + } + + if (value.getClass() == Boolean.class) { + return (Boolean) value; + } + + String stringValue = value.toString(); + if (stringValue.isEmpty()) { + return Boolean.FALSE; + } + + stringValue = stringValue.trim().toLowerCase(); + if (stringValue.equals(YES) || + stringValue.equals(Y) || + stringValue.equals(TRUE) || + stringValue.equals(ON) || + stringValue.equals(ONE)) { + return Boolean.TRUE; + } + if (stringValue.equals(NO) || + stringValue.equals(N) || + stringValue.equals(FALSE) || + stringValue.equals(OFF) || + stringValue.equals(ZERO)) { + return Boolean.FALSE; + } + + throw new TypeConversionException(value); + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ByteArrayConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ByteArrayConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..467c1dd639e03d948c7f9105e4105179de9bd1ac --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ByteArrayConverter.java @@ -0,0 +1,198 @@ +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.Converter; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +import java.sql.Blob; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; + +public class ByteArrayConverter extends TypeConvertCommon implements TypeConverter { + public static final char[] NUMBER_DELIMITERS = new char[] {',', ';', '\n'}; + + + @Override + public byte[] convert(final Object value) { + if (value == null) { + return null; + } + + final Class valueClass = value.getClass(); + + if (!valueClass.isArray()) { + // source is not an array + return convertValueToArray(value); + } + + // source is an array + return convertArrayToArray(value); + } + + /** + * Converts type using type converter manager. + */ + protected byte convertType(final Object value) { + return Converter.get().toByte(value); + //return typeConverterManager.convertType(value, byte.class).byteValue(); + } + + /** + * Creates an array with single element. + */ + protected byte[] convertToSingleElementArray(final Object value) { + return new byte[] {convertType(value)}; + } + + /** + * Converts non-array value to array. Detects various + * types and collections, iterates them to make conversion + * and to create target array. + */ + protected byte[] convertValueToArray(final Object value) { + if (value instanceof Blob) { + final Blob blob = (Blob) value; + try { + final long length = blob.length(); + if (length > Integer.MAX_VALUE) { + throw new TypeConversionException("Blob is too big."); + } + return blob.getBytes(1, (int) length); + } catch (SQLException sex) { + throw new TypeConversionException(value, sex); + } + } + + if (value instanceof Collection) { + final Collection collection = (Collection) value; + final byte[] target = new byte[collection.size()]; + + int i = 0; + for (final Object element : collection) { + target[i] = convertType(element); + i++; + } + + return target; + } + + if (value instanceof Iterable) { + final Iterable iterable = (Iterable) value; + + final ArrayList byteArrayList = new ArrayList<>(); + + for (final Object element : iterable) { + final byte convertedValue = convertType(element); + byteArrayList.add(Byte.valueOf(convertedValue)); + } + + final byte[] array = new byte[byteArrayList.size()]; + + for (int i = 0; i < byteArrayList.size(); i++) { + final Byte b = byteArrayList.get(i); + array[i] = b.byteValue(); + } + + return array; + } + + if (value instanceof CharSequence) { + final String[] strings = StringUtils.splitc(value.toString(), NUMBER_DELIMITERS); + return convertArrayToArray(strings); + } + + // everything else: + return convertToSingleElementArray(value); + } + + /** + * Converts array value to array. + */ + protected byte[] convertArrayToArray(final Object value) { + final Class valueComponentType = value.getClass().getComponentType(); + + final byte[] result; + + if (valueComponentType.isPrimitive()) { + result = convertPrimitiveArrayToArray(value, valueComponentType); + } else { + // convert object array to target array + final Object[] array = (Object[]) value; + result = new byte[array.length]; + + for (int i = 0; i < array.length; i++) { + result[i] = convertType(array[i]); + } + } + + return result; + } + + + /** + * Converts primitive array to target array. + */ + protected byte[] convertPrimitiveArrayToArray(final Object value, final Class primitiveComponentType) { + byte[] result = null; + + if (primitiveComponentType == byte.class) { + return (byte[]) value; + } + + if (primitiveComponentType == int.class) { + final int[] array = (int[]) value; + result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (byte) array[i]; + } + } + else if (primitiveComponentType == long.class) { + final long[] array = (long[]) value; + result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (byte) array[i]; + } + } + else if (primitiveComponentType == float.class) { + final float[] array = (float[]) value; + result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (byte) array[i]; + } + } + else if (primitiveComponentType == double.class) { + final double[] array = (double[]) value; + result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (byte) array[i]; + } + } + else if (primitiveComponentType == short.class) { + final short[] array = (short[]) value; + result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (byte) array[i]; + } + } + else if (primitiveComponentType == char.class) { + final char[] array = (char[]) value; + result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (byte) array[i]; + } + } + else if (primitiveComponentType == boolean.class) { + final boolean[] array = (boolean[]) value; + result = new byte[array.length]; + for (int i = 0; i < array.length; i++) { + result[i] = (byte) (array[i] ? 1 : 0); + } + } + return result; + } + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ByteConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ByteConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..07d62487ab2003dbb57337aa1cac986ea64f0021 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ByteConverter.java @@ -0,0 +1,72 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +/** + * Converts given object to Byte. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible.
  • + *
+ * Number string may start with plus and minus sign. + */ +public class ByteConverter extends TypeConvertCommon implements TypeConverter { + + @Override + public Byte convert(final Object value) { + if (value == null) { + return null; + } + if (value.getClass() == Byte.class) { + return (Byte) value; + } + if (value instanceof Number) { + return Byte.valueOf(((Number)value).byteValue()); + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? Byte.valueOf((byte) 1) : Byte.valueOf((byte) 0); + } + + try { + String stringValue = value.toString().trim(); + if (StringUtils.startsWithChar(stringValue, '+')) { + stringValue = stringValue.substring(1); + } + return Byte.valueOf(stringValue); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/CharacterConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/CharacterConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..76657093004ad5e82759295bf135bd3e7cda40fd --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/CharacterConverter.java @@ -0,0 +1,79 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +/** + * Converts given object to Character. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • Number is converted to char value
  • + *
  • finally, toString() value of length 1 is converted to char
  • + *
  • if string is longer, and made of digits, try to convert it to int first
  • + *
+ */ +public class CharacterConverter extends TypeConvertCommon implements TypeConverter { + + public Character convert(final Object value) { + if (value == null) { + return null; + } + if (value.getClass() == Character.class) { + return (Character) value; + } + if (value instanceof Number) { + char c = (char) ((Number) value).intValue(); + return Character.valueOf(c); + } + try { + String s = value.toString(); + if (s.length() != 1) { + s = s.trim(); + if (!StringUtils.containsOnlyDigitsAndSigns(s)) { + throw new TypeConversionException(value); + } + + try { + char c = (char) Integer.parseInt(s); + return Character.valueOf(c); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + return Character.valueOf(s.charAt(0)); + } catch (IndexOutOfBoundsException ioobex) { + throw new TypeConversionException(value, ioobex); + } + } + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/DateConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/DateConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..ea026ae3647dad86ac9e5d915c51f4690873d47e --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/DateConverter.java @@ -0,0 +1,54 @@ +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; +import com.vonchange.common.util.time.TimeUtil; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.util.Calendar; +import java.util.Date; + +public class DateConverter extends TypeConvertCommon implements TypeConverter { + + @Override + public Date convert(final Object value) { + if (value == null) { + return null; + } + + if (value instanceof Date) { + return (Date) value; + } + if (value instanceof Calendar) { + return new Date(((Calendar)value).getTimeInMillis()); + } + if (value instanceof LocalDateTime) { + return TimeUtil.toDate((LocalDateTime)value); + } + if (value instanceof LocalDate) { + return TimeUtil.toDate((LocalDate)value); + } + if (value instanceof Number) { + return new Date(((Number) value).longValue()); + } + + final String stringValue = value.toString().trim(); + + if (!StringUtils.containsOnlyDigits(stringValue)) { + // try to parse default string format + return TimeUtil.toDate(LocalDateTime.parse(stringValue)); + } + + try { + long milliseconds = Long.parseLong(stringValue); + return new Date(milliseconds); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/DoubleConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/DoubleConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..70df332461a431c3138c13ad055986d0f040ef06 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/DoubleConverter.java @@ -0,0 +1,72 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +/** + * Converts given object to Double. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible.
  • + *
+ * Number string may start with plus and minus sign. + */ +public class DoubleConverter extends TypeConvertCommon implements TypeConverter { + + public Double convert(final Object value) { + if (value == null) { + return null; + } + + if (value.getClass() == Double.class) { + return (Double) value; + } + if (value instanceof Number) { + return Double.valueOf(((Number)value).doubleValue()); + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? Double.valueOf(1) : Double.valueOf(0); + } + + try { + String stringValue = value.toString().trim(); + if (StringUtils.startsWithChar(stringValue, '+')) { + stringValue = stringValue.substring(1); + } + return Double.valueOf(stringValue); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/FloatConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/FloatConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..7e5bed8ca960d87816b43180d69aa23080bdd4d0 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/FloatConverter.java @@ -0,0 +1,72 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +/** + * Converts given object to Float. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible.
  • + *
+ * Number string may start with plus and minus sign. + */ +public class FloatConverter extends TypeConvertCommon implements TypeConverter { + + public Float convert(final Object value) { + if (value == null) { + return null; + } + + if (value.getClass() == Float.class) { + return (Float) value; + } + if (value instanceof Number) { + return Float.valueOf(((Number)value).floatValue()); + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? Float.valueOf(1) : Float.valueOf(0); + } + + try { + String stringValue = value.toString().trim(); + if (StringUtils.startsWithChar(stringValue, '+')) { + stringValue = stringValue.substring(1); + } + return Float.valueOf(stringValue); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/IntegerConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/IntegerConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..6c48ca0d9d4ef822ccb131a8e7c38dd2fd46387f --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/IntegerConverter.java @@ -0,0 +1,72 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +/** + * Converts given object to an Integer. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible.
  • + *
+ * Number string may start with plus and minus sign. + */ +public class IntegerConverter extends TypeConvertCommon implements TypeConverter { + + public Integer convert(final Object value) { + if (value == null) { + return null; + } + + if (value.getClass() == Integer.class) { + return (Integer) value; + } + if (value instanceof Number) { + return Integer.valueOf(((Number)value).intValue()); + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? Integer.valueOf(1) : Integer.valueOf(0); + } + + try { + String stringValue = value.toString().trim(); + if (StringUtils.startsWithChar(stringValue, '+')) { + stringValue = stringValue.substring(1); + } + return Integer.valueOf(stringValue); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalDateConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalDateConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..e9a881761b1cecac7c5809cbb28dda2806891743 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalDateConverter.java @@ -0,0 +1,85 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; +import com.vonchange.common.util.time.TimeUtil; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Calendar; +import java.util.Date; + +public class LocalDateConverter extends TypeConvertCommon implements TypeConverter { + @Override + public LocalDate convert(Object value) { + if (value == null) { + return null; + } + + if (value instanceof LocalDateTime) { + return ((LocalDateTime)value).toLocalDate(); + } + if (value instanceof Calendar) { + return TimeUtil.fromCalendar((Calendar) value).toLocalDate(); + } + if (value instanceof Timestamp) { + return TimeUtil.fromMilliseconds(((Timestamp)value).getTime()).toLocalDate(); + } + if (value instanceof Date) { + if(value instanceof java.sql.Date){ + return ((java.sql.Date) value).toLocalDate(); + } + return TimeUtil.fromDate((Date) value).toLocalDate(); + } + if (value instanceof Number) { + return TimeUtil.fromMilliseconds(((Number)value).longValue()).toLocalDate(); + } + if (value instanceof LocalTime) { + throw new TypeConversionException("Can't convert to date just from time: " + value); + } + + String stringValue = value.toString().trim(); + + if (!StringUtils.containsOnlyDigits(stringValue)) { + // try to parse default string format + return LocalDate.parse(stringValue); + } + + try { + return TimeUtil.fromMilliseconds(Long.parseLong(stringValue)).toLocalDate(); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalDateTimeConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalDateTimeConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..e8a3259b8c58ec1a29fc5a779494618af34e14cd --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalDateTimeConverter.java @@ -0,0 +1,82 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; +import com.vonchange.common.util.time.TimeUtil; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Calendar; +import java.util.Date; + +public class LocalDateTimeConverter extends TypeConvertCommon implements TypeConverter { + @Override + public LocalDateTime convert(Object value) { + if (value == null) { + return null; + } + + if (value instanceof LocalDate) { + return LocalDateTime.of(((LocalDate) value), LocalTime.MIDNIGHT); + } + if (value instanceof Calendar) { + return TimeUtil.fromCalendar((Calendar) value); + } + if (value instanceof Timestamp) { + return TimeUtil.fromMilliseconds(((Timestamp)value).getTime()); + } + if (value instanceof Date) { + return TimeUtil.fromDate((Date) value); + } + if (value instanceof Number) { + return TimeUtil.fromMilliseconds(((Number)value).longValue()); + } + if (value instanceof LocalTime) { + throw new TypeConversionException("Can't convert to date just from time: " + value); + } + + String stringValue = value.toString().trim(); + + if (!StringUtils.containsOnlyDigits(stringValue)) { + // try to parse default string format + return LocalDateTime.parse(stringValue); + } + + try { + return TimeUtil.fromMilliseconds(Long.parseLong(stringValue)); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalTimeConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalTimeConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..e3ce6bfb5f1689629a2746a95952a028732dac6d --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LocalTimeConverter.java @@ -0,0 +1,82 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; +import com.vonchange.common.util.time.TimeUtil; + +import java.sql.Timestamp; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Calendar; +import java.util.Date; + +public class LocalTimeConverter extends TypeConvertCommon implements TypeConverter { + @Override + public LocalTime convert(Object value) { + if (value == null) { + return null; + } + + if (value instanceof LocalDateTime) { + return ((LocalDateTime)value).toLocalTime(); + } + if (value instanceof Calendar) { + return TimeUtil.fromCalendar((Calendar) value).toLocalTime(); + } + if (value instanceof Timestamp) { + return TimeUtil.fromMilliseconds(((Timestamp)value).getTime()).toLocalTime(); + } + if (value instanceof Date) { + return TimeUtil.fromDate((Date) value).toLocalTime(); + } + if (value instanceof Number) { + return TimeUtil.fromMilliseconds(((Number)value).longValue()).toLocalTime(); + } + if (value instanceof LocalDate) { + throw new TypeConversionException("Can't convert to time just from date: " + value); + } + + String stringValue = value.toString().trim(); + + if (!StringUtils.containsOnlyDigits(stringValue)) { + // try to parse default string format + return LocalTime.parse(stringValue); + } + + try { + return TimeUtil.fromMilliseconds(Long.parseLong(stringValue)).toLocalTime(); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LongConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LongConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..f7e62f6c9e85b9ca8cf4b03f2966bdf3847cbf11 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/LongConverter.java @@ -0,0 +1,72 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +/** + * Converts given object to a Long. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible.
  • + *
+ * Number string may start with plus and minus sign. + */ +public class LongConverter extends TypeConvertCommon implements TypeConverter { + + public Long convert(final Object value) { + if (value == null) { + return null; + } + + if (value.getClass() == Long.class) { + return (Long) value; + } + if (value instanceof Number) { + return Long.valueOf(((Number)value).longValue()); + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? Long.valueOf(1L) : Long.valueOf(0L); + } + + try { + String stringValue = value.toString().trim(); + if (StringUtils.startsWithChar(stringValue, '+')) { + stringValue = stringValue.substring(1); + } + return Long.valueOf(stringValue); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ShortConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ShortConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..454f281aa8ed458f0b8ea63df13d0b03d242624f --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/ShortConverter.java @@ -0,0 +1,73 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +/** + * Converts given object to Short. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • object of destination type is simply casted
  • + *
  • object is converted to string, trimmed, and then converted if possible.
  • + *
+ * Number string may start with plus and minus sign. + */ +public class ShortConverter extends TypeConvertCommon implements TypeConverter { + + @Override + public Short convert(final Object value) { + if (value == null) { + return null; + } + + if (value.getClass() == Short.class) { + return (Short) value; + } + if (value instanceof Number) { + return Short.valueOf(((Number)value).shortValue()); + } + if (value instanceof Boolean) { + return ((Boolean) value).booleanValue() ? Short.valueOf((short) 1) : Short.valueOf((short) 0); + } + + try { + String stringValue = value.toString().trim(); + if (StringUtils.startsWithChar(stringValue, '+')) { + stringValue = stringValue.substring(1); + } + return Short.valueOf(stringValue); + } catch (NumberFormatException nfex) { + throw new TypeConversionException(value, nfex); + } + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/StringConverter.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/StringConverter.java new file mode 100644 index 0000000000000000000000000000000000000000..bce8ef888b9c3d4ccf4b13946577ffb9e7c80e3b --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/impl/StringConverter.java @@ -0,0 +1,80 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.bean.convert.impl; + + +import com.vonchange.common.util.bean.convert.TypeConversionException; +import com.vonchange.common.util.bean.convert.TypeConvertCommon; +import com.vonchange.common.util.bean.convert.TypeConverter; + +import java.sql.Clob; +import java.sql.SQLException; + +/** + * Converts given object to String. + * Conversion rules: + *
    + *
  • null value is returned as null
  • + *
  • for CharSequence type returns toString value
  • + *
  • Class returns cass name
  • + *
  • char[] is used for creating string
  • + *
  • arrays are converted to comma-separated list of toString values
  • + *
  • Clob is converted
  • + *
  • finally, toString() value is returned.
  • + *
+ */ +public class StringConverter extends TypeConvertCommon implements TypeConverter { + + @Override + public String convert(final Object value) { + if (value == null) { + return null; + } + + if (value instanceof CharSequence) { // for speed + return value.toString(); + } + Class type = value.getClass(); + if (type == Class.class) { + return ((Class) value).getName(); + } + + if (value instanceof Clob) { + Clob clob = (Clob) value; + try { + long length = clob.length(); + if (length > Integer.MAX_VALUE) { + throw new TypeConversionException("Clob is too big."); + } + return clob.getSubString(1, (int) length); + } catch (SQLException sex) { + throw new TypeConversionException(value, sex); + } + } + return value.toString(); + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/convert/package-info.java b/common-util/src/main/java/com/vonchange/common/util/bean/convert/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..1737d32b4cc7127d64b5e863dc57e082fcd63727 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/convert/package-info.java @@ -0,0 +1,33 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +/** + * Slick and various type conversions. Following rules are applied: + *
    + *
  • There are no default values. If conversion fails, TypeConversionException will be thrown.
  • + *
  • Conversion of null value is also null.
  • + *
+ */ +package com.vonchange.common.util.bean.convert; \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/bean/package-info.java b/common-util/src/main/java/com/vonchange/common/util/bean/package-info.java new file mode 100644 index 0000000000000000000000000000000000000000..3b9c79306bff03f412c6ef8adede9da1672ced4d --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/bean/package-info.java @@ -0,0 +1 @@ +package com.vonchange.common.util.bean; \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/exception/ExceptionUtil.java b/common-util/src/main/java/com/vonchange/common/util/exception/ExceptionUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..02b706ca1cd57ce42d60404064c5cfcf32c0ed25 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/exception/ExceptionUtil.java @@ -0,0 +1,302 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.exception; + + +import com.vonchange.common.util.StreamUtil; +import com.vonchange.common.util.StringUtils; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.UndeclaredThrowableException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collection; + +/** + * Few exception utilities. + */ +public class ExceptionUtil { + + /** + * Returns current stack trace in form of array of stack trace elements. + * First stack trace element is removed. + * Since an exception is thrown internally, this method is slow. + */ + @SuppressWarnings({"ThrowCaughtLocally"}) + public static StackTraceElement[] getCurrentStackTrace() { + StackTraceElement[] ste = new Exception().getStackTrace(); + if (ste.length > 1) { + StackTraceElement[] result = new StackTraceElement[ste.length - 1]; + System.arraycopy(ste, 1, result, 0, ste.length - 1); + return result; + } else { + return ste; + } + } + + // ---------------------------------------------------------------- exception stack trace + + /** + * Returns stack trace filtered by class names. + */ + public static StackTraceElement[] getStackTrace(final Throwable t, final String[] allow, final String[] deny) { + StackTraceElement[] st = t.getStackTrace(); + ArrayList result = new ArrayList<>(st.length); + + elementLoop: + for (StackTraceElement element : st) { + String className = element.getClassName(); + if (allow != null) { + boolean validElemenet = false; + for (String filter : allow) { + if (className.contains(filter)) { + validElemenet = true; + break; + } + } + if (!validElemenet) { + continue; + } + } + if (deny != null) { + for (String filter : deny) { + if (className.contains(filter)) { + continue elementLoop; + } + } + } + result.add(element); + } + st = new StackTraceElement[result.size()]; + return result.toArray(st); + } + + /** + * Returns stack trace chain filtered by class names. + */ + public static StackTraceElement[][] getStackTraceChain(Throwable t, final String[] allow, final String[] deny) { + ArrayList result = new ArrayList<>(); + while (t != null) { + StackTraceElement[] stack = getStackTrace(t, allow, deny); + result.add(stack); + t = t.getCause(); + } + StackTraceElement[][] allStacks = new StackTraceElement[result.size()][]; + for (int i = 0; i < allStacks.length; i++) { + allStacks[i] = result.get(i); + } + return allStacks; + } + + + /** + * Returns exception chain starting from top up to root cause. + */ + public static Throwable[] getExceptionChain(Throwable throwable) { + ArrayList list = new ArrayList<>(); + list.add(throwable); + while ((throwable = throwable.getCause()) != null) { + list.add(throwable); + } + Throwable[] result = new Throwable[list.size()]; + return list.toArray(result); + } + + + // ---------------------------------------------------------------- exception to string + + + /** + * Prints stack trace into a String. + */ + public static String exceptionStackTraceToString(final Throwable t) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw, true); + + t.printStackTrace(pw); + + StreamUtil.close(pw); + StreamUtil.close(sw); + + return sw.toString(); + } + + /** + * Prints full exception stack trace, from top to root cause, into a String. + */ + public static String exceptionChainToString(Throwable t) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw, true); + while (t != null) { + t.printStackTrace(pw); + t = t.getCause(); + } + + StreamUtil.close(pw); + StreamUtil.close(sw); + + return sw.toString(); + } + + /** + * Build a message for the given base message and its cause. + */ + public static String buildMessage(final String message, Throwable cause) { + if (cause != null) { + cause = getRootCause(cause); + StringBuilder buf = new StringBuilder(); + if (message != null) { + buf.append(message).append("; "); + } + buf.append("<--- ").append(cause); + return buf.toString(); + } else { + return message; + } + } + + // ---------------------------------------------------------------- root cause + + /** + * Introspects the Throwable to obtain the root cause. + *

+ * This method walks through the exception chain to the last element, + * "root" of the tree, and returns that exception. If no root cause found + * returns provided throwable. + */ + public static Throwable getRootCause(final Throwable throwable) { + Throwable cause = throwable.getCause(); + if (cause == null) { + return throwable; + } + + Throwable t = throwable; + + // defend against (malicious?) circularity + for (int i = 0; i < 1000; i++) { + cause = t.getCause(); + if (cause == null) { + return t; + } + t = cause; + } + + return throwable; + } + + /** + * Finds throwing cause in exception stack. Returns throwable object if cause class is matched. + * Otherwise, returns null. + */ + @SuppressWarnings({"unchecked"}) + public static T findCause(Throwable throwable, final Class cause) { + while (throwable != null) { + if (throwable.getClass().equals(cause)) { + return (T) throwable; + } + throwable = throwable.getCause(); + } + return null; + } + + + // ---------------------------------------------------------------- sql + + /** + * Rolls up SQL exceptions by taking each proceeding exception + * and making it a child of the previous using the setNextException + * method of SQLException. + */ + public static SQLException rollupSqlExceptions(final Collection exceptions) { + SQLException parent = null; + for (SQLException exception : exceptions) { + if (parent != null) { + exception.setNextException(parent); + } + parent = exception; + } + return parent; + } + + // ---------------------------------------------------------------- misc + + /** + * Throws checked exceptions in un-checked manner. + */ + public static void throwRuntimeException(final Throwable throwable) { + throw wrapToRuntimeException(throwable); + } + + /** + * Returns non-null message for a throwable. + */ + public static String message(final Throwable throwable) { + String message = throwable.getMessage(); + + if (StringUtils.isBlank(message)) { + message = throwable.toString(); + } + + return message; + } + + /** + * Wraps exception to {@code RuntimeException}. + */ + public static RuntimeException wrapToRuntimeException(final Throwable throwable) { + if (throwable instanceof RuntimeException) { + return (RuntimeException) throwable; + } + return new RuntimeException(throwable); + } + public static Exception wrapToException(final Throwable throwable) { + if (throwable instanceof Exception) { + return (Exception) throwable; + } + return new RuntimeException(throwable); + } + + /** + * Unwraps invocation and undeclared exceptions to real cause. + */ + public static Throwable unwrapThrowable(final Throwable wrappedThrowable) { + Throwable unwrapped = wrappedThrowable; + while (true) { + if (unwrapped instanceof InvocationTargetException) { + unwrapped = ((InvocationTargetException) unwrapped).getTargetException(); + } + else if (unwrapped instanceof UndeclaredThrowableException) { + unwrapped = ((UndeclaredThrowableException) unwrapped).getUndeclaredThrowable(); + } + else { + return unwrapped; + } + } + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/exception/UncheckedException.java b/common-util/src/main/java/com/vonchange/common/util/exception/UncheckedException.java new file mode 100644 index 0000000000000000000000000000000000000000..1bf848938eb3031f72d8b46f90143880424d28c2 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/exception/UncheckedException.java @@ -0,0 +1,214 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.exception; + + + +import java.io.IOException; +import java.io.PrintStream; +import java.io.PrintWriter; +import java.io.UncheckedIOException; +import java.util.concurrent.Callable; + +/** + * Unchecked exception and also a wrapper for checked exceptions. + */ +@SuppressWarnings({"SynchronizationOnLocalVariableOrMethodParameter"}) +public class UncheckedException extends RuntimeException { + + protected final Throwable cause; + + /** + * Divider between causes printouts. + */ + protected static final String CAUSE_DIV = "---[cause]------------------------------------------------------------------------"; + + /** + * If set to true stack trace will be enhanced with cause's stack traces. + */ + protected final boolean showCauseDetails; + + // ---------------------------------------------------------------- constructors + + public UncheckedException(final Throwable t) { + super(t.getMessage()); + cause = t; + this.showCauseDetails = true; + } + + public UncheckedException(final Throwable t, final boolean showCauseDetails) { + super(t.getMessage()); + cause = t; + this.showCauseDetails = showCauseDetails; + } + + public UncheckedException() { + super(); + cause = null; + this.showCauseDetails = false; + } + + public UncheckedException(final String message) { + super(message); + cause = null; + this.showCauseDetails = false; + } + + public UncheckedException(final String message, final Throwable t) { + super(message, t); + cause = t; + this.showCauseDetails = true; + } + + public UncheckedException(final String message, final Throwable t, final boolean showCauseDetails) { + super(message, t); + cause = t; + this.showCauseDetails = showCauseDetails; + } + + // ---------------------------------------------------------------- stack trace + + @Override + public void printStackTrace() { + printStackTrace(System.err); + } + + @Override + public void printStackTrace(final PrintStream ps) { + synchronized (ps) { + super.printStackTrace(ps); + if ((cause != null) && showCauseDetails) { + Throwable rootCause = ExceptionUtil.getRootCause(cause); + ps.println(CAUSE_DIV); + rootCause.printStackTrace(ps); + } + } + } + + @Override + public void printStackTrace(final PrintWriter pw) { + synchronized (pw) { + super.printStackTrace(pw); + if ((cause != null) && showCauseDetails) { + Throwable rootCause = ExceptionUtil.getRootCause(cause); + pw.println(CAUSE_DIV); + rootCause.printStackTrace(pw); + } + } + } + + // ---------------------------------------------------------------- txt + + /** + * Returns the detail message, including the message from the nested exception if there is one. + */ + @Override + public String getMessage() { + return ExceptionUtil.buildMessage(super.getMessage(), cause); + } + + // ---------------------------------------------------------------- wrap + + /** + * Wraps checked exceptions in a UncheckedException. + * Unchecked exceptions are not wrapped. + */ + public static V callAndWrapException(final Callable callable) { + try { + return callable.call(); + } + catch (IOException ioex) { + throw new UncheckedIOException(ioex); + } + catch (RuntimeException rtex) { + throw rtex; + } + catch (Exception t) { + throw new UncheckedException(t); + } + } + + @FunctionalInterface + public interface CallableVoid { + public void call() throws Exception; + } + + /** + * Wraps checked exceptions in a UncheckedException. + * Unchecked exceptions are not wrapped. + */ + public static void runAndWrapException(final CallableVoid callable) { + try { + callable.call(); + } + catch (IOException ioex) { + throw new UncheckedIOException(ioex); + } + catch (RuntimeException rtex) { + throw rtex; + } + catch (Exception t) { + throw new UncheckedException(t); + } + } + + /** + * Wraps all exceptions in a UncheckedException + */ + public static RuntimeException wrap(final Throwable t) { + return new UncheckedException(t); + } + + /** + * Wraps all exceptions in a UncheckedException + */ + public static RuntimeException wrap(final Throwable t, final String message) { + return new UncheckedException(message, t); + } + + + // ---------------------------------------------------------------- cause + + /** + * Re-throws cause if exists. + */ + public void rethrow() throws Throwable { + if (cause == null) { + return; + } + throw cause; + } + + /** + * Returns exception cause. + */ + @Override + public Throwable getCause() { + return cause; + } + + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/io/CharArraySequence.java b/common-util/src/main/java/com/vonchange/common/util/io/CharArraySequence.java new file mode 100644 index 0000000000000000000000000000000000000000..7fce2989066dbf2901e437b436b6d696a860b9da --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/io/CharArraySequence.java @@ -0,0 +1,115 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.io; + +/** + * Simple {@code CharSequence} wrapper of the char array. + * For {@code Appendable} version use + */ +public class CharArraySequence implements CharSequence { + + public static final CharSequence EMPTY = CharArraySequence.of(); + + private final char[] buffer; + private final int off, len; + + /** + * Static constructor that creates a char sequence using provided char array. + */ + public static CharArraySequence of(final char... value) { + return new CharArraySequence(value); + } + + public static CharArraySequence of(final char[] value, final int offset, final int len) { + return new CharArraySequence(value, offset, len); + } + + /** + * Static constructor that creates a char sequence by making a copy of provided char array. + */ + public static CharArraySequence from(final char[] value, final int offset, final int len) { + final char[] buffer = new char[value.length]; + + System.arraycopy(value, offset, buffer, 0, len); + + return new CharArraySequence(buffer); + } + + public CharArraySequence(final char[] value) { + buffer = value; + off = 0; + len = value.length; + } + + public CharArraySequence(final char[] value, final int offset, final int length) { + if ((offset | length | offset + length | value.length - offset - length) < 0) { + throw new IndexOutOfBoundsException(); + } + buffer = value; + off = offset; + len = length; + } + + /** + * Ctor without the bounds check. + */ + private CharArraySequence(final int offset, final int length, final char[] value) { + off = offset; + len = length; + buffer = value; + } + + @Override + public int length() { return len; } + + @Override + public String toString() { return String.valueOf(buffer, off, len); } + + @Override + public char charAt(final int index) { + //if ((index | len - index - 1) < 0) { + if (index < 0) { + throw new IndexOutOfBoundsException(); + } + return buffer[off + index]; + } + + @Override + public CharSequence subSequence(final int start, final int end) { + final int count = end - start; + final int rem = len - end; + + if ((start | end | count | rem) < 0) { + throw new IndexOutOfBoundsException(); + } + if ((start | rem) == 0) { + return this; + } + + return new CharArraySequence(off + start, count, buffer); + } + +} diff --git a/common-util/src/main/java/com/vonchange/common/util/io/FastCharArrayWriter.java b/common-util/src/main/java/com/vonchange/common/util/io/FastCharArrayWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..3083bfed47c110e85fb259cf2de6d0868fb69755 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/io/FastCharArrayWriter.java @@ -0,0 +1,132 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.io; + +import java.io.CharArrayWriter; +import java.io.IOException; +import java.io.Writer; + +/** + * Similar to but for {@link Writer}. + */ +public class FastCharArrayWriter extends Writer { + + private final FastCharBuffer buffer; + + /** + * Creates a new writer. The buffer capacity is + * initially 1024 bytes, though its size increases if necessary. + */ + public FastCharArrayWriter() { + this(1024); + } + + /** + * Creates a new char array {@link Writer}, with a buffer capacity of + * the specified size, in bytes. + * + * @param size the initial size. + * @throws IllegalArgumentException if size is negative. + */ + public FastCharArrayWriter(final int size) { + buffer = new FastCharBuffer(size); + } + + /** + * @see Writer#write(char[], int, int) + */ + @Override + public void write(final char[] b, final int off, final int len) { + buffer.append(b, off, len); + } + + /** + * Writes single byte. + */ + @Override + public void write(final int b) { + buffer.append((char) b); + } + + @Override + public void write(final String s, final int off, final int len) { + write(s.toCharArray(), off, len); + } + + /** + * @see CharArrayWriter#size() + */ + public int size() { + return buffer.size(); + } + + /** + * Closing a {@link FastCharArrayWriter} has no effect. The methods in + * this class can be called after the stream has been closed without + * generating an {@link IOException}. + */ + @Override + public void close() { + //nop + } + + /** + * Flushing a {@link FastCharArrayWriter} has no effects. + */ + @Override + public void flush() { + //nop + } + + /** + * @see CharArrayWriter#reset() + */ + public void reset() { + buffer.clear(); + } + + /** + * @see CharArrayWriter#writeTo(Writer) + */ + public void writeTo(final Writer out) throws IOException { + out.write(buffer.toArray()); + } + + /** + * @see CharArrayWriter#toCharArray() + */ + public char[] toCharArray() { + return buffer.toArray(); + } + + /** + * @see CharArrayWriter#toString() + */ + @Override + public String toString() { + return new String(toCharArray()); + } +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/io/FastCharBuffer.java b/common-util/src/main/java/com/vonchange/common/util/io/FastCharBuffer.java new file mode 100644 index 0000000000000000000000000000000000000000..28b7ef040e92b09636a30a0d44baa29eb621035f --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/io/FastCharBuffer.java @@ -0,0 +1,209 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.io; + +import java.util.Arrays; + +/** + * Faster {@code char} buffer. + */ +public class FastCharBuffer implements CharSequence, Appendable { + + private char[] buffer; + private int offset; + + /** + * Creates a new {@code char} buffer. The buffer capacity is + * initially 64 chars, though its size increases if necessary. + */ + public FastCharBuffer() { + this.buffer = new char[64]; + } + + /** + * Creates a new {@code char} buffer, with a buffer capacity of + * the specified size, in chars. + * + * @param size the initial size. + * @throws IllegalArgumentException if size is negative. + */ + public FastCharBuffer(final int size) { + this.buffer = new char[size]; + } + + /** + * Grows the buffer. + */ + private void grow(final int minCapacity) { + final int oldCapacity = buffer.length; + int newCapacity = oldCapacity << 1; + if (newCapacity - minCapacity < 0) { + // special case, min capacity is larger then a grow + newCapacity = minCapacity + 512; + } + buffer = Arrays.copyOf(buffer, newCapacity); + } + + /** + * Appends single {@code char} to buffer. + */ + @Override + public FastCharBuffer append(final char element) { + if (offset - buffer.length >= 0) { + grow(offset); + } + + buffer[offset++] = element; + return this; + } + + /** + * Appends {@code char} array to buffer. + */ + public FastCharBuffer append(final char[] array, final int off, final int len) { + if (offset + len - buffer.length > 0) { + grow(offset + len); + } + + System.arraycopy(array, off, buffer, offset, len); + offset += len; + return this; + } + + /** + * Appends {@code char} array to buffer. + */ + public FastCharBuffer append(final char[] array) { + return append(array, 0, array.length); + } + + /** + * Appends another fast buffer to this one. + */ + public FastCharBuffer append(final FastCharBuffer buff) { + if (buff.offset == 0) { + return this; + } + append(buff.buffer, 0, buff.offset); + return this; + } + + /** + * Returns buffer size. + */ + public int size() { + return offset; + } + + @Override + public int length() { + return offset; + } + + /** + * Tests if this buffer has no elements. + */ + public boolean isEmpty() { + return offset == 0; + } + + /** + * Resets the buffer content. + */ + public void clear() { + offset = 0; + } + + /** + * Creates {@code char} array from buffered content. + */ + public char[] toArray() { + return Arrays.copyOf(buffer, offset); + } + + /** + * Creates {@code char} subarray from buffered content. + */ + public char[] toArray(final int start, final int len) { + final char[] array = new char[len]; + + if (len == 0) { + return array; + } + + System.arraycopy(buffer, start, array, 0, len); + + return array; + } + + /** + * Returns {@code char} element at given index. + */ + public char get(final int index) { + if (index >= offset) { + throw new IndexOutOfBoundsException(); + } + return buffer[index]; + } + + /** + * Appends character sequence to buffer. + */ + @Override + public FastCharBuffer append(final CharSequence csq) { + append(csq, 0, csq.length()); + return this; + } + + /** + * Appends character sequence to buffer. + */ + @Override + public FastCharBuffer append(final CharSequence csq, final int start, final int end) { + for (int i = start; i < end; i++) { + append(csq.charAt(i)); + } + return this; + } + @Override + public char charAt(final int index) { + return get(index); + } + + @Override + public CharSequence subSequence(final int start, final int end) { + return new CharArraySequence(buffer, start, end - start); + } + + /** + * Returns a String of the char buffer. + * Please use {@code StringBuilder} instead, it is faster. + */ + @Override + public String toString() { + return new String(toArray()); + } +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/io/UnicodeInputStream.java b/common-util/src/main/java/com/vonchange/common/util/io/UnicodeInputStream.java new file mode 100644 index 0000000000000000000000000000000000000000..d1cfecd7cb22ee9abc397d9d272499839628a4d2 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/io/UnicodeInputStream.java @@ -0,0 +1,200 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.io; + +import java.io.IOException; +import java.io.InputStream; +import java.io.PushbackInputStream; + +/** + * Unicode input stream for detecting UTF encodings and reading BOM characters. + * Detects following BOMs: + *

    + *
  • UTF-8
  • + *
  • UTF-16BE
  • + *
  • UTF-16LE
  • + *
  • UTF-32BE
  • + *
  • UTF-32LE
  • + *
+ */ +public class UnicodeInputStream extends InputStream { + + public static final int MAX_BOM_SIZE = 4; + + private final PushbackInputStream internalInputStream; + private boolean initialized; + private int BOMSize = -1; + private String encoding; + private final String targetEncoding; + + /** + * Creates new unicode stream. It works in two modes: detect mode and read mode. + *

+ * Detect mode is active when target encoding is not specified. + * In detect mode, it tries to detect encoding from BOM if exist. + * If BOM doesn't exist, encoding is not detected. + *

+ * Read mode is active when target encoding is set. Then this stream reads + * optional BOM for given encoding. If BOM doesn't exist, nothing is skipped. + */ + public UnicodeInputStream(final InputStream in, final String targetEncoding) { + internalInputStream = new PushbackInputStream(in, MAX_BOM_SIZE); + this.targetEncoding = targetEncoding; + } + + /** + * Returns detected UTF encoding or {@code null} if no UTF encoding has been detected (i.e. no BOM). + * If stream is not read yet, it will be {@link #init() initalized} first. + */ + public String getDetectedEncoding() { + if (!initialized) { + try { + init(); + } catch (IOException ioex) { + throw new IllegalStateException(ioex); + } + } + return encoding; + } + + public static final byte[] BOM_UTF32_BE = new byte[]{(byte) 0x00, (byte) 0x00, (byte) 0xFE, (byte) 0xFF}; + public static final byte[] BOM_UTF32_LE = new byte[]{(byte) 0xFF, (byte) 0xFE, (byte) 0x00, (byte) 0x00}; + public static final byte[] BOM_UTF8 = new byte[]{(byte) 0xEF, (byte) 0xBB, (byte) 0xBF}; + public static final byte[] BOM_UTF16_BE = new byte[]{(byte) 0xFE, (byte) 0xFF}; + public static final byte[] BOM_UTF16_LE = new byte[]{(byte) 0xFF, (byte) 0xFE}; + + /** + * Detects and decodes encoding from BOM character. + * Reads ahead four bytes and check for BOM marks. + * Extra bytes are unread back to the stream, so only + * BOM bytes are skipped. + */ + protected void init() throws IOException { + if (initialized) { + return; + } + + if (targetEncoding == null) { + + // DETECT MODE + + byte[] bom = new byte[MAX_BOM_SIZE]; + int n = internalInputStream.read(bom, 0, bom.length); + int unread; + + if ((bom[0] == BOM_UTF32_BE[0]) && (bom[1] == BOM_UTF32_BE[1]) && (bom[2] == BOM_UTF32_BE[2]) && (bom[3] == BOM_UTF32_BE[3])) { + encoding = "UTF-32BE"; + unread = n - 4; + } else if ((bom[0] == BOM_UTF32_LE[0]) && (bom[1] == BOM_UTF32_LE[1]) && (bom[2] == BOM_UTF32_LE[2]) && (bom[3] == BOM_UTF32_LE[3])) { + encoding = "UTF-32LE"; + unread = n - 4; + } else if ((bom[0] == BOM_UTF8[0]) && (bom[1] == BOM_UTF8[1]) && (bom[2] == BOM_UTF8[2])) { + encoding = "UTF-8"; + unread = n - 3; + } else if ((bom[0] == BOM_UTF16_BE[0]) && (bom[1] == BOM_UTF16_BE[1])) { + encoding = "UTF-16BE"; + unread = n - 2; + } else if ((bom[0] == BOM_UTF16_LE[0]) && (bom[1] == BOM_UTF16_LE[1])) { + encoding = "UTF-16LE"; + unread = n - 2; + } else { + // BOM not found, unread all bytes + unread = n; + } + + BOMSize = MAX_BOM_SIZE - unread; + + if (unread > 0) { + internalInputStream.unread(bom, (n - unread), unread); + } + } else { + + // READ MODE + + byte[] bom = null; + + if (targetEncoding.equals("UTF-8")) { + bom = BOM_UTF8; + } else if (targetEncoding.equals("UTF-16LE")) { + bom = BOM_UTF16_LE; + } else if (targetEncoding.equals("UTF-16BE") || targetEncoding.equals("UTF-16")) { + bom = BOM_UTF16_BE; + } else if (targetEncoding.equals("UTF-32LE")) { + bom = BOM_UTF32_LE; + } else if (targetEncoding.equals("UTF-32BE") || targetEncoding.equals("UTF-32")) { + bom = BOM_UTF32_BE; + } else { + // no UTF encoding, no BOM + } + + if (bom != null) { + byte[] fileBom = new byte[bom.length]; + int n = internalInputStream.read(fileBom, 0, bom.length); + + boolean bomDetected = true; + for (int i = 0; i < n; i++) { + if (fileBom[i] != bom[i]) { + bomDetected = false; + break; + } + } + + if (!bomDetected) { + internalInputStream.unread(fileBom, 0, fileBom.length); + } + } + } + + initialized = true; + } + + /** + * Closes input stream. If stream was not used, encoding + * will be unavailable. + */ + @Override + public void close() throws IOException { + internalInputStream.close(); + } + + /** + * Reads byte from the stream. + */ + @Override + public int read() throws IOException { + init(); + return internalInputStream.read(); + } + + /** + * Returns BOM size in bytes. + * Returns -1 if BOM not found. + */ + public int getBOMSize() { + return BOMSize; + } + +} \ No newline at end of file diff --git a/common-util/src/main/java/com/vonchange/common/util/map/HashMap.java b/common-util/src/main/java/com/vonchange/common/util/map/HashMap.java new file mode 100644 index 0000000000000000000000000000000000000000..b3f8b0cf25fed3b6dc53d6d8c446b27608fa6e38 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/map/HashMap.java @@ -0,0 +1,27 @@ +package com.vonchange.common.util.map; + +import java.util.Map; + +/** + *支持链式调用的HashMap + * @author von_change@163.com + * 2015-6-14 下午10:37:59 + * @param + * @param + */ +public class HashMap extends java.util.HashMap implements Map { + + + public HashMap() { + super(); + } + + public HashMap(Map map) { + super(map); + } + + public HashMap set(K key, V value) { + super.put(key, value); + return this; + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/map/MyHashMap.java b/common-util/src/main/java/com/vonchange/common/util/map/MyHashMap.java new file mode 100644 index 0000000000000000000000000000000000000000..27c1a5b74e81d44b81e1474cd5c80860ad96d5b2 --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/map/MyHashMap.java @@ -0,0 +1,36 @@ +package com.vonchange.common.util.map; + +import java.util.Map; + + +/** + *支持链式调用的HashMap + * @author vonchange@163.com + */ +public class MyHashMap extends HashMap implements Map{ + + + public MyHashMap() { + } + + public MyHashMap(Map map) { + if (null == map) { + map = new MyHashMap(); + } + for (Entry entry : map.entrySet()) { + this.set(entry.getKey(), entry.getValue()); + } + } + @Override + public MyHashMap set(String key, Object value) { + super.put(key, value); + return this; + } + public MyHashMap setAll(Map map) { + super.putAll(map); + return this; + } + public MyHashMap put(String key, Object value) { + return this.set(key, value); + } +} diff --git a/common-util/src/main/java/com/vonchange/common/util/time/TimeUtil.java b/common-util/src/main/java/com/vonchange/common/util/time/TimeUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..5ded0983229325218eadb335e6162094b659f93d --- /dev/null +++ b/common-util/src/main/java/com/vonchange/common/util/time/TimeUtil.java @@ -0,0 +1,132 @@ +// Copyright (c) 2003-present, Jodd Team (http://jodd.org) +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// 1. Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. + +package com.vonchange.common.util.time; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; +import java.time.ZonedDateTime; +import java.util.Calendar; +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.Locale; +import java.util.TimeZone; + +public class TimeUtil { + + public static final int SECONDS_IN_DAY = 60 * 60 * 24; + public static final long MILLIS_IN_DAY = 1000L * SECONDS_IN_DAY; + + public static final SimpleDateFormat HTTP_DATE_FORMAT = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US); + + /** + * Converts local date to Date. + */ + public static Date toDate(final LocalDate localDate) { + return Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant()); + } + /** + * Converts local date time to Date. + */ + public static Date toDate(final LocalDateTime localDateTime) { + return Date.from(localDateTime.atZone(ZoneId.systemDefault()).toInstant()); + } + + /** + * Converts local date time to Calendar. + */ + public static Calendar toCalendar(final LocalDateTime localDateTime) { + return GregorianCalendar.from(ZonedDateTime.of(localDateTime, ZoneId.systemDefault())); + } + + /** + * Converts local date time to Calendar and setting time to midnight. + */ + public static Calendar toCalendar(final LocalDate localDate) { + return GregorianCalendar.from(ZonedDateTime.of(localDate, LocalTime.MIDNIGHT, ZoneId.systemDefault())); + } + + /** + * Converts local date time to epoh milliseconds. + */ + public static long toMilliseconds(final LocalDateTime localDateTime) { + return localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(); + } + + /** + * Converts local date time to epoh milliseconds assuming start of the day as time point. + */ + public static long toMilliseconds(final LocalDate localDate) { + return toMilliseconds(localDate.atStartOfDay()); + } + + + public static LocalDateTime fromCalendar(final Calendar calendar) { + final TimeZone tz = calendar.getTimeZone(); + final ZoneId zid = tz == null ? ZoneId.systemDefault() : tz.toZoneId(); + return LocalDateTime.ofInstant(calendar.toInstant(), zid); + } + + public static LocalDateTime fromDate(final Date date) { + return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault()); + } + + public static LocalDateTime fromMilliseconds(final long milliseconds) { + return LocalDateTime.ofInstant(Instant.ofEpochMilli(milliseconds), ZoneId.systemDefault()); + } + + + /** + * Formats time to HTTP date/time format. Note that number of milliseconds + * is lost. + */ + public static String formatHttpDate(final long millis) { + final Date date = new Date(millis); + return HTTP_DATE_FORMAT.format(date); + } + + /** + * Parses the HTTP date/time format. Returns -1 if given string + * is invalid. + */ + public static long parseHttpTime(final String time) { + if (time == null) { + return -1; + } + + try { + return TimeUtil.HTTP_DATE_FORMAT.parse(time).getTime(); + } + catch (ParseException e) { + return -1; + } + } + +} diff --git a/mybatis-mini/pom.xml b/mybatis-mini/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..98478183f31e5931dce2a500b9cc58a264c01310 --- /dev/null +++ b/mybatis-mini/pom.xml @@ -0,0 +1,40 @@ + + + + mybatis-mini-parant + com.vonchange.common + 2.3.9 + + 4.0.0 + mybatis-mini + 2.3.9 + + + com.vonchange.common + mybatis-template + 2.3.9 + + + com.vonchange.common + jsqlparser + 1.1 + + + + org.springframework.data + spring-data-commons + 2.1.5.RELEASE + provided + + + org.springframework + spring-jdbc + 5.1.5.RELEASE + provided + + + + + \ No newline at end of file diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/config/ConstantJdbc.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/config/ConstantJdbc.java new file mode 100644 index 0000000000000000000000000000000000000000..3d0ceecade7dfc560bc499b59678da54412a6f83 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/config/ConstantJdbc.java @@ -0,0 +1,24 @@ +package com.vonchange.jdbc.abstractjdbc.config; + +/** + * Created by 冯昌义 on 2018/3/20. + */ +public class ConstantJdbc { + private ConstantJdbc() { throw new IllegalStateException("Utility class");} + public static class PageParam{ + public static final String COUNT = "_count"; + public static final String AT = "@"; + } + public static final String ISSQLFLAG= "@sql"; + public static final String ISMDFLAG= "@md"; + public static final String MAINFLAG= "main"; + public static final String MDID= "### id"; + public static final String MDVERSION= "#### version"; + public static final String MDINITVERSION= "1.0"; + public static class DataSource{ + public static final String DEFAULT = "dataSource"; + public static final String FLAG = "@ds:"; + } + public static final String COUNTFLAG = "Count"; + public static final String MAPFIELDSPLIT = "#"; +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/config/Constants.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/config/Constants.java new file mode 100644 index 0000000000000000000000000000000000000000..257e62cf900b492571312f9523a72034df91839d --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/config/Constants.java @@ -0,0 +1,53 @@ +package com.vonchange.jdbc.abstractjdbc.config; + + +/** + * 数据字典 + * @author song.chen + * + */ +public class Constants { + private Constants() { throw new IllegalStateException("Utility class");} + /** + * mardown 配置里的信息 + */ + public static class Markdown{ + public static final String TABLES = "tables"; + public static final String IDPREF = "--"; + } + public enum EnumRWType { + read(0,"读"),write(0,"写"); + private Integer value; + private String desc; + EnumRWType(Integer value, String desc){ + this.value=value; + this.desc=desc; + } + public static EnumRWType getValue(Integer value) { + for (EnumRWType c : EnumRWType.values()) { + if (c.getValue().equals(value)) { + return c; + } + } + return null; + } + public Integer getValue() { + return value; + } + + public EnumRWType setValue(int value) { + this.value = value; + return this; + + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/core/AbstractJdbcCore.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/core/AbstractJdbcCore.java new file mode 100644 index 0000000000000000000000000000000000000000..c656adfef4509e45f77ca9f804f3ab1366bdc8d2 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/core/AbstractJdbcCore.java @@ -0,0 +1,847 @@ +package com.vonchange.jdbc.abstractjdbc.core; + + +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.jdbc.abstractjdbc.config.ConstantJdbc; +import com.vonchange.jdbc.abstractjdbc.config.Constants; +import com.vonchange.jdbc.abstractjdbc.count.CountSqlParser; +import com.vonchange.jdbc.abstractjdbc.handler.AbstractMapPageWork; +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import com.vonchange.jdbc.abstractjdbc.handler.BeanHandler; +import com.vonchange.jdbc.abstractjdbc.handler.BeanInsertHandler; +import com.vonchange.jdbc.abstractjdbc.handler.BeanListHandler; +import com.vonchange.jdbc.abstractjdbc.handler.BigDataBeanListHandler; +import com.vonchange.jdbc.abstractjdbc.handler.BigDataMapListHandler; +import com.vonchange.jdbc.abstractjdbc.handler.MapBeanListHandler; +import com.vonchange.jdbc.abstractjdbc.handler.MapHandler; +import com.vonchange.jdbc.abstractjdbc.handler.MapListHandler; +import com.vonchange.jdbc.abstractjdbc.handler.ScalarHandler; +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import com.vonchange.jdbc.abstractjdbc.model.EntityCu; +import com.vonchange.jdbc.abstractjdbc.model.EntityInsertResult; +import com.vonchange.jdbc.abstractjdbc.model.EntityUpdateResult; +import com.vonchange.jdbc.abstractjdbc.template.MyJdbcTemplate; +import com.vonchange.jdbc.abstractjdbc.util.ConvertMap; +import com.vonchange.jdbc.abstractjdbc.util.markdown.MarkdownUtil; +import com.vonchange.jdbc.abstractjdbc.util.markdown.bean.SqlInfo; +import com.vonchange.jdbc.abstractjdbc.util.sql.SqlFill; +import com.vonchange.mybatis.config.Constant; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; +import com.vonchange.mybatis.tpl.EntityUtil; +import com.vonchange.mybatis.tpl.MybatisTpl; +import com.vonchange.mybatis.tpl.model.EntityField; +import com.vonchange.mybatis.tpl.model.EntityInfo; +import com.vonchange.mybatis.tpl.model.SqlWithParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.Pageable; + +import java.beans.IntrospectionException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * jdbc core + * by von_change + */ +public abstract class AbstractJdbcCore implements JdbcRepository { + + private static final Logger log = LoggerFactory.getLogger(AbstractJdbcCore.class); + + protected abstract Dialect getDefaultDialect(); + + protected abstract DataSourceWrapper getWriteDataSource(); + + + protected abstract boolean readAllScopeOpen(); + + protected abstract int batchSize(); + + + protected abstract DataSourceWrapper getDataSourceFromSql(String sql); + protected abstract boolean logRead(); + protected abstract boolean logWrite(); + protected abstract boolean logFullSql(); + protected abstract boolean needReadMdLastModified(); + + private Dialect dialect = null; + private Dialect getDialect(DataSourceWrapper dataSourceWrapper){ + if(null!=dataSourceWrapper&&null!=dataSourceWrapper.getDialect()){ + return dataSourceWrapper.getDialect(); + } + if (null == dialect) { + dialect = getDefaultDialect(); + } + return dialect; + } + private MyJdbcTemplate initJdbcTemplate(DataSourceWrapper dataSourceWrapper, Constants.EnumRWType enumRWType, String sql) { + return getJdbcTemplate(dataSourceWrapper, enumRWType, sql); + } + + private static Map yhJdbcTemplateMap = new ConcurrentHashMap<>(); + + private DataSourceWrapper getDataSourceWrapper(DataSourceWrapper dataSourceWrapper, Constants.EnumRWType enumRWType, + String sql) { + if (null != dataSourceWrapper) { + return dataSourceWrapper; + } + //from sql get datasource + DataSourceWrapper dataSourceFromSql = getDataSourceFromSql(sql); + if (null != dataSourceFromSql) { + return dataSourceFromSql; + } + //去除 直接读随机数据源 主从有延迟 还是需要根据业务指定数据源 + if (enumRWType.equals(Constants.EnumRWType.read) && readAllScopeOpen()) { + return getReadDataSource(); + } + return getWriteDataSource(); + } + + private MyJdbcTemplate getJdbcTemplate(DataSourceWrapper dataSourceWrapper, Constants.EnumRWType enumRWType, String sql) { + DataSourceWrapper dataSource = getDataSourceWrapper(dataSourceWrapper, enumRWType, sql); + log.debug("\n====== use dataSource key {}", dataSource.getKey()); + if (yhJdbcTemplateMap.containsKey(dataSource.getKey())) { + return yhJdbcTemplateMap.get(dataSource.getKey()); + } + MyJdbcTemplate myJdbcTemplate = new MyJdbcTemplate(dataSource.getDataSource()); + myJdbcTemplate.setFetchSizeBigData(getDialect(dataSource).getBigDataFetchSize()); + myJdbcTemplate.setFetchSize(getDialect(dataSource).getFetchSize()); + yhJdbcTemplateMap.put(dataSource.getKey(), myJdbcTemplate); + return myJdbcTemplate; + } + + public final int insertBatch(List entityList,int batchSize) { + return insertBatch(null, entityList,batchSize); + } + + public final int insertBatch(DataSourceWrapper dataSourceWrapper, List entityList,int batchSize) { + return insertBatch(dataSourceWrapper, entityList, false,batchSize); + } + + public final int insertBatchDuplicateKey(List entityList,int batchSize) { + return insertBatchDuplicateKey(null, entityList,batchSize); + } + + public final int insertBatchDuplicateKey(DataSourceWrapper dataSourceWrapper, List entityList,int batchSize) { + return insertBatch(dataSourceWrapper, entityList, true,batchSize); + } + public final int updateBatch( List entityList, int batchSize) { + return updateBatch(entityList,batchSize); + } + public final int updateBatch(DataSourceWrapper dataSourceWrapper, List entityList, int batchSize) { + if (null == entityList || entityList.isEmpty()) { + return 0; + } + SqlWithParam sqlParmeter = generateUpdateEntitySql(entityList.get(0), false); + String sql = sqlParmeter.getSql(); + List list = new ArrayList<>(); + int i = 0; + if(batchSize<=0){ + batchSize=batchSize(); + } + List> listSplit = new ArrayList<>(); + for (T t : entityList) { + if (i != 0 && i % batchSize == 0) { + listSplit.add(list); + list = new ArrayList<>(); + } + SqlWithParam sqlParameterItem = generateUpdateEntitySql(t, false); + list.add(sqlParameterItem.getParams()); + i++; + } + if (!list.isEmpty()) { + listSplit.add(list); + } + int num=0; + for (List item : listSplit) { + int[] result = updateBatch(dataSourceWrapper, sql, item); + num+=result.length; + log.debug("\nupdateBatch {}", result); + } + return num; + } + private int insertBatch(DataSourceWrapper dataSourceWrapper, List entityList, boolean duplicate,int batchSize) { + if (null == entityList || entityList.isEmpty()) { + return 0; + } + SqlWithParam sqlParmeter = generateInsertSql(entityList.get(0), duplicate); + String sql = sqlParmeter.getSql(); + List list = new ArrayList<>(); + int i = 0; + if(batchSize<=0){ + batchSize=batchSize(); + } + List> listSplit = new ArrayList<>(); + for (T t : entityList) { + if (i != 0 && i % batchSize == 0) { + listSplit.add(list); + list = new ArrayList<>(); + } + SqlWithParam sqlParameterItem = generateInsertSql(t, duplicate); + list.add(sqlParameterItem.getParams()); + i++; + } + if (!list.isEmpty()) { + listSplit.add(list); + } + int num=0; + for (List item : listSplit) { + int[] result = updateBatch(dataSourceWrapper, sql, item); + num+=result.length; + log.debug("\ninsertBatch {}", result); + } + return num; + } + + public final int insert(DataSourceWrapper dataSourceWrapper, T entity) { + SqlWithParam sqlParmeter = generateInsertSql(entity, false); + return insert(dataSourceWrapper,entity, sqlParmeter.getSql(),sqlParmeter.getColumnReturns(), sqlParmeter.getParams()); + } + + public final int insert(T entity) { + return insert(null, entity); + } + + + public final int update(DataSourceWrapper dataSourceWrapper, T entity) { + SqlWithParam sqlParmeter = generateUpdateEntitySql(entity, false); + return update(dataSourceWrapper, sqlParmeter.getSql(), sqlParmeter.getParams()); + } + + public final int update(T entity) { + return update(null, entity); + } + + public final int updateAllField(DataSourceWrapper dataSourceWrapper, T entity) { + SqlWithParam sqlParmeter = generateUpdateEntitySql(entity, true); + return update(dataSourceWrapper, sqlParmeter.getSql(), sqlParmeter.getParams()); + } + + public final int updateAllField(T entity) { + return updateAllField(null, entity); + } + + public final int insertDuplicateKey(T entity) { + return insertDuplicateKey(null, entity); + } + + public final int insertDuplicateKey(DataSourceWrapper dataSourceWrapper, T entity) { + SqlWithParam sqlParmeter = generateInsertSql(entity, true); + return insert(dataSourceWrapper, entity,sqlParmeter.getSql(),sqlParmeter.getColumnReturns(), sqlParmeter.getParams()); + } + + private void initEntityInfo(Class clazz) { + EntityUtil.initEntityInfo(clazz); + } + + private static Object getPublicPro(Object bean, String name) { + if (name.equals("serialVersionUID")) {//?????? + return null; + } + return Constant.BeanUtil.getProperty(bean, name); + } + + //private String + private SqlWithParam generateInsertSql(T entity, boolean duplicate) { + initEntityInfo(entity.getClass()); + SqlWithParam sqlParmeter = new SqlWithParam(); + List entityCuArrayList = new ArrayList<>(); + EntityInfo entityInfo = EntityUtil.getEntityInfo(entity.getClass()); + String tableName = entityInfo.getTableName(); + Map entityFieldMap = entityInfo.getFieldMap(); + for (Map.Entry entry : entityFieldMap.entrySet()) { + String fieldName = entry.getKey(); + EntityField entityField = entry.getValue(); + if (Boolean.TRUE.equals(entityField.getIsColumn())) { + Object value = getPublicPro(entity, fieldName); + if(null!=value&&value.getClass().isEnum()){ + value=value.toString(); + } + entityCuArrayList.add(new EntityCu(entityField, value, duplicate, false)); + } + } + workInsertItem(entityCuArrayList); + EntityInsertResult entityInsertResult = getInsertValueSql(entityCuArrayList); + String insertSql = StringUtils.format("insert into {0}({1}) values ({2})", tableName, entityInsertResult.getKeySql(), entityInsertResult.getValueSql()); + if (duplicate) { + insertSql = insertSql + " ON DUPLICATE KEY UPDATE " + entityInsertResult.getUpdateStr(); + } + sqlParmeter.setColumnReturns(entityInfo.getColumnReturns()); + sqlParmeter.setSql(insertSql); + sqlParmeter.setParams(entityInsertResult.getValueList().toArray()); + return sqlParmeter; + } + + private String updateIfNullValue(EntityCu entityCu, boolean nullUpdate) { + EntityField entityField = entityCu.getEntityField(); + entityCu.setUpdateValueColumn(true); + entityCu.setUpdateValueParam(true); + if (StringUtils.isNotBlank(entityField.getUpdateIfNullFunc())) { + entityCu.setUpdateValueParam(false); + return entityField.getUpdateIfNullFunc(); + } + if (StringUtils.isNotBlank(entityField.getUpdateIfNull())) { + entityCu.setUpdateValueParam(false); + return "'" + entityField.getUpdateIfNull() + "'"; + } + if (nullUpdate && Boolean.FALSE.equals(entityField.getUpdateNotNull())) { + return "?"; + } + if (null != entityCu.getValue()) { + return "?"; + } + entityCu.setUpdateValueParam(false); + entityCu.setUpdateValueColumn(false); + return null; + } + + private String insertIfNullValue(EntityCu entityCu) { + EntityField entityField = entityCu.getEntityField(); + entityCu.setInsertKeyColumn(true); + entityCu.setInsertValueParam(true); + if (StringUtils.isNotBlank(entityField.getInsertIfNullFunc())) { + entityCu.setInsertValueParam(false); + return entityField.getInsertIfNullFunc(); + } + if (StringUtils.isNotBlank(entityField.getInsertIfNull())) { + entityCu.setInsertValueParam(false); + return "'" + entityField.getInsertIfNull() + "'"; + } + if (null != entityCu.getValue()) { + return "?"; + } + entityCu.setInsertValueParam(false); + entityCu.setInsertKeyColumn(false); + return null; + } + + private void workInsertItem(List entityCuList) { + for (EntityCu entityCu : entityCuList) { + entityCu.setInsertIfNullValue(insertIfNullValue(entityCu)); + if (Boolean.TRUE.equals(entityCu.getDuplicate())) { + entityCu.setUpdateIfNullValue(updateIfNullValue(entityCu, false)); + } + } + } + + private EntityInsertResult getInsertValueSql(List entityCus) { + StringBuilder valueStr = new StringBuilder(); + StringBuilder keyStr = new StringBuilder(); + StringBuilder updateStr = new StringBuilder(" "); + List valueList = new ArrayList<>(); + List valueUpdateList = new ArrayList<>(); + for (EntityCu entityCu : entityCus) { + if (Boolean.TRUE.equals(entityCu.getInsertKeyColumn())) { + valueStr.append(entityCu.getInsertIfNullValue()).append(","); + keyStr.append("`").append(entityCu.getEntityField().getColumnName()).append("`").append(","); + } + if (Boolean.TRUE.equals(entityCu.getInsertValueParam())) { + valueList.add(entityCu.getValue()); + } + if (Boolean.TRUE.equals(entityCu.getDuplicate()) && Boolean.TRUE.equals(entityCu.getUpdateValueColumn()) && Boolean.FALSE.equals(entityCu.getEntityField().getIgnoreDupUpdate())) { + updateStr.append("`").append(entityCu.getEntityField().getColumnName()).append("`") + .append("=").append( entityCu.getUpdateIfNullValue()) + .append(","); + if (Boolean.TRUE.equals(entityCu.getUpdateValueParam())) { + valueUpdateList.add(entityCu.getValue()); + } + } + } + valueList.addAll(valueUpdateList); + return new EntityInsertResult(keyStr.substring(0, keyStr.length() - 1), + valueStr.substring(0, valueStr.length() - 1), updateStr.substring(0, updateStr.length() - 1), valueList); + } + + private SqlWithParam generateUpdateEntitySql(T entity, boolean isNullUpdate) { + SqlWithParam sqlParmeter = new SqlWithParam(); + initEntityInfo(entity.getClass()); + EntityInfo entityInfo = EntityUtil.getEntityInfo(entity.getClass()); + String tableName = entityInfo.getTableName(); + String idColumnName = entityInfo.getIdColumnName(); + if(null==idColumnName){ + throw new MybatisMinRuntimeException("need entity field @ID"); + } + Object idValue = getPublicPro(entity, entityInfo.getIdFieldName()); + if (null == idValue) { + throw new MybatisMinRuntimeException("ID value is null,can not update"); + } + List entityCuList = new ArrayList<>(); + Map entityFieldMap = entityInfo.getFieldMap(); + for (Map.Entry entry : entityFieldMap.entrySet()) { + EntityField entityField = entry.getValue(); + if (Boolean.TRUE.equals(entityField.getIsColumn()) && Boolean.FALSE.equals(entityField.getIsId())) { + Object value = getPublicPro(entity, entry.getKey()); + entityCuList.add(new EntityCu(entityField, value, false, isNullUpdate)); + } + } + workUpdateItem(entityCuList); + EntityUpdateResult entityUpdateResult = workUpdateSql(entityCuList); + List valueList = entityUpdateResult.getValueList(); + valueList.add(idValue); + //0:tableName 1:setSql 2:idName + String sql = StringUtils.format("update {0} set {1} where {2}=?", tableName, entityUpdateResult.getUpdateStr(), idColumnName); + sqlParmeter.setSql(sql); + sqlParmeter.setParams(valueList.toArray()); + return sqlParmeter; + } + + private void workUpdateItem(List entityCuList) { + for (EntityCu entityCu : entityCuList) { + entityCu.setUpdateIfNullValue(updateIfNullValue(entityCu, entityCu.getNullUpdate())); + } + } + + private EntityUpdateResult workUpdateSql(List entityCus) { + String item = "{0}"; + StringBuilder updateStr = new StringBuilder(); + List valueList = new ArrayList<>(); + for (EntityCu entityCu : entityCus) { + if (Boolean.TRUE.equals(entityCu.getUpdateValueColumn())) { + updateStr.append("`").append(entityCu.getEntityField().getColumnName()).append("`").append("=") + .append(StringUtils.format(item, entityCu.getUpdateIfNullValue())).append(","); + } + if (Boolean.TRUE.equals(entityCu.getUpdateValueParam())) { + valueList.add(entityCu.getValue()); + } + } + return new EntityUpdateResult(updateStr.substring(0, updateStr.length() - 1), valueList); + } + + //crud end + public final T queryById(DataSourceWrapper dataSourceWrapper, Class type, Object id) { + String sql = generateQueryByIdSql(type); + return queryOne(dataSourceWrapper, type, sql, id); + } + + public final T queryById(Class type, Object id) { + return queryById(null, type, id); + } + + private String generateQueryByIdSql(Class type) { + initEntityInfo(type); + EntityInfo entityInfo = EntityUtil.getEntityInfo(type); + Map fieldMap = entityInfo.getFieldMap(); + StringBuilder sb = new StringBuilder(); + for (Map.Entry entry:fieldMap.entrySet()) { + if(entry.getValue().getIsColumn()){ + sb.append(entry.getValue().getColumnName()).append(","); + } + } + String tableName = entityInfo.getTableName(); + String idName = entityInfo.getIdColumnName(); + return StringUtils.format("select {0} from {1} where {2} = ?", sb.substring(0,sb.length()-1),tableName, idName); + } + + public final List queryList(DataSourceWrapper dataSourceWrapper, Class type, String sqlId, Map parameter) { + SqlInfo sqlinfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlinfo.getSql(), parameter); + return queryList(dataSourceWrapper, type, sqlParmeter.getSql(), sqlParmeter.getParams()); + } + + public final List queryList(Class type, String sqlId, Map parameter) { + return queryList(null, type, sqlId, parameter); + } + + + public T queryOne(DataSourceWrapper dataSourceWrapper, Class type, String sqlId, Map parameter) { + SqlInfo sqlInfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlInfo.getSql(), parameter); + List list= queryList(dataSourceWrapper, type, sqlParmeter.getSql(), sqlParmeter.getParams()); + if(list.isEmpty()){ + return null; + } + if(list.size()>1){ + log.warn("{} expect one row but found {} rows",sqlId,list.size()); + } + return list.get(0); + } + + public T queryOne(Class type, String sqlId, Map parameter) { + return queryOne(null, type, sqlId, parameter); + } + + + public Map queryMapOne(DataSourceWrapper dataSourceWrapper, String sqlId, Map parameter) { + SqlInfo sqlinfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlinfo.getSql(), parameter); + List> list= queryListResultMap(dataSourceWrapper, sqlParmeter.getSql(), sqlParmeter.getParams()); + if(list.isEmpty()){ + return null; + } + if(list.size()>1){ + log.warn("{} expect one row but found {} rows",sqlId,list.size()); + } + return list.get(0); + } + + public Map queryMapOne(String sqlId, Map parameter) { + return queryMapOne(null, sqlId, parameter); + } + + public final List> queryMapList(DataSourceWrapper dataSourceWrapper, String sqlId, Map parameter) { + SqlInfo sqlInfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlInfo.getSql(), parameter); + return queryListResultMap(dataSourceWrapper, sqlParmeter.getSql(), sqlParmeter.getParams()); + } + + public final List> queryMapList(String sqlId, Map parameter) { + return queryMapList(null, sqlId, parameter); + } + + + public final void queryMapBigData(String sqlId, AbstractMapPageWork pageWork, Map parameter) { + queryMapBigData(null, sqlId, pageWork, parameter); + } + + public final void queryMapBigData(DataSourceWrapper dataSourceWrapper, String sqlId, AbstractMapPageWork pageWork, Map parameter) { + SqlInfo sqlInfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlInfo.getSql(), parameter); + queryForBigData(dataSourceWrapper, sqlParmeter.getSql(), pageWork, sqlParmeter.getParams()); + } + + public final void queryBigData(Class type, String sqlId, AbstractPageWork pageWork, Map parameter) { + queryBigData(null, type, sqlId, pageWork, parameter); + } + @SuppressWarnings("unchecked") + public final void queryBigData(DataSourceWrapper dataSourceWrapper, Class type, String sqlId, AbstractPageWork pageWork, Map parameter) { + SqlInfo sqlInfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlInfo.getSql(), parameter); + queryForBigData(dataSourceWrapper, type, sqlParmeter.getSql(), pageWork, sqlParmeter.getParams()); + } + + public final Page> queryMapPage(String sqlId, Pageable pageable, Map parameter) { + return queryMapPage(null, sqlId, pageable, parameter); + } + + public final Page> queryMapPage(DataSourceWrapper dataSourceWrapper, String sqlId, Pageable pageable, Map parameter) { + SqlInfo sqlInfo = getSqlInfo(sqlId,parameter); + SqlInfo countSqlInfo = getSqlInfo(sqlId + ConstantJdbc.COUNTFLAG,parameter); + String countSql = countSqlInfo.getSql(); + boolean hasCountSqlInMd = true; + if (StringUtils.isBlank(countSql)) { + countSql = null; + hasCountSqlInMd = false; + } + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlInfo.getSql(), parameter); + long totalCount = countMySqlResult(dataSourceWrapper, sqlInfo.getSql(), countSql, parameter); + String sql = sqlParmeter.getSql(); + int pageNum = pageable.getPageNumber() <= 0 ? 0 : pageable.getPageNumber(); + int firstEntityIndex = pageable.getPageSize() * pageNum; + boolean hasLimit = false; + if (hasCountSqlInMd) { + hasLimit = hasLimit(sql); + } + if (!hasCountSqlInMd || !hasLimit) { + sql = getDialect(dataSourceWrapper).getPageSql(sql, firstEntityIndex, pageable.getPageSize()); + } + List> entities = queryListResultMap(dataSourceWrapper, sql, sqlParmeter.getParams()); + return new PageImpl<>(entities, pageable, totalCount); + } + + public Page queryPage(Class type, String sqlId, Pageable pageable, Map parameter) { + return queryPage(null, type, sqlId, pageable, parameter); + } + + public Page queryPage(DataSourceWrapper dataSourceWrapper, Class type, String sqlId, Pageable pageable, Map parameter) { + SqlInfo sqlinfo = getSqlInfo(sqlId,parameter); + SqlInfo countSqlInfo = getSqlInfo(sqlId + ConstantJdbc.COUNTFLAG,parameter); + String countSql = countSqlInfo.getSql(); + boolean hasCountSqlInMd = true; + if (StringUtils.isBlank(countSqlInfo.getSql())) { + countSql = null; + hasCountSqlInMd = false; + } + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlinfo.getSql(), parameter); + long totalCount = countMySqlResult(dataSourceWrapper, sqlinfo.getSql(), countSql, parameter); + String sql = sqlParmeter.getSql(); + int pageNum = pageable.getPageNumber() <= 0 ? 0 : pageable.getPageNumber(); + int firstEntityIndex = pageable.getPageSize() * pageNum; + boolean hasLimit = false; + if (hasCountSqlInMd) { + hasLimit = hasLimit(sql); + } + if (!hasCountSqlInMd || !hasLimit) { + sql = getDialect(dataSourceWrapper).getPageSql(sql, firstEntityIndex, pageable.getPageSize()); + } + List entities = queryList(dataSourceWrapper, type, sql, sqlParmeter.getParams()); + return new PageImpl<>(entities, pageable, totalCount); + } + + private boolean hasLimit(String sql) { + String lowerSql = sql.toLowerCase(); + if (lowerSql.contains("limit ") || lowerSql.contains("limit\n")) { + return true; + } + return false; + } + + private long countMySqlResult(DataSourceWrapper dataSourceWrapper, String sql, String countSql, Map params) { + if (params.containsKey(ConstantJdbc.PageParam.COUNT)) { + countSql = ConvertUtil.toString(params.get(ConstantJdbc.PageParam.COUNT)); + } + //count num  _count = @123 + if (!StringUtils.isBlank(countSql) && countSql.startsWith(ConstantJdbc.PageParam.AT)) { + return ConvertUtil.toLong(countSql.substring(1)); + } + Object result = null; + + if (!StringUtils.isBlank(countSql)) { + result = findBy(dataSourceWrapper, countSql, params); + } + if (StringUtils.isBlank(countSql)) { + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sql, params); + countSql = generateMyCountSql(sqlParmeter.getSql()); + result =queryOneColumn(dataSourceWrapper, countSql, 1, sqlParmeter.getParams()); + } + if (null == result) { + return 0L; + } + return ConvertUtil.toLong(result); + } + + + public T queryOneColumn(Class targetType, String sqlId, Map parameter) { + return queryOneColumn(null, targetType, sqlId, parameter); + } + + public T queryOneColumn(DataSourceWrapper dataSourceWrapper, Class targetType, String sqlId, Map parameter) { + SqlInfo sqlInfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlInfo.getSql(), parameter); + Object result = queryOneColumn(dataSourceWrapper, sqlParmeter.getSql(), 1, sqlParmeter.getParams()); + return ConvertUtil.toObject(result, targetType); + } + + private Object findBy(DataSourceWrapper dataSourceWrapper, String sql, Map parameter) { + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sql, parameter); + return queryOneColumn(dataSourceWrapper, sqlParmeter.getSql(), 1, sqlParmeter.getParams()); + } + + private SqlWithParam getSqlParmeter(DataSourceWrapper dataSourceWrapper,String sql, Map parameter) { + return MybatisTpl.generate(sql,parameter,getDialect(dataSourceWrapper)); + } + + public Map queryToMap(Class c, String sqlId, String keyInMap, Map parameter) { + return queryToMap(null, c, sqlId, keyInMap, parameter); + } + + public Map queryToMap(DataSourceWrapper dataSourceWrapper, Class c, String sqlId, String keyInMap, Map parameter) { + SqlInfo sqlInfo = getSqlInfo(sqlId,parameter); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlInfo.getSql(), parameter); + return queryMapList(dataSourceWrapper, c, sqlParmeter.getSql(), keyInMap, sqlParmeter.getParams()); + } + + private SqlInfo getSqlInfo(String sqlId,Map parameter) { + if(null==parameter){ + parameter= new LinkedHashMap<>(); + } + parameter.put(MybatisTpl.MARKDOWN_SQL_ID,sqlId); + return MarkdownUtil.getSqlInfo(sqlId,needReadMdLastModified()); + } + + private String generateMyCountSql(String sql) { + StringBuilder sb = new StringBuilder(); + Matcher m = Pattern.compile("(/\\*)([\\w\\s\\@\\:]*)(\\*/)").matcher(sql); + while (m.find()) { + String group = m.group(); + sb.append(group); + } + CountSqlParser countSqlParser = new CountSqlParser(); + return sb.toString() + countSqlParser.getSmartCountSql(sql); + } + public int batchUpdate( String sqlId, List entityList) { + return batchUpdate(null,sqlId, entityList,0); + } + public int batchUpdate( String sqlId, List entityList,int size) { + return batchUpdate(null,sqlId, entityList,size); + } + public int batchUpdate(DataSourceWrapper dataSourceWrapper, String sqlId, List entityList){ + return batchUpdate(dataSourceWrapper, sqlId, entityList, 0); + } + public int batchUpdate(DataSourceWrapper dataSourceWrapper, String sqlId, List entityList,int size) { + if (null == entityList || entityList.isEmpty()) { + return 0; + } + + Map map = new LinkedHashMap<>(); + try { + T entity= entityList.get(0); + map = ConvertMap.toMap(entity,entity.getClass()); + } catch (IntrospectionException e) { + log.error("IntrospectionException ", e); + } + SqlInfo sqlinfo = getSqlInfo(sqlId,map); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sqlinfo.getSql(), map); + String sql = sqlParmeter.getSql(); + List param = new ArrayList<>(); + int i = 0; + List> listSplit = new ArrayList<>(); + int batchSize =size; + if(size<=0){ + batchSize = batchSize(); + } + for (T t : entityList) { + if (i != 0 && i % batchSize == 0) { + listSplit.add(param); + param = new ArrayList<>(); + } + param.add(beanToObjects(t, sqlParmeter.getPropertyNames())); + i++; + } + if (!param.isEmpty()) { + listSplit.add(param); + } + int updateNum=0; + for (List item : listSplit) { + int[] result = updateBatch(dataSourceWrapper, sql, item); + log.debug("\nbatchUpdateBySql {}", result); + updateNum+=result.length; + } + return updateNum; + } + + private Object[] beanToObjects(T t, List propertyNames) { + List result = new ArrayList<>(); + for (String propertyName: propertyNames) { + result.add(Constant.BeanUtil.getProperty(t, propertyName)); + } + return result.toArray(); + } + + public int update(String sqlId, Map parameter) { + return update(null, sqlId, parameter); + } + + public int update(DataSourceWrapper dataSourceWrapper, String sqlId, Map parameter) { + SqlInfo sqlinfo = getSqlInfo(sqlId,parameter); + String sql = sqlinfo.getSql(); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sql, parameter); + return update(dataSourceWrapper, sqlParmeter.getSql(), sqlParmeter.getParams()); + } + + public int insert(String sqlId, Map parameter) { + return insert(null, sqlId, parameter); + } + + public int insert(DataSourceWrapper dataSourceWrapper, String sqlId, Map parameter) { + SqlInfo sqlinfo = getSqlInfo(sqlId,parameter); + String sql = sqlinfo.getSql(); + SqlWithParam sqlParmeter = getSqlParmeter(dataSourceWrapper,sql, parameter); + return insert(dataSourceWrapper, sqlParmeter.getSql(), sqlParmeter.getParams()); + } + + // ================================= base + + public List queryList(DataSourceWrapper dataSourceWrapper,Class type, String sql, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + return jdbcTemplate.query(sql, new BeanListHandler<>(type), args); + } + //@Override + public List> queryListResultMap(DataSourceWrapper dataSourceWrapper,String sql, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + return jdbcTemplate.query(sql, new MapListHandler(sql), args); + } + + public void queryForBigData(DataSourceWrapper dataSourceWrapper,String sql, AbstractMapPageWork pageWork, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + jdbcTemplate.queryBigData(sql, new BigDataMapListHandler(pageWork, sql), args); + } + + @SuppressWarnings("unchecked") + public void queryForBigData(DataSourceWrapper dataSourceWrapper,Class type, String sql, AbstractPageWork pageWork, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + jdbcTemplate.queryBigData(sql, new BigDataBeanListHandler(type, pageWork, sql), args); + } + + public T queryOne(DataSourceWrapper dataSourceWrapper,Class type, String sql, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + return jdbcTemplate.query(sql, new BeanHandler<>(type), args); + } + + public Map queryUniqueResultMap(DataSourceWrapper dataSourceWrapper,String sql, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + return jdbcTemplate.query(sql, new MapHandler(sql), args); + } + + public Object queryOneColumn(DataSourceWrapper dataSourceWrapper,String sql, int columnIndex, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + return jdbcTemplate.query(sql, new ScalarHandler(columnIndex), args); + } + + + + + public Map queryMapList(DataSourceWrapper dataSourceWrapper,Class c, String sql, String keyInMap, Object... args) { + logSql(Constants.EnumRWType.read,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.read,sql); + return jdbcTemplate.query(sql, new MapBeanListHandler<>(c, keyInMap), args); + } + + //write + + public int insert(DataSourceWrapper dataSourceWrapper,T entity,String sql,List columnReturn, Object[] parameter) { + logSql(Constants.EnumRWType.write,sql, parameter); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.write,sql); + return jdbcTemplate.insert(sql,columnReturn, new BeanInsertHandler<>(entity), parameter); + } + + public int insert(DataSourceWrapper dataSourceWrapper,String sql,Object[] parameter) { + logSql(Constants.EnumRWType.write,sql, parameter); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.write,sql); + return jdbcTemplate.insert(sql,null, new ScalarHandler(), parameter); + } + public int update(DataSourceWrapper dataSourceWrapper,String sql, Object... args) { + logSql(Constants.EnumRWType.write,sql, args); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.write,sql); + return jdbcTemplate.update(sql, args); + } + + public int[] updateBatch(DataSourceWrapper dataSourceWrapper,String sql, List batchArgs) { + if(null==batchArgs||batchArgs.isEmpty()){ + return new int[0]; + } + logSql(Constants.EnumRWType.write,sql, batchArgs.get(0)); + MyJdbcTemplate jdbcTemplate = initJdbcTemplate(dataSourceWrapper,Constants.EnumRWType.write,sql); + return jdbcTemplate.batchUpdate(sql, batchArgs); + } + + private void logSql(Constants.EnumRWType enumRWType,String sql, Object... params) { + if(log.isDebugEnabled()){ + log.debug("\norg sql: {}\nparams: {}", sql, params); + String sqlResult= SqlFill.fill(sql, params); + log.debug("\nresult sql: {}", sqlResult); + } + if(log.isInfoEnabled()){ + if(enumRWType.equals(Constants.EnumRWType.write)&&logWrite()){ + log.info("\nwrite org sql: {}\n参数为:{}", sql, params); + if(logFullSql()){ + String sqlResult=SqlFill.fill(sql, params); + log.info("\nwrite result sql: {}", sqlResult); + } + } + if(enumRWType.equals(Constants.EnumRWType.read)&&logRead()){ + log.info("\nread org sql: {}\n参数为:{}", sql, params); + if(logFullSql()){ + String sqlResult=SqlFill.fill(sql, params); + log.info("\nread result sql: {}", sqlResult); + } + } + } + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/core/JdbcRepository.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/core/JdbcRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..a3bd5ff57762759c69c206158c0c624decb92dfe --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/core/JdbcRepository.java @@ -0,0 +1,60 @@ +package com.vonchange.jdbc.abstractjdbc.core; + +import com.vonchange.jdbc.abstractjdbc.handler.AbstractMapPageWork; +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; + +import java.util.List; +import java.util.Map; + +public interface JdbcRepository { + DataSourceWrapper getReadDataSource(); + List queryList(Class type, String sqlId, Map parameter); + int update(String sqlId, Map parameter); + int insert(String sqlId, Map parameter); + int insert(T entity); + int update(T entity); + int updateAllField(T entity); + int insertDuplicateKey(T entity); + T queryOne(Class type, String sqlId, Map parameter); + T queryById(Class type,Object id); + Page queryPage(Class type, String sqlId, Pageable pageable, Map parameter); + T queryOneColumn(Class targetType,String sqlId, Map parameter); + void queryBigData(Class type, String sqlId, AbstractPageWork pageWork, Map parameter); + // map + void queryMapBigData(String sqlId, AbstractMapPageWork pageWork, Map parameter); + Map queryMapOne(String sqlId, Map parameter); + Page> queryMapPage(String sqlId, Pageable pageable, Map parameter); + List> queryMapList(String sqlId, Map parameter); + int insertBatch(List entityList,int size); + int batchUpdate( String sqlId, List entityList,int size); + int updateBatch(List entityList,int size); + int insertBatchDuplicateKey(List entityList,int size); + //带 dataSource + List queryList(DataSourceWrapper dataSourceWrapper,Class type, String sqlId, Map parameter); + int update(DataSourceWrapper dataSourceWrapper,String sqlId, Map parameter); + int insert(DataSourceWrapper dataSourceWrapper,String sqlId, Map parameter); + int insert(DataSourceWrapper dataSourceWrapper,T entity); + int update(DataSourceWrapper dataSourceWrapper,T entity); + int updateAllField(DataSourceWrapper dataSourceWrapper,T entity); + int insertDuplicateKey(DataSourceWrapper dataSourceWrapper,T entity); + T queryOne(DataSourceWrapper dataSourceWrapper,Class type, String sqlId, Map parameter); + T queryById(DataSourceWrapper dataSourceWrapper,Class type,Object id); + Page queryPage(DataSourceWrapper dataSourceWrapper,Class type, String sqlId, Pageable pageable, Map parameter); + T queryOneColumn(DataSourceWrapper dataSourceWrapper,Class targetType,String sqlId, Map parameter); + void queryBigData(DataSourceWrapper dataSourceWrapper,Class type, String sqlId, AbstractPageWork pageWork, Map parameter); + // map + void queryMapBigData(DataSourceWrapper dataSourceWrapper,String sqlId, AbstractMapPageWork pageWork, Map parameter); + Map queryMapOne(DataSourceWrapper dataSourceWrapper,String sqlId, Map parameter); + Page> queryMapPage(DataSourceWrapper dataSourceWrapper,String sqlId, Pageable pageable, Map parameter); + List> queryMapList(DataSourceWrapper dataSourceWrapper,String sqlId, Map parameter); + int insertBatch(DataSourceWrapper dataSourceWrapper,List entityList,int size); + int updateBatch(DataSourceWrapper dataSourceWrapper,List entityList,int size); + int batchUpdate(DataSourceWrapper dataSourceWrapper, String sqlId, List entityList,int size); + Map queryToMap(Class c, String sqlId, String keyInMap, Map parameter); + Map queryToMap(DataSourceWrapper dataSourceWrapper,Class c, String sqlId, String keyInMap, Map parameter); + int insertBatchDuplicateKey(DataSourceWrapper dataSourceWrapper, List entityList,int size); +} + diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/count/CountSqlParser.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/count/CountSqlParser.java new file mode 100644 index 0000000000000000000000000000000000000000..6d806a9171a77c069a19386294a2ab13ba2293e1 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/count/CountSqlParser.java @@ -0,0 +1,464 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2014-2017 abel533@gmail.com + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package com.vonchange.jdbc.abstractjdbc.count; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.jsqlparser.expression.Alias; +import com.vonchange.jsqlparser.expression.Expression; +import com.vonchange.jsqlparser.expression.Function; +import com.vonchange.jsqlparser.parser.CCJSqlParserUtil; +import com.vonchange.jsqlparser.schema.Column; +import com.vonchange.jsqlparser.statement.Statement; +import com.vonchange.jsqlparser.statement.select.FromItem; +import com.vonchange.jsqlparser.statement.select.Join; +import com.vonchange.jsqlparser.statement.select.LateralSubSelect; +import com.vonchange.jsqlparser.statement.select.OrderByElement; +import com.vonchange.jsqlparser.statement.select.PlainSelect; +import com.vonchange.jsqlparser.statement.select.Select; +import com.vonchange.jsqlparser.statement.select.SelectBody; +import com.vonchange.jsqlparser.statement.select.SelectExpressionItem; +import com.vonchange.jsqlparser.statement.select.SelectItem; +import com.vonchange.jsqlparser.statement.select.SetOperationList; +import com.vonchange.jsqlparser.statement.select.SubJoin; +import com.vonchange.jsqlparser.statement.select.SubSelect; +import com.vonchange.jsqlparser.statement.select.ValuesList; +import com.vonchange.jsqlparser.statement.select.WithItem; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * sql解析类,提供更智能的count查询sql + * + * @author liuzh + */ +public class CountSqlParser { + private static final Logger log = LoggerFactory.getLogger(CountSqlParser.class); + public static final String KEEP_ORDERBY = "/*keep orderby*/"; + private static final Alias TABLE_ALIAS; + private static final String KEEP_SMART = "/*rx*/"; + // + private final Set skipFunctions = Collections.synchronizedSet(new HashSet()); + private final Set falseFunctions = Collections.synchronizedSet(new HashSet()); + + /** + * 聚合函数,以下列函数开头的都认为是聚合函数 + */ + private static final Set AGGREGATE_FUNCTIONS = new HashSet<>(Arrays.asList( + ("APPROX_COUNT_DISTINCT," + + "ARRAY_AGG," + + "AVG," + + "BIT_," + + //"BIT_AND," + + //"BIT_OR," + + //"BIT_XOR," + + "BOOL_," + + //"BOOL_AND," + + //"BOOL_OR," + + "CHECKSUM_AGG," + + "COLLECT," + + "CORR," + + //"CORR_," + + //"CORRELATION," + + "COUNT," + + //"COUNT_BIG," + + "COVAR," + + //"COVAR_POP," + + //"COVAR_SAMP," + + //"COVARIANCE," + + //"COVARIANCE_SAMP," + + "CUME_DIST," + + "DENSE_RANK," + + "EVERY," + + "FIRST," + + "GROUP," + + //"GROUP_CONCAT," + + //"GROUP_ID," + + //"GROUPING," + + //"GROUPING," + + //"GROUPING_ID," + + "JSON_," + + //"JSON_AGG," + + //"JSON_ARRAYAGG," + + //"JSON_OBJECT_AGG," + + //"JSON_OBJECTAGG," + + //"JSONB_AGG," + + //"JSONB_OBJECT_AGG," + + "LAST," + + "LISTAGG," + + "MAX," + + "MEDIAN," + + "MIN," + + "PERCENT_," + + //"PERCENT_RANK," + + //"PERCENTILE_CONT," + + //"PERCENTILE_DISC," + + "RANK," + + "REGR_," + + "SELECTIVITY," + + "STATS_," + + //"STATS_BINOMIAL_TEST," + + //"STATS_CROSSTAB," + + //"STATS_F_TEST," + + //"STATS_KS_TEST," + + //"STATS_MODE," + + //"STATS_MW_TEST," + + //"STATS_ONE_WAY_ANOVA," + + //"STATS_T_TEST_*," + + //"STATS_WSR_TEST," + + "STD," + + //"STDDEV," + + //"STDDEV_POP," + + //"STDDEV_SAMP," + + //"STDDEV_SAMP," + + //"STDEV," + + //"STDEVP," + + "STRING_AGG," + + "SUM," + + "SYS_OP_ZONE_ID," + + "SYS_XMLAGG," + + "VAR," + + //"VAR_POP," + + //"VAR_SAMP," + + //"VARIANCE," + + //"VARIANCE_SAMP," + + //"VARP," + + "XMLAGG").split(","))); + // + + static { + TABLE_ALIAS = new Alias("table_count"); + TABLE_ALIAS.setUseAs(false); + } + + /** + * 添加到聚合函数,可以是逗号隔开的多个函数前缀 + * + * @param functions + */ + public static void addAggregateFunctions(String functions){ + if(StringUtils.isNotBlank(functions)){ + String[] funs = functions.split(","); + for (int i = 0; i < funs.length; i++) { + AGGREGATE_FUNCTIONS.add(funs[i].toUpperCase()); + } + } + } + + /** + * 获取智能的countSql + * + * @param sql + */ + public String getSmartCountSql(String sql) { + return getSmartCountSql(sql, "0"); + } + private String generateMyCountSql(String sql) { + String lowerSql = sql.toLowerCase(); + int begin = lowerSql.indexOf("from "); + int guoIndex = lowerSql.lastIndexOf(')'); + int end = lowerSql.length(); + int orderIndex=0; + if (guoIndex > 0) { + orderIndex=sql.lastIndexOf("order ",guoIndex); + //sql.substring(guoIndex).lastIndexOf("order "); + if(orderIndex>0){ + end = guoIndex + orderIndex; + } + }else{ + orderIndex=sql.lastIndexOf("order "); + if(orderIndex>0){ + end = guoIndex + orderIndex; + } + } + String result = sql.substring(begin, end); + return StringUtils.format("select count(1) {0} ", result); + } + /** + * 获取智能的countSql + * + * @param sql + * @param name 列名,默认 0 + */ + public String getSmartCountSql(String sql, String name) { + //解析SQL + Statement stmt = null; + //特殊sql不需要去掉order by时,使用注释前缀 + if(sql.contains(KEEP_ORDERBY)){ + return getSimpleCountSql(sql, name); + } + boolean keepSmart=false; + if(sql.contains(KEEP_SMART)){ + keepSmart=true; + } + if(keepSmart){ + try{ + return generateMyCountSql(sql); + }catch (Exception e){ + return getSimpleCountSql(sql); + } + } + try { + stmt = CCJSqlParserUtil.parse(sql); + } catch (Exception e) { + log.debug("无法解析 使用一般方法返回count语句"); + //无法解析的用一般方法返回count语句 + return getSimpleCountSql(sql, name); + } + Select select = (Select) stmt; + SelectBody selectBody = select.getSelectBody(); + try { + //处理body-去order by + processSelectBody(selectBody); + } catch (Exception e) { + log.debug("当sql包含group by时 不去除order by"); + //当 sql 包含 group by 时,不去除 order by + return getSimpleCountSql(sql, name); + } + //处理with-去order by + processWithItemsList(select.getWithItemsList()); + //处理为count查询 + sqlToCount(select, name); + return select.toString(); + } + + /** + * 获取普通的Count-sql + * + * @param sql 原查询sql + * @return 返回count查询sql + */ + public String getSimpleCountSql(final String sql) { + return getSimpleCountSql(sql, "0"); + } + + /** + * 获取普通的Count-sql + * + * @param sql 原查询sql + * @return 返回count查询sql + */ + public String getSimpleCountSql(final String sql, String name) { + StringBuilder stringBuilder = new StringBuilder(sql.length() + 40); + stringBuilder.append("select count("); + stringBuilder.append(name); + stringBuilder.append(") from ("); + stringBuilder.append(sql); + stringBuilder.append(") tmp_count"); + return stringBuilder.toString(); + } + + /** + * 将sql转换为count查询 + * + * @param select + */ + public void sqlToCount(Select select, String name) { + SelectBody selectBody = select.getSelectBody(); + // 是否能简化count查询 + List COUNT_ITEM = new ArrayList<>(); + COUNT_ITEM.add(new SelectExpressionItem(new Column("count(" + name +")"))); + if (selectBody instanceof PlainSelect && isSimpleCount((PlainSelect) selectBody)) { + ((PlainSelect) selectBody).setSelectItems(COUNT_ITEM); + } else { + PlainSelect plainSelect = new PlainSelect(); + SubSelect subSelect = new SubSelect(); + subSelect.setSelectBody(selectBody); + subSelect.setAlias(TABLE_ALIAS); + plainSelect.setFromItem(subSelect); + plainSelect.setSelectItems(COUNT_ITEM); + select.setSelectBody(plainSelect); + } + } + + /** + * 是否可以用简单的count查询方式 + * + * @param select + */ + public boolean isSimpleCount(PlainSelect select) { + //包含group by的时候不可以 + if (select.getGroupBy() != null) { + return false; + } + //包含distinct的时候不可以 + if (select.getDistinct() != null) { + return false; + } + for (SelectItem item : select.getSelectItems()) { + //select列中包含参数的时候不可以,否则会引起参数个数错误 + if (item.toString().contains("?")) { + return false; + } + //如果查询列中包含函数,也不可以,函数可能会聚合列 + if (item instanceof SelectExpressionItem) { + Expression expression = ((SelectExpressionItem) item).getExpression(); + if (expression instanceof Function) { + String name = ((Function) expression).getName(); + if (name != null) { + String NAME = name.toUpperCase(); + if(skipFunctions.contains(NAME)){ + //go on + } else if(falseFunctions.contains(NAME)){ + return false; + } else { + for (String aggregateFunction : AGGREGATE_FUNCTIONS) { + if(NAME.startsWith(aggregateFunction)){ + falseFunctions.add(NAME); + return false; + } + } + skipFunctions.add(NAME); + } + } + } + } + } + return true; + } + + /** + * 处理selectBody去除Order by + * + * @param selectBody + */ + public void processSelectBody(SelectBody selectBody) { + if (selectBody instanceof PlainSelect) { + processPlainSelect((PlainSelect) selectBody); + } else if (selectBody instanceof WithItem) { + WithItem withItem = (WithItem) selectBody; + if (withItem.getSelectBody() != null) { + processSelectBody(withItem.getSelectBody()); + } + } else { + SetOperationList operationList = (SetOperationList) selectBody; + if (operationList.getSelects() != null && !operationList.getSelects().isEmpty()) { + List plainSelects = operationList.getSelects(); + for (SelectBody plainSelect : plainSelects) { + processSelectBody(plainSelect); + } + } + if (!orderByHashParameters(operationList.getOrderByElements())) { + operationList.setOrderByElements(null); + } + } + } + + /** + * 处理PlainSelect类型的selectBody + * + * @param plainSelect + */ + public void processPlainSelect(PlainSelect plainSelect) { + if (!orderByHashParameters(plainSelect.getOrderByElements())) { + plainSelect.setOrderByElements(null); + } + if (plainSelect.getFromItem() != null) { + processFromItem(plainSelect.getFromItem()); + } + if (plainSelect.getJoins() != null &&! plainSelect.getJoins().isEmpty()) { + List joins = plainSelect.getJoins(); + for (Join join : joins) { + if (join.getRightItem() != null) { + processFromItem(join.getRightItem()); + } + } + } + } + + /** + * 处理WithItem + * + * @param withItemsList + */ + public void processWithItemsList(List withItemsList) { + if (withItemsList != null && !withItemsList.isEmpty()) { + for (WithItem item : withItemsList) { + processSelectBody(item.getSelectBody()); + } + } + } + + /** + * 处理子查询 + * + * @param fromItem + */ + public void processFromItem(FromItem fromItem) { + if (fromItem instanceof SubJoin) { + SubJoin subJoin = (SubJoin) fromItem; + if (subJoin.getJoinList() != null && !subJoin.getJoinList().isEmpty()) { + for (Join join : subJoin.getJoinList()) { + if (join.getRightItem() != null) { + processFromItem(join.getRightItem()); + } + } + } + if (subJoin.getLeft() != null) { + processFromItem(subJoin.getLeft()); + } + } else if (fromItem instanceof SubSelect) { + SubSelect subSelect = (SubSelect) fromItem; + if (subSelect.getSelectBody() != null) { + processSelectBody(subSelect.getSelectBody()); + } + } else if (fromItem instanceof ValuesList) { + + } else if (fromItem instanceof LateralSubSelect) { + LateralSubSelect lateralSubSelect = (LateralSubSelect) fromItem; + if (lateralSubSelect.getSubSelect() != null) { + SubSelect subSelect = lateralSubSelect.getSubSelect(); + if (subSelect.getSelectBody() != null) { + processSelectBody(subSelect.getSelectBody()); + } + } + } + //Table时不用处理 + } + + /** + * 判断Orderby是否包含参数,有参数的不能去 + * + * @param orderByElements + */ + public boolean orderByHashParameters(List orderByElements) { + if (orderByElements == null) { + return false; + } + for (OrderByElement orderByElement : orderByElements) { + if (orderByElement.toString().contains("?")) { + return true; + } + } + return false; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/exception/NotAllowDBColumnException.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/exception/NotAllowDBColumnException.java new file mode 100644 index 0000000000000000000000000000000000000000..e5c5b6539f8652a1b0c019a84ec7a733769255eb --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/exception/NotAllowDBColumnException.java @@ -0,0 +1,16 @@ +package com.vonchange.jdbc.abstractjdbc.exception; + + +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; + +/** + *不允许使用数据库字段! + * @author von_change@163.com + * 2015-6-14 下午12:50:21 + */ +public class NotAllowDBColumnException extends MybatisMinRuntimeException { + + public NotAllowDBColumnException(String msg) { + super(msg); + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/AbstractMapPageWork.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/AbstractMapPageWork.java new file mode 100644 index 0000000000000000000000000000000000000000..95bb35e699add6f60c2c48761fda1ec75d4777fa --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/AbstractMapPageWork.java @@ -0,0 +1,39 @@ +package com.vonchange.jdbc.abstractjdbc.handler; + +import java.util.List; +import java.util.Map; + +/** + * Created by 冯昌义 on 2018/4/17. + */ +public abstract class AbstractMapPageWork { + private long totalElements; + private int totalPages; + private int size; + protected abstract void doPage(List> pageContentList, int pageNum, Map extData); + protected abstract int getPageSize(); + + public long getTotalElements() { + return totalElements; + } + + public void setTotalElements(long totalElements) { + this.totalElements = totalElements; + } + + public int getTotalPages() { + return totalPages; + } + + public void setTotalPages(int totalPages) { + this.totalPages = totalPages; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/AbstractPageWork.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/AbstractPageWork.java new file mode 100644 index 0000000000000000000000000000000000000000..84fbd39721dd7bdec28d4144a586caf8ae441ee9 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/AbstractPageWork.java @@ -0,0 +1,40 @@ +package com.vonchange.jdbc.abstractjdbc.handler; + +import java.util.List; +import java.util.Map; + +/** + * + * Created by 冯昌义 on 2018/4/17. + */ +public abstract class AbstractPageWork { + private long totalElements; + private int totalPages; + private int size; + protected abstract void doPage(List pageContentList, int pageNum, Map extData); + protected abstract int getPageSize(); + + public long getTotalElements() { + return totalElements; + } + + public void setTotalElements(long totalElements) { + this.totalElements = totalElements; + } + + public int getTotalPages() { + return totalPages; + } + + public void setTotalPages(int totalPages) { + this.totalPages = totalPages; + } + + public int getSize() { + return size; + } + + public void setSize(int size) { + this.size = size; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..25df2ee5f306e1eef6f718575bbea06537d9c894 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanHandler.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.jdbc.abstractjdbc.util.ConvertMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * ResultSetHandler implementation that converts the first + * ResultSet row into a JavaBean. This class is thread safe. + * + * @param + * the target bean type + */ +public class BeanHandler implements ResultSetExtractor { + + private static final Logger log = LoggerFactory.getLogger(BeanHandler.class); + /** + * The Class of beans produced by this handler. + */ + private final Class type; + + + public BeanHandler(Class type) { + this.type = type; + } + + /** + * Convert the first row of the ResultSet into a bean with the + * Class given in the constructor. + * + * @param rs + * ResultSet to process. + * @return An initialized JavaBean or null if there were no + * rows in the ResultSet. + * + * @throws SQLException + * if a database access error occurs + */ + @Override + public T extractData(ResultSet rs) throws SQLException { + return rs.next() ? this.toBean(rs, this.type) : null; + } + + private T toBean(ResultSet rs, Class type) throws SQLException { + T entity = null; + try { + entity = ConvertMap.convertMap(type,ConvertMap.newMap(HandlerUtil.rowToMap(rs))); + } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { + log.error("exception",e); + } + return entity; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanInsertHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanInsertHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..0eb039d2ade3af94f69d77ff71d2266512ab230b --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanInsertHandler.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.jdbc.abstractjdbc.util.ConvertMap; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; +import com.vonchange.mybatis.tpl.EntityUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * ResultSetHandler implementation that converts the first + * ResultSet row into a JavaBean. This class is thread safe. + * + * @param + * the target bean type + */ +public class BeanInsertHandler implements ResultSetExtractor { + + private static final Logger log = LoggerFactory.getLogger(BeanInsertHandler.class); + /** + * The Class of beans produced by this handler. + */ + private final T entity; + + + public BeanInsertHandler(T entity) { + this.entity = entity; + } + + /** + * Convert the first row of the ResultSet into a bean with the + * Class given in the constructor. + * + * @param rs + * ResultSet to process. + * @return An initialized JavaBean or null if there were no + * rows in the ResultSet. + * + * @throws SQLException + * if a database access error occurs + */ + @Override + public T extractData(ResultSet rs) throws SQLException { + return rs.next() ? this.toBean(rs, this.entity) : null; + } + + private T toBean(ResultSet rs, T entity) throws SQLException { + String genColumn = EntityUtil.getEntityInfo(entity.getClass()).getGenColumn(); + if(StringUtils.isBlank(genColumn)){ + throw new MybatisMinRuntimeException("实体类未设置主键注解@Id"); + } + try { + ConvertMap.convertMap(entity,null,ConvertMap.newMap(HandlerUtil.rowToMap(rs,genColumn))); + } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { + log.error("exception",e); + } + return entity; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanListHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanListHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..e86350941375a83c55b895030b500eb88c792cda --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanListHandler.java @@ -0,0 +1,103 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + +import com.vonchange.common.util.ClazzUtils; +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.jdbc.abstractjdbc.util.ConvertMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; + +/** + * ResultSetHandler implementation that converts a + * ResultSet into a List of beans. This class is + * thread safe. + * + * @param the target processor type + */ +public class BeanListHandler implements ResultSetExtractor> { + + private static final Logger log = LoggerFactory.getLogger(BeanListHandler.class); + /** + * The Class of beans produced by this handler. + */ + private final Class type; + + + /** + * Creates a new instance of BeanListHandler. + * + * @param type The Class that objects returned from handle() + * are created from. + */ + + + /** + * Creates a new instance of BeanListHandler. + * + * @param type The Class that objects returned from handle() + * are created from. + * to use when converting rows into beans. + */ + public BeanListHandler(Class type) { + this.type = type; + } + + /** + * Convert the whole ResultSet into a List of beans with + * the Class given in the constructor. + * + * @param rs The ResultSet to handle. + * @return A List of beans, never null. + * @throws SQLException if a database access error occurs + */ + @Override + public List extractData(ResultSet rs) throws SQLException { + try { + return this.toBeanList(rs, type); + } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { + log.error("Exception ", e); + } + return new ArrayList<>(); + } + @SuppressWarnings("unchecked") + private List toBeanList(ResultSet rs, Class type) throws SQLException, IntrospectionException, IllegalAccessException, InvocationTargetException { + List results = new ArrayList<>(); + if (!rs.next()) { + return results; + } + boolean base=false; + if(ClazzUtils.isBaseType(type)){ + base=true; + } + T entity; + do { + entity= (T) (base? ConvertUtil.toObject(rs.getObject(1),type):ConvertMap.convertMap(type,ConvertMap.newMap(HandlerUtil.rowToMap(rs)))); + results.add(entity); + } while (rs.next()); + return results; + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanProcessor.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanProcessor.java new file mode 100644 index 0000000000000000000000000000000000000000..a1b527d02e704752d98a03e7cbc8f5bb51af705a --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BeanProcessor.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import java.sql.SQLException; + +/** + *bean处理器 + * @author von_change@163.com + * 2015-6-14 下午10:12:33 + */ +public class BeanProcessor { + /** + * 创建bean + * @param rs + * @return T + * @throws SQLException + */ + //@SuppressWarnings("unchecked") + /*public T createBean(ResultSet rs, Class c) throws SQLException, IntrospectionException, IllegalAccessException, InvocationTargetException { + return (T) ConvertMap.convertMap(c,ConvertMap.newMap(HandlerUtil.rowToMap(rs))); + }*/ + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BigDataBeanListHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BigDataBeanListHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..ec9a12f5891b3eac701bb248b47323867bb4b01e --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BigDataBeanListHandler.java @@ -0,0 +1,123 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.common.util.ClazzUtils; +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.jdbc.abstractjdbc.util.ConvertMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @param the target processor type + */ +public class BigDataBeanListHandler implements ResultSetExtractor { + private static final Logger logger = LoggerFactory.getLogger(BigDataBeanListHandler.class); + /** + * The Class of beans produced by this handler. + */ + private final Class type; + private AbstractPageWork abstractPageWork; + + + /** + * Creates a new instance of BeanListHandler. + * + * @param type The Class that objects returned from handle() + * are created from. + */ + + + /** + * Creates a new instance of BeanListHandler. + * + * @param type The Class that objects returned from handle() + * are created from. + * to use when converting rows into beans. + */ + public BigDataBeanListHandler(Class type, AbstractPageWork abstractPageWork, String sql) { + this.type = type; + this.abstractPageWork = abstractPageWork; + } + + /** + * Convert the whole ResultSet into a List of beans with + * the Class given in the constructor. + * + * @param rs The ResultSet to handle. + * @return A List of beans, never null. + * @throws SQLException if a database access error occurs + */ + @Override + public Integer extractData(ResultSet rs) throws SQLException { + int pageSize = abstractPageWork.getPageSize(); + try { + this.toBeanList(rs, type, pageSize); + } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) { + logger.error("Exception ", e); + } + return 1; + } + @SuppressWarnings("unchecked") + private void toBeanList(ResultSet rs, Class type, int pageSize) throws SQLException, IntrospectionException, IllegalAccessException, InvocationTargetException { + List result = new ArrayList<>(); + Map extData = new HashMap<>(); + if (!rs.next()) { + abstractPageWork.doPage(result, 0, extData); + abstractPageWork.setSize(pageSize); + abstractPageWork.setTotalElements(0L); + abstractPageWork.setTotalPages(0); + return ; + } + int pageItem = 0; + int pageNum = 0; + long count = 0; + boolean base=false; + if(ClazzUtils.isBaseType(type)){ + base=true; + } + do { + result.add((T) (base? ConvertUtil.toObject(rs.getObject(1),type):ConvertMap.convertMap(type,ConvertMap.newMap(HandlerUtil.rowToMap(rs))))); + pageItem++; + count++; + if (pageItem == pageSize) { + abstractPageWork.doPage(result, pageNum, extData); + pageNum++; + result = new ArrayList<>(); + pageItem = 0; + } + } while (rs.next()); + if (!result.isEmpty()) { + abstractPageWork.doPage(result, pageNum, extData); + } + abstractPageWork.setSize(pageSize); + abstractPageWork.setTotalElements(count); + abstractPageWork.setTotalPages(pageNum); + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BigDataMapListHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BigDataMapListHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..b0f2d13e7f3b81dc067ee51d572894bc08f589e5 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/BigDataMapListHandler.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.mybatis.tpl.sql.SqlCommentUtil; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * ResultSetHandler implementation that converts the first + * ResultSet row into a Map. This class is thread + * safe. + */ +public class BigDataMapListHandler implements ResultSetExtractor { + private final String sql; + + private AbstractMapPageWork abstractPageWork; + public BigDataMapListHandler(AbstractMapPageWork abstractPageWork,String sql) { + this.sql=sql; + this.abstractPageWork=abstractPageWork; + } + + @Override + public Integer extractData(ResultSet rs) throws SQLException { + int pageSize=abstractPageWork.getPageSize(); + this.toMapList(rs,pageSize); + return 1; + } + + private void toMapList(ResultSet rs,int pageSize) throws SQLException { + List> result = new ArrayList<>(); + Map extData= new HashMap<>(); + if (!rs.next()) { + abstractPageWork.doPage(result,0,extData); + abstractPageWork.setSize(pageSize); + abstractPageWork.setTotalElements(0L); + abstractPageWork.setTotalPages(0); + return; + } + int pageItem=0; + int pageNum=0; + long count=0; + do { + result.add(HandlerUtil.rowToMap(rs, SqlCommentUtil.getLowerNo(sql) + ,SqlCommentUtil.getOrmNo(sql))); + pageItem++; + count++; + if(pageItem==pageSize){ + abstractPageWork.doPage(result,pageNum,extData); + pageNum++; + result=new ArrayList<>(); + pageItem=0; + } + } while (rs.next()); + if(!result.isEmpty()){ + abstractPageWork.doPage(result,pageNum,extData); + } + abstractPageWork.setSize(pageSize); + abstractPageWork.setTotalElements(count); + abstractPageWork.setTotalPages(pageNum); + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/HandlerUtil.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/HandlerUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..b03a60b5d4fc839aa63d2c90a271ab88684c2e5d --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/HandlerUtil.java @@ -0,0 +1,50 @@ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.mybatis.tpl.OrmUtil; + +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author 冯昌义 + * 2017/12/26. + */ +public class HandlerUtil { + private HandlerUtil() { throw new IllegalStateException("Utility class");} + public static Map rowToMap(ResultSet rs,boolean lower,boolean orm,String genColumn) throws SQLException { + Map resultMap = new LinkedHashMap<>(); + ResultSetMetaData rsmd = rs.getMetaData(); + int cols = rsmd.getColumnCount(); + for (int col = 1; col <= cols; col++) { + String columnName = rsmd.getColumnLabel(col); + if (null == columnName || 0 == columnName.length()) { + columnName = rsmd.getColumnName(col); + } + if(lower){ + columnName=columnName.toLowerCase(); + } + if(orm){ + columnName= OrmUtil.toFiled(columnName.toLowerCase()); + } + if(columnName.equalsIgnoreCase("GENERATED_KEY")){ + columnName=genColumn; + } + resultMap.put(columnName, rs.getObject(col)); + } + return resultMap; + } + public static Map rowToMap(ResultSet rs) throws SQLException{ + return rowToMap(rs,false,false); + } + public static Map rowToMap(ResultSet rs,String genColumn) throws SQLException{ + return rowToMap(rs,false,false,genColumn); + } + public static Map rowToMap(ResultSet rs,boolean lower,boolean orm) throws SQLException { + return rowToMap(rs,lower,orm,null); + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapBeanListHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapBeanListHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..ca3b3be4f9e72bb4b093994574e7c1260f71eb30 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapBeanListHandler.java @@ -0,0 +1,113 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.jdbc.abstractjdbc.config.ConstantJdbc; +import com.vonchange.jdbc.abstractjdbc.util.ConvertMap; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; + +/** + * ResultSetHandler implementation that converts a + * ResultSet into a List of beans. This class is + * thread safe. + * + * @param the target processor type + */ +public class MapBeanListHandler implements ResultSetExtractor> { + private static final Logger log = LoggerFactory.getLogger(MapBeanListHandler.class); + /** + * The Class of beans produced by this handler. + */ + private final Class type; + private final String keyInMap; + + /** + * Creates a new instance of BeanListHandler. + * + * @param type The Class that objects returned from handle() + * are created from. + */ + + + /** + * Creates a new instance of BeanListHandler. + * + * @param type The Class that objects returned from handle() + * are created from. + * to use when converting rows into beans. + */ + public MapBeanListHandler(Class type,String keyInMap) { + this.type = type; + this.keyInMap=keyInMap; + } + + /** + * Convert the whole ResultSet into a List of beans with + * the Class given in the constructor. + * + * @param rs The ResultSet to handle. + * + * @return A List of beans, never null. + * + * @throws SQLException if a database access error occurs + */ + @Override + public Map extractData(ResultSet rs) throws SQLException { + try { + return this.toBeanList(rs, type); + } catch (IllegalAccessException | IntrospectionException | InvocationTargetException e) { + log.error("",e); + } + return new HashMap<>(); + } + @SuppressWarnings("unchecked") + private Map toBeanList(ResultSet rs, Class type) throws SQLException, IllegalAccessException, IntrospectionException, InvocationTargetException { + Map resultMap= new HashMap<>(); + if (!rs.next()) { + return resultMap; + } + T entity ; + Map newMap; + do { + newMap=ConvertMap.newMap(HandlerUtil.rowToMap(rs)); + entity=(T) ConvertMap.convertMap(type,newMap); + String[] keyInMaps= new String[]{keyInMap}; + if(keyInMap.indexOf(ConstantJdbc.MAPFIELDSPLIT)!=-1){ + keyInMaps=keyInMap.split(ConstantJdbc.MAPFIELDSPLIT); + } + StringBuilder key=new StringBuilder(); + for (String keyIn:keyInMaps) { + keyIn=keyIn.toLowerCase(); + key.append(ConvertUtil.toString(newMap.get(keyIn))).append("_"); + } + resultMap.put(key.substring(0,key.length()-1),entity); + } while (rs.next()); + return resultMap; + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..1d290501b436acad443504a0f9f5ce086c83e1ce --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapHandler.java @@ -0,0 +1,56 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.mybatis.tpl.sql.SqlCommentUtil; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +/** + * ResultSetHandler implementation that converts the first + * ResultSet row into a Map. This class is thread + * safe. + * + */ +public class MapHandler implements ResultSetExtractor> { + + private String sql; + public MapHandler(String sql){ + this.sql=sql; + } + /** + * Converts the first row in the ResultSet into a + * Map. + * @param rs ResultSet to process. + * @return A Map with the values from the first row or + * null if there are no rows in the ResultSet. + * + * @throws SQLException if a database access error occurs + */ + @Override + public Map extractData(ResultSet rs) throws SQLException { + return rs.next() ? this.toMap(rs) : null; + } + + private Map toMap(ResultSet rs) throws SQLException { + return HandlerUtil.rowToMap(rs, SqlCommentUtil.getLowerNo(sql),SqlCommentUtil.getOrmNo(sql)); + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapListHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapListHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..0baa21d18cfcd5d7432f366e504434dc2cf788c9 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/MapListHandler.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + + +import com.vonchange.mybatis.tpl.sql.SqlCommentUtil; +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * ResultSetHandler implementation that converts the first + * ResultSet row into a Map. This class is thread + * safe. + */ +public class MapListHandler implements ResultSetExtractor>> { + private String sql; + public MapListHandler(String sql){ + this.sql=sql; + } + @Override + public List> extractData(ResultSet rs) throws SQLException { + return this.toMapList(rs); + } + + private List> toMapList(ResultSet rs) throws SQLException { + List> result = new ArrayList<>(); + if (!rs.next()) { + return result; + } + do { + result.add(HandlerUtil.rowToMap(rs, SqlCommentUtil.getLowerNo(sql), + SqlCommentUtil.getOrmNo(sql))); + } while (rs.next()); + return result; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/ScalarHandler.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/ScalarHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..851631ed903a08ae7f70bf7cd4020f9d0cb497c9 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/handler/ScalarHandler.java @@ -0,0 +1,106 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.jdbc.abstractjdbc.handler; + +import org.springframework.jdbc.core.ResultSetExtractor; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * ResultSetHandler implementation that converts one + * ResultSet column into an Object. This class is thread safe. + * + */ +public class ScalarHandler implements ResultSetExtractor { + + /** + * The column number to retrieve. + */ + private final int columnIndex; + + /** + * The column name to retrieve. Either columnName or columnIndex + * will be used but never both. + */ + private final String columnName; + + /** + * Creates a new instance of ScalarHandler. The first column will + * be returned from handle(). + */ + public ScalarHandler() { + this(1, null); + } + + /** + * Creates a new instance of ScalarHandler. + * + * @param columnIndex The index of the column to retrieve from the + * ResultSet. + */ + public ScalarHandler(int columnIndex) { + this(columnIndex, null); + } + + /** + * Creates a new instance of ScalarHandler. + * + * @param columnName The name of the column to retrieve from the + * ResultSet. + */ + public ScalarHandler(String columnName) { + this(1, columnName); + } + + /** Helper constructor + * @param columnIndex The index of the column to retrieve from the + * ResultSet. + * @param columnName The name of the column to retrieve from the + * ResultSet. + */ + private ScalarHandler(int columnIndex, String columnName) { + this.columnIndex = columnIndex; + this.columnName = columnName; + } + + /** + * Returns one ResultSet column as an object via the + * ResultSet.getObject() method that performs type + * conversions. + * @param rs ResultSet to process. + * @return The column or null if there are no rows in + * the ResultSet. + * + * @throws SQLException if a database access error occurs + * @throws ClassCastException if the class datatype does not match the column type + * + */ + // We assume that the user has picked the correct type to match the column + // so getObject will return the appropriate type and the cast will succeed. + @SuppressWarnings("unchecked") + @Override + public Object extractData(ResultSet rs) throws SQLException { + if (rs.next()) { + if (this.columnName == null) { + return rs.getObject(this.columnIndex); + } + return rs.getObject(this.columnName); + } + return null; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/DataSourceWrapper.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/DataSourceWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..91a7fd2b70cc7598c8cdf5c44b338f3b3feda12c --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/DataSourceWrapper.java @@ -0,0 +1,33 @@ +package com.vonchange.jdbc.abstractjdbc.model; + +import com.vonchange.mybatis.dialect.Dialect; + +import javax.sql.DataSource; + +public class DataSourceWrapper { + private DataSource dataSource; + private String key; + private Dialect dialect; + public DataSourceWrapper(DataSource dataSource,String key){ + this.dataSource=dataSource; + this.key=key; + } + + public DataSource getDataSource() { + return dataSource; + } + + public Dialect getDialect() { + return dialect; + } + + public DataSourceWrapper setDialect(Dialect dialect) { + this.dialect = dialect; + return this; + } + + public String getKey() { + return key; + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityCu.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityCu.java new file mode 100644 index 0000000000000000000000000000000000000000..4e65e782448eb447f9f81d2f3ca697703775cc40 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityCu.java @@ -0,0 +1,105 @@ +package com.vonchange.jdbc.abstractjdbc.model; + +import com.vonchange.mybatis.tpl.model.EntityField; + +public class EntityCu { + private EntityField entityField; + private Object value; + private Boolean duplicate; + private Boolean nullUpdate; + private String insertIfNullValue; + private Boolean insertKeyColumn; + private Boolean insertValueParam; + private String updateIfNullValue; + private Boolean updateValueColumn; + private Boolean updateValueParam; + public EntityCu() { + } + public EntityCu(EntityField entityField, Object value,Boolean duplicate,Boolean nullUpdate) { + this.entityField = entityField; + this.value = value; + this.duplicate=duplicate; + this.nullUpdate =nullUpdate; + } + + public Boolean getUpdateValueParam() { + return updateValueParam; + } + + public void setUpdateValueParam(Boolean updateValueParam) { + this.updateValueParam = updateValueParam; + } + + public Boolean getInsertValueParam() { + return insertValueParam; + } + + public void setInsertValueParam(Boolean insertValueParam) { + this.insertValueParam = insertValueParam; + } + + public String getUpdateIfNullValue() { + return updateIfNullValue; + } + + public void setUpdateIfNullValue(String updateIfNullValue) { + this.updateIfNullValue = updateIfNullValue; + } + + public Boolean getUpdateValueColumn() { + return updateValueColumn; + } + + public void setUpdateValueColumn(Boolean updateValueColumn) { + this.updateValueColumn = updateValueColumn; + } + + public Boolean getInsertKeyColumn() { + return insertKeyColumn; + } + + public void setInsertKeyColumn(Boolean insertKeyColumn) { + this.insertKeyColumn = insertKeyColumn; + } + + public Boolean getNullUpdate() { + return nullUpdate; + } + + public void setNullUpdate(Boolean nullUpdate) { + this.nullUpdate = nullUpdate; + } + + public String getInsertIfNullValue() { + return insertIfNullValue; + } + + public void setInsertIfNullValue(String insertIfNullValue) { + this.insertIfNullValue = insertIfNullValue; + } + + public Boolean getDuplicate() { + return duplicate; + } + + public void setDuplicate(Boolean duplicate) { + this.duplicate = duplicate; + } + + + public EntityField getEntityField() { + return entityField; + } + + public void setEntityField(EntityField entityField) { + this.entityField = entityField; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityInsertResult.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityInsertResult.java new file mode 100644 index 0000000000000000000000000000000000000000..7838d030e3d460d24e0e6a0fd4a248f7e7ebdd70 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityInsertResult.java @@ -0,0 +1,49 @@ +package com.vonchange.jdbc.abstractjdbc.model; + +import java.util.List; + +public class EntityInsertResult { + private String keySql; + private String valueSql; + private String updateStr; + private List valueList; + + public EntityInsertResult(String keySql, String valueSql, String updateStr,List valueList) { + this.keySql = keySql; + this.valueSql = valueSql; + this.updateStr=updateStr; + this.valueList = valueList; + } + + public String getUpdateStr() { + return updateStr; + } + + public void setUpdateStr(String updateStr) { + this.updateStr = updateStr; + } + + public String getValueSql() { + return valueSql; + } + + public void setValueSql(String valueSql) { + this.valueSql = valueSql; + } + + public List getValueList() { + return valueList; + } + + public void setValueList(List valueList) { + this.valueList = valueList; + } + + public String getKeySql() { + return keySql; + } + + public void setKeySql(String keySql) { + this.keySql = keySql; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityUpdateResult.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityUpdateResult.java new file mode 100644 index 0000000000000000000000000000000000000000..2f5dcf30a76ada0cc9c476a2a1891b0a8a77d54d --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/EntityUpdateResult.java @@ -0,0 +1,33 @@ +package com.vonchange.jdbc.abstractjdbc.model; + +import java.util.List; + +public class EntityUpdateResult { + private String updateStr; + private List valueList; + + public EntityUpdateResult( String updateStr, List valueList) { + this.updateStr=updateStr; + this.valueList = valueList; + } + + public String getUpdateStr() { + return updateStr; + } + + public void setUpdateStr(String updateStr) { + this.updateStr = updateStr; + } + + + + public List getValueList() { + return valueList; + } + + public void setValueList(List valueList) { + this.valueList = valueList; + } + + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/SqlFragment.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/SqlFragment.java new file mode 100644 index 0000000000000000000000000000000000000000..a1ef4f12856b76c5f9c9816179477797a20b5c98 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/model/SqlFragment.java @@ -0,0 +1,30 @@ +package com.vonchange.jdbc.abstractjdbc.model; + +import java.util.List; + +/** + * sql片段实体 + * @author von_change@163.com + * 2015-6-14 下午12:45:34 + */ +public class SqlFragment { + private String sql; + private List params; + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public List getParams() { + return params; + } + + public void setParams(List params) { + this.params = params; + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/template/MyJdbcTemplate.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/template/MyJdbcTemplate.java new file mode 100644 index 0000000000000000000000000000000000000000..d469b31c56fa8ea5af5730320a11ba09840cd831 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/template/MyJdbcTemplate.java @@ -0,0 +1,134 @@ +package com.vonchange.jdbc.abstractjdbc.template; + +import org.springframework.dao.DataAccessException; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.ParameterDisposer; +import org.springframework.jdbc.core.PreparedStatementCallback; +import org.springframework.jdbc.core.PreparedStatementCreator; +import org.springframework.jdbc.core.PreparedStatementSetter; +import org.springframework.jdbc.core.ResultSetExtractor; +import org.springframework.jdbc.core.SqlProvider; +import org.springframework.util.Assert; + +import javax.sql.DataSource; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.List; + +public class MyJdbcTemplate extends JdbcTemplate { + public MyJdbcTemplate() { + } + + /** + * Construct a new JdbcTemplate, given a DataSource to obtain connections from. + *

Note: This will not trigger initialization of the exception translator. + * @param dataSource the JDBC DataSource to obtain connections from + */ + public MyJdbcTemplate(DataSource dataSource) { + super(dataSource); + } + protected int insert(final PreparedStatementCreator psc, final PreparedStatementSetter pss, final ResultSetExtractor rse) throws DataAccessException { + + logger.debug("Executing prepared SQL update"); + return execute(psc, new PreparedStatementCallback() { + + public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException { + try { + if (pss != null) { + pss.setValues(ps); + } + int result = ps.executeUpdate(); + ResultSet resultSet = ps.getGeneratedKeys(); + rse.extractData(resultSet); + /* if (logger.isDebugEnabled()) { + logger.debug("generatedKeys : " + generatedKeys); + }*/ + return result; + } finally { + if (pss instanceof ParameterDisposer) { + ((ParameterDisposer) pss).cleanupParameters(); + } + } + } + }); + } + + private int insert(String sql,List columnReturn, PreparedStatementSetter pss, ResultSetExtractor rse) throws DataAccessException { + return insert(new InsertPreparedStatementCreator(sql,columnReturn), pss, rse); + } + + + public int insert(String sql, List columnReturn, ResultSetExtractor rse, Object... params) { + return insert(sql,columnReturn, newArgPreparedStatementSetter(params), rse); + } + private static class InsertPreparedStatementCreator implements PreparedStatementCreator, SqlProvider { + + private final String sql; + private final List columnReturn; + + public InsertPreparedStatementCreator(String sql,List columnReturn) { + Assert.notNull(sql, "SQL must not be null"); + this.sql = sql; + this.columnReturn=columnReturn; + } + + public PreparedStatement createPreparedStatement(Connection con) throws SQLException { + /* if(null==columnReturn||columnReturn.isEmpty()){ + return con.prepareStatement(this.sql, Statement.RETURN_GENERATED_KEYS); + }*/ + return con.prepareStatement(this.sql, Statement.RETURN_GENERATED_KEYS); + //return con.prepareStatement(this.sql, columnReturn.toArray(new String[0])); + } + public String getSql() { + return this.sql; + } + } + + private int fetchSizeBigData=0; + + public int getFetchSizeBigData() { + return fetchSizeBigData; + } + + public void setFetchSizeBigData(int fetchSizeBigData) { + this.fetchSizeBigData = fetchSizeBigData; + } + + public T queryBigData(String sql, ResultSetExtractor rse, Object... args) throws DataAccessException { + return queryBigData(sql, newArgPreparedStatementSetter(args), rse); + } + public T queryBigData(String sql, PreparedStatementSetter pss, ResultSetExtractor rse) throws DataAccessException { + int fetchSize = getFetchSizeBigData(); + return query(new BigDataPreparedStatementCreator(sql,fetchSize), pss, rse); + } + + + private static class BigDataPreparedStatementCreator implements PreparedStatementCreator, SqlProvider { + + private final String sql; + private final int fetchSize; + + public BigDataPreparedStatementCreator(String sql,int fetchSize) { + Assert.notNull(sql, "SQL must not be null"); + this.sql = sql; + this.fetchSize=fetchSize; + } + + @Override + public PreparedStatement createPreparedStatement(Connection con) throws SQLException { + PreparedStatement ps = con.prepareStatement(sql, ResultSet.TYPE_FORWARD_ONLY, + ResultSet.CONCUR_READ_ONLY); + ps.setFetchSize(this.fetchSize); + ps.setFetchDirection(ResultSet.FETCH_REVERSE); + return ps; + } + + @Override + public String getSql() { + return this.sql; + } + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/ConvertMap.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/ConvertMap.java new file mode 100644 index 0000000000000000000000000000000000000000..90d842bad4d83a0c5072c0152ff89b912e492b4e --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/ConvertMap.java @@ -0,0 +1,110 @@ +package com.vonchange.jdbc.abstractjdbc.util; + + +import com.vonchange.common.util.ClazzUtils; +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.mybatis.config.Constant; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; +import com.vonchange.mybatis.tpl.EntityUtil; +import com.vonchange.mybatis.tpl.OrmUtil; +import com.vonchange.mybatis.tpl.model.EntityField; +import com.vonchange.mybatis.tpl.model.EntityInfo; + +import java.beans.BeanInfo; +import java.beans.IntrospectionException; +import java.beans.Introspector; +import java.beans.PropertyDescriptor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; + +public class ConvertMap { + private ConvertMap() { + throw new IllegalStateException("Utility class"); + } + + @SuppressWarnings("unchecked") + public static Map toMap(T entity,Class clazz) throws IntrospectionException { + if(entity instanceof Map){ + return (Map) entity; + } + BeanInfo beanInfo = Introspector.getBeanInfo(clazz); + PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); + String propertyName; + Object value; + Map map = new HashMap<>(); + for (PropertyDescriptor property: propertyDescriptors) { + if(!ClazzUtils.isBaseType(property.getPropertyType())){ + continue; + } + propertyName = property.getName(); + value= Constant.BeanUtil.getProperty(entity, propertyName); + //property.getValue(propertyName); + map.put(propertyName,value); + } + return map; + } + + /** + * Map to JavaBean + */ + @SuppressWarnings("unchecked") + public static T convertMap(T entity,Class type, Map map) throws IntrospectionException, IllegalAccessException, InvocationTargetException { + if(null!=entity){ + type=entity.getClass(); + } + if(null==entity){ + try { + entity = (T) type.newInstance(); + }catch (InstantiationException e){ + throw new MybatisMinRuntimeException("java.lang.InstantiationException "+type.getName()+" need no-arguments constructor"); + } + } + EntityInfo entityInfo = EntityUtil.getEntityInfo(type); + if(null!=entityInfo){ + Map fieldInfoMap = entityInfo.getFieldMap(); + for (Map.Entry entry:fieldInfoMap.entrySet()) { + String columnNameLower = entry.getValue().getColumnName().toLowerCase(); + String fieldNameLower = entry.getValue().getFieldName().toLowerCase(); + Object value = null; + if(map.containsKey(fieldNameLower)){ + value = map.get(fieldNameLower); + } + if(map.containsKey(columnNameLower)){ + value = map.get(columnNameLower); + } + if (null!=value) { + value = ConvertUtil.toObject(value, entry.getValue().getType()); + //Constant.BeanUtil.setProperty(entity,entry.getValue().getFieldName(),value); + Method writeMethod = entry.getValue().getWriteMethod(); + writeMethod.invoke(entity, value); + } + } + return entity; + } + return entity; + } + public static T convertMap(Class type, Map map) throws IntrospectionException, IllegalAccessException, InvocationTargetException { + return convertMap(null,type,map); + } + + + public static Map newMap(Map map){ + if(null==map||map.isEmpty()){ + return new LinkedHashMap<>(); + } + Map newMap=new LinkedHashMap<>(); + String key; + for (Map.Entry entry: map.entrySet()) { + key=entry.getKey(); + newMap.put(key.toLowerCase(),entry.getValue()); + key= OrmUtil.toFiled(entry.getKey()); + newMap.put(key.toLowerCase(),entry.getValue()); + } + return newMap; + } + + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/PageUtil.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/PageUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..2c1686e6dd2563d5e0cdd7aa0913969a19b83d70 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/PageUtil.java @@ -0,0 +1,14 @@ +package com.vonchange.jdbc.abstractjdbc.util; + +/** + * Created by 冯昌义 on 2018/5/24. + */ +public class PageUtil { + private PageUtil() { throw new IllegalStateException("Utility class"); } + public static int getTotalPage(long totalNum, int pageSize) { + if (pageSize <= 0 || totalNum <= 0) { + return 0; + } + return (int) Math.ceil((double) totalNum / (double) pageSize); + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/FileUtils.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/FileUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..86254188e3f462e4ac92e3660942354f12d16331 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/FileUtils.java @@ -0,0 +1,44 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +public class FileUtils { + private FileUtils() { + throw new IllegalStateException("Utility class"); + } + private static final String ENCODING = "UTF-8"; + private static final String URLSEPARATOR="/"; + public static String getEncoding() { + return ENCODING; + } + public static String getFileURLPath(String packageName, String name) { + String path = packageName.replaceAll("\\.", URLSEPARATOR); + return path + URLSEPARATOR+ name; + } + + + + + /** + * 取指定文件的扩展名 + * @param filePathName + * 文件路径 + * @return 扩展名 + */ + public static String getFileExt(String filePathName) { + int pos = 0; + pos = filePathName.lastIndexOf('.'); + if (pos != -1) + return filePathName.substring(pos + 1, filePathName.length()); + else + return ""; + } + //classpath:com/test/a.md + public static Resource getResource(String location){ + PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver(); + return patternResolver.getResource(location); + } + + +} \ No newline at end of file diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownDTO.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..d43a0bfc057fd466ef4946049a5ac763b7e1ecb6 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownDTO.java @@ -0,0 +1,45 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown; + +import java.util.HashMap; +import java.util.Map; + + +public class MarkdownDTO { + private String id;//文件或整个文档ID + private String version;//版本号 + private Map contentMap=new HashMap<>(); + private Map> jsonMap=new HashMap<>(); + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Map getContentMap() { + return contentMap; + } + + public void setContentMap(Map contentMap) { + this.contentMap = contentMap; + } + + public Map> getJsonMap() { + return jsonMap; + } + + public void setJsonMap(Map> jsonMap) { + this.jsonMap = jsonMap; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownDataUtil.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownDataUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..094177916175104d7fd8143037b915d643d72384 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownDataUtil.java @@ -0,0 +1,22 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.jdbc.abstractjdbc.config.ConstantJdbc; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; + + +public class MarkdownDataUtil{ + private MarkdownDataUtil() { + throw new IllegalStateException("Utility class"); + } + + public static String getSql(MarkdownDTO markdownDTO,String id) { + String sql =markdownDTO.getContentMap().get(id); + if(StringUtils.isBlank(sql)&&!StringUtils.endsWith(id, ConstantJdbc.COUNTFLAG)){ + throw new MybatisMinRuntimeException(markdownDTO.getId()+" can not find id:"+id); + } + /* 支持[@sql */ + return MarkdownUtil.getSqlSpinner(markdownDTO,sql); + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownUtil.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..3e8115b89aa9651576faa9c24f5f2020fc285eaf --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/MarkdownUtil.java @@ -0,0 +1,287 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown; + + +import com.vonchange.common.util.FileUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.jdbc.abstractjdbc.config.ConstantJdbc; +import com.vonchange.jdbc.abstractjdbc.config.Constants; +import com.vonchange.jdbc.abstractjdbc.util.markdown.bean.MdWithInnerIdTemp; +import com.vonchange.jdbc.abstractjdbc.util.markdown.bean.SqlInfo; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * markdown 组件 + * von_change + */ +public class MarkdownUtil { + private MarkdownUtil(){ + throw new IllegalStateException("Utility class"); + } + private static Logger logger = LoggerFactory.getLogger(MarkdownUtil.class); + private static Map idMarkdownMap=new ConcurrentHashMap<>(); + + + public static boolean markdownFileExist(String packageName,String fileName){ + String url= "classpath:"+FileUtils.getFileURLPath(packageName,fileName); + Resource resource= FileUtils.getResource(url); + return resource.exists(); + } + public static MarkdownDTO readMarkdownFile(String packageName,String fileName,boolean needReadMdLastModified){ + String id = packageName+"."+fileName; + if(!needReadMdLastModified&&idMarkdownMap.containsKey(id)){ + return idMarkdownMap.get(id); + } + String url= "classpath:"+FileUtils.getFileURLPath(packageName,fileName); + Resource resource= FileUtils.getResource(url); + long lastModified; + try { + lastModified= resource.lastModified(); + if(lastModified==0){ + return null; + } + } catch (IOException e) { + logger.error("read markdown file error {}",url); + throw new MybatisMinRuntimeException("read markdown file error "+url); + } + boolean needLoad=true; + if(idMarkdownMap.containsKey(id)){ + MarkdownDTO markdownDTO=idMarkdownMap.get(id); + if((lastModified+"").equals(markdownDTO.getVersion())){ + needLoad=false; + } + } + if(!needLoad){ + return idMarkdownMap.get(id); + } + String content=null; + try { + content= FileUtil.readUTFString(resource.getInputStream()); + } catch (IOException e) { + logger.error("读取markdown文件出错{}:{}",url,e); + } + MarkdownDTO markdownDTO= getMarkDownInfo(content,id,lastModified+""); + idMarkdownMap.put(id,markdownDTO); + return markdownDTO; + } + private static MarkdownDTO readMarkdown(String content,String id,String version){ + if(null==id||"".equals(id.trim())){ + id=getId(content); + } + if(null==version||"".equals(version.trim())){ + version=getVersion(content); + } + boolean needLoad=true; + if(null!=idMarkdownMap.get(id)){ + MarkdownDTO markdownDTO=idMarkdownMap.get(id); + if((version).equals(markdownDTO.getVersion())){ + needLoad=false; + } + } + if(!needLoad){ + return idMarkdownMap.get(id); + } + MarkdownDTO markdownDTO= getMarkDownInfo(content,id,version); + idMarkdownMap.put(id,markdownDTO); + return markdownDTO; + } + private static String getId(String result){ + String idSym= ConstantJdbc.MDID; + int vdx = result.indexOf(idSym); + if(vdx == -1) { + throw new IllegalArgumentException("无"+ConstantJdbc.MDID); + } + StringBuilder idSB=new StringBuilder(); + for(int j=vdx+idSB.length();result.charAt(j)!='\n';j++){ + idSB.append(result.charAt(j)); + } + return idSB.toString(); + } + private static String getVersion(String result){ + String versionSym=ConstantJdbc.MDVERSION; + int vdx = result.indexOf(versionSym); + if(vdx == -1) { + throw new IllegalArgumentException("无"+ConstantJdbc.MDVERSION); + } + StringBuilder versionSB=new StringBuilder(); + for(int j=vdx+versionSym.length();result.charAt(j)!='\n';j++){ + versionSB.append(result.charAt(j)); + } + return versionSB.toString(); + } + + private static MarkdownDTO getMarkDownInfo(String result,String id,String version){ + MarkdownDTO markdownDTO= new MarkdownDTO(); + String scriptSym="```"; + if(null==id||"".equals(id.trim())){ + markdownDTO.setId(getId(result)); + }else{ + markdownDTO.setId(id); + } + if(null==version||"".equals(version.trim())){ + markdownDTO.setVersion(getVersion(result)); + }else{ + markdownDTO.setVersion(version); + } + int i=0; + int len = result.length(); + int startLen=scriptSym.length(); + int endLen=scriptSym.length(); + StringBuilder idSB; + while (i < len) { + int ndx = result.indexOf(scriptSym, i); + if(ndx==-1){ + break; + } + ndx += startLen; + idSB=new StringBuilder(); + for(int j=ndx;result.charAt(j)!='\n';j++){ + idSB.append(result.charAt(j)); + } + int firstLineLength=idSB.length(); + idSB=new StringBuilder(); + for(int j=ndx+firstLineLength+1;result.charAt(j)!='\n';j++){ + idSB.append(result.charAt(j)); + } + int zsIndex= idSB.indexOf(Constants.Markdown.IDPREF); + if(zsIndex==-1){ + throw new IllegalArgumentException("无id注释"+idSB); + } + String key= idSB.substring(zsIndex+Constants.Markdown.IDPREF.length()).trim(); + if(key.length()==0){ + throw new IllegalArgumentException("请定义类型和ID at "+ndx); + } + ndx += idSB.length()+firstLineLength+1; + int ndx2 = result.indexOf(scriptSym, ndx); + if(ndx2 == -1) { + throw new IllegalArgumentException("无结尾 ``` 符号 at: " + (ndx - startLen)); + } + String content=result.substring(ndx,ndx2).trim(); + markdownDTO.getContentMap().put(key,content); + i=ndx2+endLen; + } + return markdownDTO; + } + public static String getSqlSpinner(MarkdownDTO markdownDTO,String sql){ + if(StringUtils.isBlank(sql)){ + return sql; + } + if(!sql.contains("[@sql")){ + return sql; + } + String startSym="[@sql"; + String endSym="]"; + int len = sql.length(); + int startLen=startSym.length(); + int endLen=endSym.length(); + int i=0; + StringBuilder newSb=new StringBuilder(); + String model; + while (i < len) { + int ndx = sql.indexOf(startSym, i); + if(ndx==-1){ + newSb.append(i == 0?sql:sql.substring(i)); + break; + } + newSb.append(sql, i, ndx); + ndx += startLen; + int ndx2 = sql.indexOf(endSym, ndx); + if(ndx2 == -1) { + throw new IllegalArgumentException("无结尾 } 符号 at: " + (ndx - startLen)); + } + model=sql.substring(ndx,ndx2).trim(); + newSb.append(MarkdownDataUtil.getSql(markdownDTO,model)); + i=ndx2+endLen; + } + return newSb.toString(); + } + + public static String getSql(String sqlId) { + MdWithInnerIdTemp mdWithInnerIdTemp=loadConfigData(sqlId,false); + return MarkdownDataUtil.getSql(mdWithInnerIdTemp.getMarkdownDTO(),mdWithInnerIdTemp.getInnnerId()); + } + public static boolean containsSqlId(String sqlId) { + MdWithInnerIdTemp mdWithInnerIdTemp=loadConfigData(sqlId,false); + return mdWithInnerIdTemp.getMarkdownDTO().getContentMap().containsKey(sqlId); + } + public static SqlInfo getSqlInfo(String sqlId,boolean needReadMdLastModified) { + MdWithInnerIdTemp mdWithInnerIdTemp=loadConfigData(sqlId,needReadMdLastModified); + String sql = MarkdownDataUtil.getSql(mdWithInnerIdTemp.getMarkdownDTO(),mdWithInnerIdTemp.getInnnerId()); + SqlInfo sqlInfo=new SqlInfo(); + sqlInfo.setInnnerId(mdWithInnerIdTemp.getInnnerId()); + sqlInfo.setMarkdownDTO(mdWithInnerIdTemp.getMarkdownDTO()); + sqlInfo.setSql(sql); + return sqlInfo; + } + public static MdWithInnerIdTemp loadConfigData(String sqlId,boolean needReadMdLastModified) { + MdWithInnerIdTemp mdWithInnerIdTemp=new MdWithInnerIdTemp(); + if(sqlId.startsWith(ConstantJdbc.ISSQLFLAG)){ + MarkdownDTO markdownDTO= new MarkdownDTO(); + markdownDTO.setId(ConstantJdbc.MAINFLAG+"_"+ StringUtils.uuid()); + Map map=new HashMap<>(); + String sql=sqlId.substring(ConstantJdbc.ISSQLFLAG.length()); + if(sqlId.endsWith(ConstantJdbc.COUNTFLAG)){ + sql=null; + } + map.put(ConstantJdbc.MAINFLAG,sql); + markdownDTO.setContentMap(map); + String innerId=ConstantJdbc.MAINFLAG; + if(sqlId.endsWith(ConstantJdbc.COUNTFLAG)){ + innerId="main"+ConstantJdbc.COUNTFLAG; + } + mdWithInnerIdTemp.setInnnerId(innerId); + mdWithInnerIdTemp.setMarkdownDTO(markdownDTO); + return mdWithInnerIdTemp; + } + if(sqlId.startsWith(ConstantJdbc.ISMDFLAG)){ + MarkdownDTO markdownDTO= MarkdownUtil.readMarkdown(sqlId.substring(ConstantJdbc.ISMDFLAG.length()),null,null); + mdWithInnerIdTemp.setInnnerId(ConstantJdbc.MAINFLAG); + mdWithInnerIdTemp.setMarkdownDTO(markdownDTO); + return mdWithInnerIdTemp; + } + + String[] sqlIds = StringUtils.split(sqlId, "."); + if (sqlIds.length < 2) { + throw new MybatisMinRuntimeException("error config id:"+sqlId); + } + StringBuilder packageName = new StringBuilder(); + for (int i = 0; i < sqlIds.length - 2; i++) { + packageName.append(sqlIds[i]).append("."); + } + String fileName=sqlIds[sqlIds.length - 2] + ".md"; + String needFindId=sqlIds[sqlIds.length - 1]; + MarkdownDTO markdownDTO= MarkdownUtil.readMarkdownFile(packageName.substring(0,packageName.length()-1),fileName,needReadMdLastModified); + mdWithInnerIdTemp.setInnnerId(needFindId); + mdWithInnerIdTemp.setMarkdownDTO(markdownDTO); + return mdWithInnerIdTemp; + } + public static String initStringMd(String md){ + return initStringMd(md,StringUtils.uuid(),ConstantJdbc.MDINITVERSION); + } + public static String initStringMd(String md,String id,String version){ + if(!md.contains(ConstantJdbc.MDVERSION)){ + md=ConstantJdbc.MDVERSION+" "+version+" \n"+md; + } + if(!md.contains(ConstantJdbc.MDID)){ + md=ConstantJdbc.MDID+" "+id + "\n"+md; + } + if(!md.startsWith(ConstantJdbc.ISMDFLAG)){ + md=ConstantJdbc.ISMDFLAG+md; + } + return md; + } + public static String initSqlInSqlId(String sqlId){ + if(!sqlId.startsWith(ConstantJdbc.ISSQLFLAG)){ + return ConstantJdbc.ISSQLFLAG+sqlId; + } + return sqlId; + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/JoinTable.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/JoinTable.java new file mode 100644 index 0000000000000000000000000000000000000000..f7d74643fedbe81fd9b48f01275ce6883083156c --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/JoinTable.java @@ -0,0 +1,44 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown.bean; + +/** + * @author 冯昌义 + * 2017/12/5. + */ +public class JoinTable { + private String sql; + private String tables; + private String views; + private String js; + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public String getTables() { + return tables; + } + + public void setTables(String tables) { + this.tables = tables; + } + + public String getViews() { + return views; + } + + public void setViews(String views) { + this.views = views; + } + + public String getJs() { + return js; + } + + public void setJs(String js) { + this.js = js; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/MdWithInnerIdTemp.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/MdWithInnerIdTemp.java new file mode 100644 index 0000000000000000000000000000000000000000..a836fe9160c3ba995910c55302212c3903c5a1cf --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/MdWithInnerIdTemp.java @@ -0,0 +1,29 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown.bean; + + +import com.vonchange.jdbc.abstractjdbc.util.markdown.MarkdownDTO; + +/** + * @author 冯昌义 + * 2017/12/14. + */ +public class MdWithInnerIdTemp { + private String innnerId; + private MarkdownDTO markdownDTO; + + public String getInnnerId() { + return innnerId; + } + + public void setInnnerId(String innnerId) { + this.innnerId = innnerId; + } + + public MarkdownDTO getMarkdownDTO() { + return markdownDTO; + } + + public void setMarkdownDTO(MarkdownDTO markdownDTO) { + this.markdownDTO = markdownDTO; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/MemTable.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/MemTable.java new file mode 100644 index 0000000000000000000000000000000000000000..90b50b0ebba61add62e9d5a8062424c7287abb8e --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/MemTable.java @@ -0,0 +1,28 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown.bean; + +import java.util.Map; + +/** + * @author 冯昌义 + * 2017/12/5. + */ +public class MemTable { + private Map info; + private String sql; + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public Map getInfo() { + return info; + } + + public void setInfo(Map info) { + this.info = info; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/SqlInfo.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/SqlInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..b12859f77ff1c725cb3a6a93feb406c304c82ed3 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/markdown/bean/SqlInfo.java @@ -0,0 +1,45 @@ +package com.vonchange.jdbc.abstractjdbc.util.markdown.bean; + +import com.vonchange.jdbc.abstractjdbc.util.markdown.MarkdownDTO; + +/** + * Created by 冯昌义 on 2018/1/22. + */ +public class SqlInfo { + private String sqlId; + private String sql; + private String innnerId; + private MarkdownDTO markdownDTO; + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public String getInnnerId() { + return innnerId; + } + + public void setInnnerId(String innnerId) { + this.innnerId = innnerId; + } + + public MarkdownDTO getMarkdownDTO() { + return markdownDTO; + } + + public void setMarkdownDTO(MarkdownDTO markdownDTO) { + this.markdownDTO = markdownDTO; + } + + public String getSqlId() { + return sqlId; + } + + public void setSqlId(String sqlId) { + this.sqlId = sqlId; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/sql/AbstractSqlDialectUtil.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/sql/AbstractSqlDialectUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..34367e146455da2c25b389528f8eb1e5a288e9c1 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/sql/AbstractSqlDialectUtil.java @@ -0,0 +1,35 @@ +package com.vonchange.jdbc.abstractjdbc.util.sql; + +import com.vonchange.jdbc.abstractjdbc.config.ConstantJdbc; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.dialect.MySQLDialect; +import com.vonchange.mybatis.dialect.OracleDialect; + + +/** + * Created by 冯昌义 on 2018/4/17. + */ +public abstract class AbstractSqlDialectUtil { + protected abstract Dialect getDefaultDialect(); + protected abstract String getDataSource(); + public Dialect getDialect(String sql){ + if(sql.contains("@mysql")){ + return new MySQLDialect(); + } + if(sql.contains("@oracle")){ + return new OracleDialect(); + } + return getDefaultDialect(); + } + public String getDataSource(String sql){ + if(sql.contains(ConstantJdbc.DataSource.FLAG)){ + int start=sql.indexOf(ConstantJdbc.DataSource.FLAG); + int end = sql.indexOf(' ',start+ConstantJdbc.DataSource.FLAG.length()); + return sql.substring(start+ConstantJdbc.DataSource.FLAG.length(),end); + } + if(null==getDataSource()){ + return ConstantJdbc.DataSource.DEFAULT; + } + return getDataSource(); + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/sql/SqlFill.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/sql/SqlFill.java new file mode 100644 index 0000000000000000000000000000000000000000..1f9af613f9abfbc307c3d44b14254f0912677fce --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/abstractjdbc/util/sql/SqlFill.java @@ -0,0 +1,64 @@ +package com.vonchange.jdbc.abstractjdbc.util.sql; + + +import com.vonchange.common.util.time.TimeUtil; + +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.util.Date; + +/** + * 填充sql + * + * @author von_change@163.com + * 2016年4月6日 下午6:07:00 + * @since 1.0 + */ +public class SqlFill { + private SqlFill() { + throw new IllegalStateException("Utility class"); + } + + private static String getParameterValue(Object obj) { + if (null == obj) { + return "NULL"; + } + if (obj instanceof String||obj.getClass().isEnum()) { + // 排除恶意sql漏洞 + //return "'" + obj.toString().replaceAll("([';])+|(--)+", "") + "'"; + return "'" + obj.toString() + "'"; + } + if (obj instanceof Date) { + return "'"+ TimeUtil.fromDate((Date) obj).toString()+"'"; + //return "'" + DateFormatUtils.format((Date) obj, FORMAT) + "'"; + } + if(obj instanceof LocalDateTime|| obj instanceof LocalDate || obj instanceof LocalTime){ + return "'"+obj.toString()+"'"; + } + return obj.toString(); + } + + public static String fill(String source, Object[] params) { + if (null == params || params.length == 0) { + return source; + } + //[ \x0B]+ "[\s]+ + String sql = source.replaceAll("[ \\x0B]+", " ");//去掉多余空格 + char[] chars = sql.toCharArray(); + StringBuilder sb = new StringBuilder(); + char j; + int p = 0; + for (int i = 0; i < chars.length; i++) { + j = chars[i]; + if (j == '?') { + sb.append(getParameterValue(params[p]));// + p++; + } else { + sb.append(j); + } + } + return sb.toString(); + } + +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/springjdbc/repository/AbstractJbdcRepositoryMysql.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/springjdbc/repository/AbstractJbdcRepositoryMysql.java new file mode 100644 index 0000000000000000000000000000000000000000..bcdcb8e801b84e5f18dbdc64e480c185b2128e94 --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/springjdbc/repository/AbstractJbdcRepositoryMysql.java @@ -0,0 +1,29 @@ +package com.vonchange.jdbc.springjdbc.repository; + + +import com.vonchange.jdbc.abstractjdbc.core.AbstractJdbcCore; +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.dialect.MySQLDialect; + +public abstract class AbstractJbdcRepositoryMysql extends AbstractJdbcCore { + + @Override + protected Dialect getDefaultDialect() { + return new MySQLDialect(); + } + + @Override + protected DataSourceWrapper getDataSourceFromSql(String sql){ + return null; + } + + + protected boolean readAllScopeOpen(){ + return false; + } + @Override + protected boolean needReadMdLastModified() { + return false; + } +} diff --git a/mybatis-mini/src/main/java/com/vonchange/jdbc/springjdbc/repository/JdbcRepositoryBaseImpl.java b/mybatis-mini/src/main/java/com/vonchange/jdbc/springjdbc/repository/JdbcRepositoryBaseImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..47b2dbf2e47bd6adbfc0fdb32bf06f542cb5b97c --- /dev/null +++ b/mybatis-mini/src/main/java/com/vonchange/jdbc/springjdbc/repository/JdbcRepositoryBaseImpl.java @@ -0,0 +1,47 @@ +package com.vonchange.jdbc.springjdbc.repository; + +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; + +import javax.sql.DataSource; + + +public class JdbcRepositoryBaseImpl extends AbstractJbdcRepositoryMysql implements JdbcRepository { + private DataSource dataSource; + public JdbcRepositoryBaseImpl(DataSource dataSource){ + this.dataSource=dataSource; + } + @Override + public DataSourceWrapper getReadDataSource() { + return new DataSourceWrapper(dataSource,"dataSource"); + } + + @Override + protected DataSourceWrapper getWriteDataSource() { + return new DataSourceWrapper(dataSource,"dataSource"); + } + + @Override + protected int batchSize() { + return 5000; + } + + @Override + protected boolean logRead() { + return false; + } + + @Override + protected boolean logWrite() { + return false; + } + + @Override + protected boolean logFullSql() { + return false; + } + + + + +} diff --git a/mybatis-sql-extend-test/pom.xml b/mybatis-sql-extend-test/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..988910231791200b3004eee5f1d779a8997b9b78 --- /dev/null +++ b/mybatis-sql-extend-test/pom.xml @@ -0,0 +1,124 @@ + + + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + 4.0.0 + com.vonchange.common + + mybatis-sql-extend-test + 2.3.9 + + 2.3.9 + + 8.0.15 + + + + com.vonchange.common + mybatis-sql-extend + ${spring.mybatis.mini} + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.boot + spring-boot-starter-web + + + + mysql + mysql-connector-java + runtime + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 2.1.4 + + + mysql + mysql-connector-java + 8.0.16 + + + + com.h2database + h2 + 1.4.200 + + + + + + aliyun-repos + Aliyun Repository + http://maven.aliyun.com/nexus/content/groups/public + + true + + + false + + + + sonatype-repos + Sonatype Repository + https://oss.sonatype.org/content/groups/public + + true + + + false + + + + sonatype-repos-s + Sonatype Repository + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + false + + + + org.springframework.boot + spring-boot-maven-plugin + + + + \ No newline at end of file diff --git a/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/DemoApplication.java b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/DemoApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..6b4fbef1326cce2ba40a7a7d680e33ec7df5ad49 --- /dev/null +++ b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/DemoApplication.java @@ -0,0 +1,16 @@ +package com.vonchange.mybatis; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +//@SpringBootApplication(exclude={JdbcConfiguration.class}) +@SpringBootApplication +//@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) +public class DemoApplication { + + public static void main(String[] args) { + + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/SimpleLanguageDriver.java b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/SimpleLanguageDriver.java new file mode 100644 index 0000000000000000000000000000000000000000..8722542d8603bc0298677c8c057a21d93c439225 --- /dev/null +++ b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/SimpleLanguageDriver.java @@ -0,0 +1,19 @@ +package com.vonchange.mybatis.test.config; + + +import com.vonchange.mybatis.dialect.MySQLDialect; +import com.vonchange.mybatis.language.MybatisSqlLanguageUtil; +import org.apache.ibatis.mapping.SqlSource; +import org.apache.ibatis.scripting.LanguageDriver; +import org.apache.ibatis.scripting.xmltags.XMLLanguageDriver; +import org.apache.ibatis.session.Configuration; + +public class SimpleLanguageDriver extends XMLLanguageDriver implements LanguageDriver { + + @Override + public SqlSource createSqlSource(Configuration configuration, String script, Class parameterType) { + + String sqlInXml = MybatisSqlLanguageUtil.sqlInXml("mapper",script,new MySQLDialect()); + return super.createSqlSource(configuration, sqlInXml, parameterType); + } +} diff --git a/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/UserBaseDO.java b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/UserBaseDO.java new file mode 100644 index 0000000000000000000000000000000000000000..4d0be9310e53057bf946e65d0100845ec83defcc --- /dev/null +++ b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/UserBaseDO.java @@ -0,0 +1,40 @@ +package com.vonchange.mybatis.test.config; + + + + +import lombok.AllArgsConstructor; +import lombok.Data; + + +import java.time.LocalDateTime; +import java.util.Date; + +@Data +@AllArgsConstructor +public class UserBaseDO { + + + private Long id; + + private String code; + + private String userName; + private String mobilePhone; + + private Integer isDelete; + + private LocalDateTime createTime; + //@UpdateDuplicateKeyIgnore + + private Date updateTime; + + private byte[] headImageData; + public UserBaseDO(){ + + } + + + + +} diff --git a/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/UserMapper.java b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/UserMapper.java new file mode 100644 index 0000000000000000000000000000000000000000..a9dc0e219447077447b04069c445e3b5d5d16dec --- /dev/null +++ b/mybatis-sql-extend-test/src/main/java/com/vonchange/mybatis/test/config/UserMapper.java @@ -0,0 +1,16 @@ +package com.vonchange.mybatis.test.config; + +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; +import org.apache.ibatis.annotations.Select; + +import java.time.LocalDateTime; +import java.util.List; + +@Mapper +public interface UserMapper { + + @Select("@UserMapper.findList") + List findList(@Param("userName") String userName, + @Param("createTime") LocalDateTime createTime); +} diff --git a/mybatis-sql-extend-test/src/main/resources/application.yml b/mybatis-sql-extend-test/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..431a361a2c60e3bcea466009541b229fd872b37f --- /dev/null +++ b/mybatis-sql-extend-test/src/main/resources/application.yml @@ -0,0 +1,37 @@ +spring: + profiles: + active: local + application: + name: demo + datasource: + hikari: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/nine_user?autoReconnect=true&rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT + username: root + password: 123456 + connection-timeout: 20000 + minimum-idle: 5 + maximum-pool-size: 20 + idle-timeout: 60000 + max-lifetime: 600000 + leak-detection-threshold: 20000 + +mybatis: + default-scripting-language-driver: com.vonchange.mybatis.test.config.SimpleLanguageDriver + configuration: + map-underscore-to-camel-case: true + + + + +logback: + aliyun: + endpoint: cn-hangzhou.log.aliyuncs.com + + + + + + + + diff --git a/mybatis-sql-extend-test/src/main/resources/mapper/UserMapper.md b/mybatis-sql-extend-test/src/main/resources/mapper/UserMapper.md new file mode 100644 index 0000000000000000000000000000000000000000..5ae52786ee56f04432a58b0b8e9ac5788faae0fc --- /dev/null +++ b/mybatis-sql-extend-test/src/main/resources/mapper/UserMapper.md @@ -0,0 +1,14 @@ +``` +-- findList +select * from user_base +[@sql findListWhereSql] +``` + +> sql 片段 +``` +-- findListWhereSql + +[@@and user_name like userName] +[@and create_time < createTime] + +``` \ No newline at end of file diff --git a/mybatis-sql-extend-test/src/test/java/com/vonchange/mybatis/test/DemoApplicationTests.java b/mybatis-sql-extend-test/src/test/java/com/vonchange/mybatis/test/DemoApplicationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..3ac114bbdbabc631233225ba13bce46fabd1fd20 --- /dev/null +++ b/mybatis-sql-extend-test/src/test/java/com/vonchange/mybatis/test/DemoApplicationTests.java @@ -0,0 +1,16 @@ +package com.vonchange.mybatis.test; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class DemoApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/mybatis-sql-extend-test/src/test/java/com/vonchange/mybatis/test/MybatisSqlExtendTest.java b/mybatis-sql-extend-test/src/test/java/com/vonchange/mybatis/test/MybatisSqlExtendTest.java new file mode 100644 index 0000000000000000000000000000000000000000..7515f9a240518842cee08bb8029c79bacf1b3f85 --- /dev/null +++ b/mybatis-sql-extend-test/src/test/java/com/vonchange/mybatis/test/MybatisSqlExtendTest.java @@ -0,0 +1,31 @@ +package com.vonchange.mybatis.test; + +import com.vonchange.common.util.JsonUtil; +import com.vonchange.mybatis.test.config.UserBaseDO; +import com.vonchange.mybatis.test.config.UserMapper; +import lombok.extern.slf4j.Slf4j; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.time.LocalDateTime; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +@Slf4j +public class MybatisSqlExtendTest { + + @Resource + private UserMapper userMapper; + + @Test + public void sqlExtendTest(){ + List userBaseDOList = userMapper.findList("test", LocalDateTime.now().plusHours(1L)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}", JsonUtil.toJson(userBaseDO)); + }); + } +} diff --git a/mybatis-sql-extend/pom.xml b/mybatis-sql-extend/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..973372022ae25b64ad4243017653d0c9a7181701 --- /dev/null +++ b/mybatis-sql-extend/pom.xml @@ -0,0 +1,33 @@ + + + + mybatis-mini-parant + com.vonchange.common + 2.3.9 + + 4.0.0 + mybatis-sql-extend + 2.3.9 + + + ch.qos.logback + logback-classic + 1.2.3 + + + + com.vonchange.common + common-util + 2.3.9 + + + org.springframework + spring-core + 5.1.5.RELEASE + provided + + + + \ No newline at end of file diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/config/Constant.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/config/Constant.java new file mode 100644 index 0000000000000000000000000000000000000000..f1cdd61bf37f6a666c2c954a3534122ff3504bd1 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/config/Constant.java @@ -0,0 +1,35 @@ +package com.vonchange.mybatis.config; + +import com.vonchange.common.util.bean.BeanUtil; + +public class Constant { + private Constant(){ + throw new IllegalStateException("Utility class"); + } + public static final BeanUtil BeanUtil= new BeanUtil(); + public static final String PARAM_NOT_NULL="Parameter name must not be null"; + public static final String NOLOWER = "@-lower"; + public static final String NOORM = "@-orm"; + public static class Dialog{ + public static final String MYSQL = "mysql"; + public static final String ORACLE = "oracle"; + } + public static class PageParam{ + public static final String COUNT = "_count"; + public static final String AT = "@"; + } + public static final String ISSQLFLAG= "@sql"; + public static final String ISMDFLAG= "@md"; + public static final String MAINFLAG= "main"; + public static final String MDID= "### id"; + public static final String MDVERSION= "#### version"; + public static final String MDINITVERSION= "1.0"; + public static class DataSource{ + public static final String DEFAULT = "dataSource"; + public static final String FLAG = "@ds:"; + } + public static final String COUNTFLAG = "Count"; + public static final String MAPFIELDSPLIT = "#"; + public static final String TABLES = "tables"; + public static final String IDPREF = "--"; +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/Dialect.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/Dialect.java new file mode 100644 index 0000000000000000000000000000000000000000..4be500de8dbdae45b0c685b036813dc30bcdc367 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/Dialect.java @@ -0,0 +1,22 @@ +package com.vonchange.mybatis.dialect; + + +/** + *方言接口 + * @author von_change@163.com + * 2015-6-14 下午12:46:50 + */ +public interface Dialect { + + /** + * 获取分页的sql + * @param sql 要分页sql + * @param beginNo 开始数 + * @return 分页sql + */ + String getPageSql(String sql, int beginNo, int pageSize); + int getBigDataFetchSize(); + int getFetchSize(); + String getDialogName(); + LikeTemplate getLikeTemplate(); +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/DialectType.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/DialectType.java new file mode 100644 index 0000000000000000000000000000000000000000..39ae6ca8bcd7c8994a98d812f529f050819e3b69 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/DialectType.java @@ -0,0 +1,12 @@ +package com.vonchange.mybatis.dialect; + +/** + * 方言类型 + * @author von_change@163.com + *2015-6-14 下午12:47:10 + */ +public enum DialectType { + + ORACLE,MYSQL,POSTGRE,H2,SPARK_SQL + +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/LikeTemplate.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/LikeTemplate.java new file mode 100644 index 0000000000000000000000000000000000000000..bba4662dcc19aa46ccb170861d5f12c004e2b096 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/LikeTemplate.java @@ -0,0 +1,37 @@ +package com.vonchange.mybatis.dialect; + +public class LikeTemplate { + private String full; + private String left; + private String right; + + public LikeTemplate(String full, String left, String right) { + this.full = full; + this.left = left; + this.right = right; + } + + public String getFull() { + return full; + } + + public void setFull(String full) { + this.full = full; + } + + public String getLeft() { + return left; + } + + public void setLeft(String left) { + this.left = left; + } + + public String getRight() { + return right; + } + + public void setRight(String right) { + this.right = right; + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/MySQLDialect.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/MySQLDialect.java new file mode 100644 index 0000000000000000000000000000000000000000..bfa6e43b0280664b8530889e7f7c94f0b4a1c6ae --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/MySQLDialect.java @@ -0,0 +1,42 @@ +package com.vonchange.mybatis.dialect; + + +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.config.Constant; + + +/** + *mysql方言 + * @author von_change@163.com + * 2015-6-14 下午12:47:21 + */ +public class MySQLDialect implements Dialect { + + @Override + public String getPageSql(String sql, int beginNo, int pageSize) { + return StringUtils.format("{0} limit {1},{2} ", sql, ConvertUtil.toString(beginNo), ConvertUtil.toString(pageSize)); + } + + + + @Override + public int getBigDataFetchSize() { + return Integer.MIN_VALUE; + } + + @Override + public int getFetchSize() { + return -1; + } + + @Override + public String getDialogName() { + return Constant.Dialog.MYSQL; + } + + @Override + public LikeTemplate getLikeTemplate() { + return new LikeTemplate(" CONCAT(''%'',#'{'{0}'}',''%'') "," CONCAT(''%'',#'{'{0}'}')"," CONCAT(#'{'{0}'}',''%'') "); + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/OracleDialect.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/OracleDialect.java new file mode 100644 index 0000000000000000000000000000000000000000..fbc632c7194aef3c47ef1bd3b15bbd18a4cbeb24 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/dialect/OracleDialect.java @@ -0,0 +1,46 @@ +package com.vonchange.mybatis.dialect; + + +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.config.Constant; + + +/** + * + * Created by 冯昌义 on 2018/4/16. + */ +public class OracleDialect implements Dialect { + @Override + public String getPageSql(String sql, int beginNo, int pageSize) { + if(beginNo==0){ + String sqlLimit="{0}" + + " fetch first {1} rows only" ; + return StringUtils.format(sqlLimit, sql, ConvertUtil.toString(pageSize)); + } + String sqlOrg="{0}" + + " offset {1} rows fetch next {2} rows only " ; + return StringUtils.format(sqlOrg, sql, ConvertUtil.toString(beginNo), ConvertUtil.toString(pageSize)); + } + + + @Override + public int getBigDataFetchSize() { + return 500; + } + + @Override + public int getFetchSize() { + return 500; + } + + @Override + public String getDialogName() { + return Constant.Dialog.ORACLE; + } + + @Override + public LikeTemplate getLikeTemplate() { + return new LikeTemplate(" ''%''||#'{'{0}'}'||''%'' "," ''%''||#'{'{0}'}' "," #'{'{0}'}'||''%'' "); + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/exception/MybatisMinRuntimeException.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/exception/MybatisMinRuntimeException.java new file mode 100644 index 0000000000000000000000000000000000000000..324bd6096ee52bae19519112b17e7c14a05f0201 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/exception/MybatisMinRuntimeException.java @@ -0,0 +1,25 @@ +package com.vonchange.mybatis.exception; + + + +/** + *自定义RuntimeException + * @author von_change@163.com + */ +public class MybatisMinRuntimeException extends NestedRuntimeException { + + public MybatisMinRuntimeException(String msg) { + super(msg); + } + public static MybatisMinRuntimeException instance(Object... msg) { + StringBuilder sb = new StringBuilder(); + for (Object object : msg) { + sb.append(String.valueOf(object)); + } + String msgStr=sb.toString(); + return new MybatisMinRuntimeException(msgStr); + } + + private static final long serialVersionUID = 1L; + +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/exception/NestedRuntimeException.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/exception/NestedRuntimeException.java new file mode 100644 index 0000000000000000000000000000000000000000..1f46d309c847c01f85d53730d8f270383aba658a --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/exception/NestedRuntimeException.java @@ -0,0 +1,122 @@ +/* + * Copyright 2002-2018 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.vonchange.mybatis.exception; + + +import com.vonchange.common.util.NestedExceptionUtils; + +public abstract class NestedRuntimeException extends RuntimeException { + + /** Use serialVersionUID from Spring 1.2 for interoperability. */ + private static final long serialVersionUID = 5439915454935047936L; + + static { + // Eagerly load the NestedExceptionUtils class to avoid classloader deadlock + // issues on OSGi when calling getMessage(). Reported by Don Brown; SPR-5607. + NestedExceptionUtils.class.getName(); + } + + + /** + * Construct a {@code NestedRuntimeException} with the specified detail message. + * @param msg the detail message + */ + public NestedRuntimeException(String msg) { + super(msg); + } + + /** + * Construct a {@code NestedRuntimeException} with the specified detail message + * and nested exception. + * @param msg the detail message + * @param cause the nested exception + */ + public NestedRuntimeException( String msg, Throwable cause) { + super(msg, cause); + } + + + /** + * Return the detail message, including the message from the nested exception + * if there is one. + */ + @Override + + public String getMessage() { + return NestedExceptionUtils.buildMessage(super.getMessage(), getCause()); + } + + + /** + * Retrieve the innermost cause of this exception, if any. + * @return the innermost exception, or {@code null} if none + * @since 2.0 + */ + + public Throwable getRootCause() { + return NestedExceptionUtils.getRootCause(this); + } + + /** + * Retrieve the most specific cause of this exception, that is, + * either the innermost cause (root cause) or this exception itself. + *

Differs from {@link #getRootCause()} in that it falls back + * to the present exception if there is no root cause. + * @return the most specific cause (never {@code null}) + * @since 2.0.3 + */ + public Throwable getMostSpecificCause() { + Throwable rootCause = getRootCause(); + return (rootCause != null ? rootCause : this); + } + + /** + * Check whether this exception contains an exception of the given type: + * either it is of the given class itself or it contains a nested cause + * of the given type. + * @param exType the exception type to look for + * @return whether there is a nested exception of the specified type + */ + public boolean contains( Class exType) { + if (exType == null) { + return false; + } + if (exType.isInstance(this)) { + return true; + } + Throwable cause = getCause(); + if (cause == this) { + return false; + } + if (cause instanceof NestedRuntimeException) { + return ((NestedRuntimeException) cause).contains(exType); + } + else { + while (cause != null) { + if (exType.isInstance(cause)) { + return true; + } + if (cause.getCause() == cause) { + break; + } + cause = cause.getCause(); + } + return false; + } + } + +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/language/MybatisSqlLanguageUtil.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/language/MybatisSqlLanguageUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..0d4298a26dc0283fda6834f13ce57491e2e368aa --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/language/MybatisSqlLanguageUtil.java @@ -0,0 +1,32 @@ +package com.vonchange.mybatis.language; + +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.markdown.MarkdownUtil; +import com.vonchange.mybatis.sql.DynamicSql; + + +public class MybatisSqlLanguageUtil { + /** + * + * @param prePackage 前缀报名 比如mapper + * @param script sqlInXml + * @param dialect 方言 + */ + public static String sqlInXml(String prePackage,String script, Dialect dialect){ + String sqlInXml = script; + if (script.startsWith("@")) { + String sqlId = script.substring(1); + sqlInXml = MarkdownUtil.getSql(null==prePackage?sqlId:(prePackage+"."+sqlId)); + sqlInXml = DynamicSql.dynamicSql(sqlInXml, dialect); + sqlInXml = sqlInXml.trim(); + if (sqlInXml.contains("" + sqlInXml + ""; + sqlInXml = StringUtils.replaceEach(sqlInXml, new String[]{" > ", " < ", " >= ", " <= ", " <> "}, + new String[]{" > ", " < ", " >= ", " <= ", " <> "}); + } + } + return sqlInXml; + } + +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/FileUtils.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/FileUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..46664d59c1354d3046c290fd3c1d3d7391fda291 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/FileUtils.java @@ -0,0 +1,44 @@ +package com.vonchange.mybatis.markdown; + +import org.springframework.core.io.Resource; +import org.springframework.core.io.support.PathMatchingResourcePatternResolver; + +public class FileUtils { + private FileUtils() { + throw new IllegalStateException("Utility class"); + } + private static final String ENCODING = "UTF-8"; + private static final String URLSEPARATOR="/"; + public static String getEncoding() { + return ENCODING; + } + public static String getFileURLPath(String packageName, String name) { + String path = packageName.replaceAll("\\.", URLSEPARATOR); + return path + URLSEPARATOR+ name; + } + + + + + /** + * 取指定文件的扩展名 + * @param filePathName + * 文件路径 + * @return 扩展名 + */ + public static String getFileExt(String filePathName) { + int pos = 0; + pos = filePathName.lastIndexOf('.'); + if (pos != -1) + return filePathName.substring(pos + 1, filePathName.length()); + else + return ""; + } + //classpath:com/test/a.md + public static Resource getResource(String location){ + PathMatchingResourcePatternResolver patternResolver = new PathMatchingResourcePatternResolver(); + return patternResolver.getResource(location); + } + + +} \ No newline at end of file diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownDTO.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownDTO.java new file mode 100644 index 0000000000000000000000000000000000000000..e28b68366e354522584da21a0f4b6b33fc538659 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownDTO.java @@ -0,0 +1,45 @@ +package com.vonchange.mybatis.markdown; + +import java.util.HashMap; +import java.util.Map; + + +public class MarkdownDTO { + private String id;//文件或整个文档ID + private String version;//版本号 + private Map contentMap=new HashMap<>(); + private Map> jsonMap=new HashMap<>(); + + public String getVersion() { + return version; + } + + public void setVersion(String version) { + this.version = version; + } + + public Map getContentMap() { + return contentMap; + } + + public void setContentMap(Map contentMap) { + this.contentMap = contentMap; + } + + public Map> getJsonMap() { + return jsonMap; + } + + public void setJsonMap(Map> jsonMap) { + this.jsonMap = jsonMap; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownDataUtil.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownDataUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..2f640dec2bb593d2c60593f7f20fdca4a86e9d79 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownDataUtil.java @@ -0,0 +1,21 @@ +package com.vonchange.mybatis.markdown; + + +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; + + +public class MarkdownDataUtil{ + private MarkdownDataUtil() { + throw new IllegalStateException("Utility class"); + } + public static final String COUNTFLAG = "Count"; + public static String getSql(MarkdownDTO markdownDTO,String id) { + String sql =markdownDTO.getContentMap().get(id); + if(StringUtils.isBlank(sql)&&!StringUtils.endsWith(id, COUNTFLAG)){ + throw new MybatisMinRuntimeException(markdownDTO.getId()+" can not find id:"+id); + } + /* 支持[@sql */ + return MarkdownUtil.getSqlSpinner(markdownDTO,sql); + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownUtil.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..5ca9dde5756d92652dadd020566a10d118400fe5 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/MarkdownUtil.java @@ -0,0 +1,286 @@ +package com.vonchange.mybatis.markdown; + + +import com.vonchange.common.util.FileUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.config.Constant; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; +import com.vonchange.mybatis.markdown.bean.MdWithInnerIdTemp; +import com.vonchange.mybatis.markdown.bean.SqlInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.core.io.Resource; + +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * markdown 组件 + * von_change + */ +public class MarkdownUtil { + private MarkdownUtil(){ + throw new IllegalStateException("Utility class"); + } + private static Logger logger = LoggerFactory.getLogger(MarkdownUtil.class); + private static Map idMarkdownMap=new ConcurrentHashMap<>(); + + + public static boolean markdownFileExist(String packageName,String fileName){ + String url= "classpath:"+FileUtils.getFileURLPath(packageName,fileName); + Resource resource= FileUtils.getResource(url); + return resource.exists(); + } + public static MarkdownDTO readMarkdownFile(String packageName,String fileName,boolean needReadMdLastModified){ + String id = packageName+"."+fileName; + if(!needReadMdLastModified&&idMarkdownMap.containsKey(id)){ + return idMarkdownMap.get(id); + } + String url= "classpath:"+FileUtils.getFileURLPath(packageName,fileName); + Resource resource= FileUtils.getResource(url); + long lastModified; + try { + lastModified= resource.lastModified(); + if(lastModified==0){ + return null; + } + } catch (IOException e) { + logger.error("read markdown file error {}",url); + throw new MybatisMinRuntimeException("read markdown file error "+url); + } + boolean needLoad=true; + if(idMarkdownMap.containsKey(id)){ + MarkdownDTO markdownDTO=idMarkdownMap.get(id); + if((lastModified+"").equals(markdownDTO.getVersion())){ + needLoad=false; + } + } + if(!needLoad){ + return idMarkdownMap.get(id); + } + String content=null; + try { + content= FileUtil.readUTFString(resource.getInputStream()); + } catch (IOException e) { + logger.error("读取markdown文件出错{}:{}",url,e); + } + MarkdownDTO markdownDTO= getMarkDownInfo(content,id,lastModified+""); + idMarkdownMap.put(id,markdownDTO); + return markdownDTO; + } + private static MarkdownDTO readMarkdown(String content,String id,String version){ + if(null==id||"".equals(id.trim())){ + id=getId(content); + } + if(null==version||"".equals(version.trim())){ + version=getVersion(content); + } + boolean needLoad=true; + if(null!=idMarkdownMap.get(id)){ + MarkdownDTO markdownDTO=idMarkdownMap.get(id); + if((version).equals(markdownDTO.getVersion())){ + needLoad=false; + } + } + if(!needLoad){ + return idMarkdownMap.get(id); + } + MarkdownDTO markdownDTO= getMarkDownInfo(content,id,version); + idMarkdownMap.put(id,markdownDTO); + return markdownDTO; + } + private static String getId(String result){ + String idSym= Constant.MDID; + int vdx = result.indexOf(idSym); + if(vdx == -1) { + throw new IllegalArgumentException("无"+Constant.MDID); + } + StringBuilder idSB=new StringBuilder(); + for(int j=vdx+idSB.length();result.charAt(j)!='\n';j++){ + idSB.append(result.charAt(j)); + } + return idSB.toString(); + } + private static String getVersion(String result){ + String versionSym=Constant.MDVERSION; + int vdx = result.indexOf(versionSym); + if(vdx == -1) { + throw new IllegalArgumentException("无"+Constant.MDVERSION); + } + StringBuilder versionSB=new StringBuilder(); + for(int j=vdx+versionSym.length();result.charAt(j)!='\n';j++){ + versionSB.append(result.charAt(j)); + } + return versionSB.toString(); + } + + private static MarkdownDTO getMarkDownInfo(String result,String id,String version){ + MarkdownDTO markdownDTO= new MarkdownDTO(); + String scriptSym="```"; + if(null==id||"".equals(id.trim())){ + markdownDTO.setId(getId(result)); + }else{ + markdownDTO.setId(id); + } + if(null==version||"".equals(version.trim())){ + markdownDTO.setVersion(getVersion(result)); + }else{ + markdownDTO.setVersion(version); + } + int i=0; + int len = result.length(); + int startLen=scriptSym.length(); + int endLen=scriptSym.length(); + StringBuilder idSB; + while (i < len) { + int ndx = result.indexOf(scriptSym, i); + if(ndx==-1){ + break; + } + ndx += startLen; + idSB=new StringBuilder(); + for(int j=ndx;result.charAt(j)!='\n';j++){ + idSB.append(result.charAt(j)); + } + int firstLineLength=idSB.length(); + idSB=new StringBuilder(); + for(int j=ndx+firstLineLength+1;result.charAt(j)!='\n';j++){ + idSB.append(result.charAt(j)); + } + int zsIndex= idSB.indexOf(Constant.IDPREF); + if(zsIndex==-1){ + throw new IllegalArgumentException("无id注释"+idSB); + } + String key= idSB.substring(zsIndex+Constant.IDPREF.length()).trim(); + if(key.length()==0){ + throw new IllegalArgumentException("请定义类型和ID at "+ndx); + } + ndx += idSB.length()+firstLineLength+1; + int ndx2 = result.indexOf(scriptSym, ndx); + if(ndx2 == -1) { + throw new IllegalArgumentException("无结尾 ``` 符号 at: " + (ndx - startLen)); + } + String content=result.substring(ndx,ndx2).trim(); + markdownDTO.getContentMap().put(key,content); + i=ndx2+endLen; + } + return markdownDTO; + } + public static String getSqlSpinner(MarkdownDTO markdownDTO,String sql){ + if(StringUtils.isBlank(sql)){ + return sql; + } + if(!sql.contains("[@sql")){ + return sql; + } + String startSym="[@sql"; + String endSym="]"; + int len = sql.length(); + int startLen=startSym.length(); + int endLen=endSym.length(); + int i=0; + StringBuilder newSb=new StringBuilder(); + String model; + while (i < len) { + int ndx = sql.indexOf(startSym, i); + if(ndx==-1){ + newSb.append(i == 0?sql:sql.substring(i)); + break; + } + newSb.append(sql, i, ndx); + ndx += startLen; + int ndx2 = sql.indexOf(endSym, ndx); + if(ndx2 == -1) { + throw new IllegalArgumentException("无结尾 } 符号 at: " + (ndx - startLen)); + } + model=sql.substring(ndx,ndx2).trim(); + newSb.append(MarkdownDataUtil.getSql(markdownDTO,model)); + i=ndx2+endLen; + } + return newSb.toString(); + } + + public static String getSql(String sqlId) { + MdWithInnerIdTemp mdWithInnerIdTemp=loadConfigData(sqlId,false); + return MarkdownDataUtil.getSql(mdWithInnerIdTemp.getMarkdownDTO(),mdWithInnerIdTemp.getInnnerId()); + } + public static boolean containsSqlId(String sqlId) { + MdWithInnerIdTemp mdWithInnerIdTemp=loadConfigData(sqlId,false); + return mdWithInnerIdTemp.getMarkdownDTO().getContentMap().containsKey(sqlId); + } + public static SqlInfo getSqlInfo(String sqlId, boolean needReadMdLastModified) { + MdWithInnerIdTemp mdWithInnerIdTemp=loadConfigData(sqlId,needReadMdLastModified); + String sql = MarkdownDataUtil.getSql(mdWithInnerIdTemp.getMarkdownDTO(),mdWithInnerIdTemp.getInnnerId()); + SqlInfo sqlInfo=new SqlInfo(); + sqlInfo.setInnnerId(mdWithInnerIdTemp.getInnnerId()); + sqlInfo.setMarkdownDTO(mdWithInnerIdTemp.getMarkdownDTO()); + sqlInfo.setSql(sql); + return sqlInfo; + } + public static MdWithInnerIdTemp loadConfigData(String sqlId,boolean needReadMdLastModified) { + MdWithInnerIdTemp mdWithInnerIdTemp=new MdWithInnerIdTemp(); + if(sqlId.startsWith(Constant.ISSQLFLAG)){ + MarkdownDTO markdownDTO= new MarkdownDTO(); + markdownDTO.setId(Constant.MAINFLAG+"_"+ StringUtils.uuid()); + Map map=new HashMap<>(); + String sql=sqlId.substring(Constant.ISSQLFLAG.length()); + if(sqlId.endsWith(Constant.COUNTFLAG)){ + sql=null; + } + map.put(Constant.MAINFLAG,sql); + markdownDTO.setContentMap(map); + String innerId=Constant.MAINFLAG; + if(sqlId.endsWith(Constant.COUNTFLAG)){ + innerId="main"+Constant.COUNTFLAG; + } + mdWithInnerIdTemp.setInnnerId(innerId); + mdWithInnerIdTemp.setMarkdownDTO(markdownDTO); + return mdWithInnerIdTemp; + } + if(sqlId.startsWith(Constant.ISMDFLAG)){ + MarkdownDTO markdownDTO= MarkdownUtil.readMarkdown(sqlId.substring(Constant.ISMDFLAG.length()),null,null); + mdWithInnerIdTemp.setInnnerId(Constant.MAINFLAG); + mdWithInnerIdTemp.setMarkdownDTO(markdownDTO); + return mdWithInnerIdTemp; + } + + String[] sqlIds = StringUtils.split(sqlId, "."); + if (sqlIds.length < 2) { + throw new MybatisMinRuntimeException("error config id:"+sqlId); + } + StringBuilder packageName = new StringBuilder(); + for (int i = 0; i < sqlIds.length - 2; i++) { + packageName.append(sqlIds[i]).append("."); + } + String fileName=sqlIds[sqlIds.length - 2] + ".md"; + String needFindId=sqlIds[sqlIds.length - 1]; + MarkdownDTO markdownDTO= MarkdownUtil.readMarkdownFile(packageName.substring(0,packageName.length()-1),fileName,needReadMdLastModified); + mdWithInnerIdTemp.setInnnerId(needFindId); + mdWithInnerIdTemp.setMarkdownDTO(markdownDTO); + return mdWithInnerIdTemp; + } + public static String initStringMd(String md){ + return initStringMd(md,StringUtils.uuid(),Constant.MDINITVERSION); + } + public static String initStringMd(String md,String id,String version){ + if(!md.contains(Constant.MDVERSION)){ + md=Constant.MDVERSION+" "+version+" \n"+md; + } + if(!md.contains(Constant.MDID)){ + md=Constant.MDID+" "+id + "\n"+md; + } + if(!md.startsWith(Constant.ISMDFLAG)){ + md=Constant.ISMDFLAG+md; + } + return md; + } + public static String initSqlInSqlId(String sqlId){ + if(!sqlId.startsWith(Constant.ISSQLFLAG)){ + return Constant.ISSQLFLAG+sqlId; + } + return sqlId; + } + +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/JoinTable.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/JoinTable.java new file mode 100644 index 0000000000000000000000000000000000000000..c49fab8d3c329a9678ee315c8e9124807bb34793 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/JoinTable.java @@ -0,0 +1,44 @@ +package com.vonchange.mybatis.markdown.bean; + +/** + * @author 冯昌义 + * 2017/12/5. + */ +public class JoinTable { + private String sql; + private String tables; + private String views; + private String js; + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public String getTables() { + return tables; + } + + public void setTables(String tables) { + this.tables = tables; + } + + public String getViews() { + return views; + } + + public void setViews(String views) { + this.views = views; + } + + public String getJs() { + return js; + } + + public void setJs(String js) { + this.js = js; + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/MdWithInnerIdTemp.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/MdWithInnerIdTemp.java new file mode 100644 index 0000000000000000000000000000000000000000..90e5cb227e55a13c35529def20f4e4671acaad52 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/MdWithInnerIdTemp.java @@ -0,0 +1,29 @@ +package com.vonchange.mybatis.markdown.bean; + + +import com.vonchange.mybatis.markdown.MarkdownDTO; + +/** + * @author 冯昌义 + * 2017/12/14. + */ +public class MdWithInnerIdTemp { + private String innnerId; + private MarkdownDTO markdownDTO; + + public String getInnnerId() { + return innnerId; + } + + public void setInnnerId(String innnerId) { + this.innnerId = innnerId; + } + + public MarkdownDTO getMarkdownDTO() { + return markdownDTO; + } + + public void setMarkdownDTO(MarkdownDTO markdownDTO) { + this.markdownDTO = markdownDTO; + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/MemTable.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/MemTable.java new file mode 100644 index 0000000000000000000000000000000000000000..88f343c09607355acc45c3df8f79dc1add55e312 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/MemTable.java @@ -0,0 +1,28 @@ +package com.vonchange.mybatis.markdown.bean; + +import java.util.Map; + +/** + * @author 冯昌义 + * 2017/12/5. + */ +public class MemTable { + private Map info; + private String sql; + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public Map getInfo() { + return info; + } + + public void setInfo(Map info) { + this.info = info; + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/SqlInfo.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/SqlInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..fe3ed2de1c6a2240c8725642d8118f10c0658af1 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/markdown/bean/SqlInfo.java @@ -0,0 +1,46 @@ +package com.vonchange.mybatis.markdown.bean; + + +import com.vonchange.mybatis.markdown.MarkdownDTO; + +/** + * Created by 冯昌义 on 2018/1/22. + */ +public class SqlInfo { + private String sqlId; + private String sql; + private String innnerId; + private MarkdownDTO markdownDTO; + + public String getSql() { + return sql; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public String getInnnerId() { + return innnerId; + } + + public void setInnnerId(String innnerId) { + this.innnerId = innnerId; + } + + public MarkdownDTO getMarkdownDTO() { + return markdownDTO; + } + + public void setMarkdownDTO(MarkdownDTO markdownDTO) { + this.markdownDTO = markdownDTO; + } + + public String getSqlId() { + return sqlId; + } + + public void setSqlId(String sqlId) { + this.sqlId = sqlId; + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/AnalyeNamed.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/AnalyeNamed.java new file mode 100644 index 0000000000000000000000000000000000000000..175693832d6849433301baf5045af90cdb67fd67 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/AnalyeNamed.java @@ -0,0 +1,64 @@ +package com.vonchange.mybatis.sql; + +/** + * 分析后的实体类 + */ +public class AnalyeNamed { + private String condition; + //private String type; + /** + * 1 String 2 其他 base 3:list 4.arr + */ + private String namedFull; + private String itemProperty; + private String link; + //private Object value; + private String column; + + public String getCondition() { + return condition; + } + + public void setCondition(String condition) { + this.condition = condition; + } + + + + + + + public String getNamedFull() { + return namedFull; + } + + public void setNamedFull(String namedFull) { + this.namedFull = namedFull; + } + + public String getItemProperty() { + return itemProperty; + } + + public void setItemProperty(String itemProperty) { + this.itemProperty = itemProperty; + } + + public String getLink() { + return link; + } + + public void setLink(String link) { + this.link = link; + } + + public String getColumn() { + return column; + } + + public void setColumn(String column) { + this.column = column; + } + + +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/DynamicSql.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/DynamicSql.java new file mode 100644 index 0000000000000000000000000000000000000000..814b5c9aafd676af5d21736f8d39db1c1a2e69d7 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/DynamicSql.java @@ -0,0 +1,311 @@ +package com.vonchange.mybatis.sql; + +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.dialect.LikeTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * @author 冯昌义 + */ +public class DynamicSql { + private DynamicSql() { + throw new IllegalStateException("Utility class"); + } + + private static Logger logger = LoggerFactory.getLogger(DynamicSql.class); + private static final String PALCEHOLDERA="#'{'{0}'}'"; + + public static String dynamicSql(String sql, Dialect dialect) { + if (sql.contains("[@")) { + return dynamicSqlDo(sql,dialect); + } + //未来版本不再支持 + if (sql.contains("{@")) { + return dynamicSqlOld(sql,dialect); + } + return sql; + } + private static String dynamicSqlDo(String sql,Dialect dialect){ + String startSym = "[@"; + String endSym = "]"; + int len = sql.length(); + int startLen = startSym.length(); + int endLen = endSym.length(); + int i = 0; + StringBuilder newSql = new StringBuilder(); + String model = null; + while (i < len) { + int ndx = sql.indexOf(startSym, i); + if (ndx == -1) { + newSql.append(i == 0 ? sql : sql.substring(i)); + break; + } + newSql.append(sql.substring(i, ndx)); + ndx += startLen; + //newSql + int ndx2 = sql.indexOf(endSym, ndx); + if (ndx2 == -1) { + throw new IllegalArgumentException("无结尾 ] 符号 at: " + (ndx - startLen)); + } + model = sql.substring(ndx, ndx2); + newSql.append(new StringBuffer(getModel(model,dialect))); + i = ndx2 + endLen; + } + logger.debug("自定义语言\n{}", newSql); + return newSql.toString(); + } + private static String dynamicSqlOld(String sql,Dialect dialect){ + String startSym = "{@"; + String endSym = "}"; + int len = sql.length(); + int startLen = startSym.length(); + int endLen = endSym.length(); + int i = 0; + StringBuilder newSql = new StringBuilder(); + String model; + while (i < len) { + int ndx = sql.indexOf(startSym, i); + if (ndx == -1) { + newSql.append(i == 0 ? sql : sql.substring(i)); + break; + } + newSql.append(sql.substring(i, ndx)); + ndx += startLen; + //newSql + int ndx2 = sql.indexOf(endSym, ndx); + if (ndx2 == -1) { + throw new IllegalArgumentException("无结尾 } 符号 at: " + (ndx - startLen)); + } + model = sql.substring(ndx, ndx2); + newSql.append(new StringBuffer(getModel(model,dialect))); + i = ndx2 + endLen; + } + logger.debug("自定义语言\n{}", newSql); + return newSql.toString(); + } + + private static String getModel(String model,Dialect dialect) { + if(model.contains("#{")){ + return ifNull(model,dialect); + } + model = model.trim(); + model = model.replaceAll("[\\s]+", " "); + String[] moduleSubs = model.split(" "); + List resultList = new ArrayList<>(); + for (String str : moduleSubs) { + resultList.add(str.trim()); + } + if (resultList.size() == 4) { + AnalyeNamed analyeNamed = analyeNamed(resultList); + return workNamed(analyeNamed,dialect); + } + //扩展只有判空 + return model; + } + private static String ifNull(String model,Dialect dialect){ + SqlParamResult sqlParamResult = getParamFromModel(model,dialect); + if(model.startsWith("@")){ + return sqlParamResult.getNewSql().substring(1); + } + StringBuilder sb= new StringBuilder(); + for (String param:sqlParamResult.getParam()) { + sb.append(format("@com.vonchange.mybatis.tpl.MyOgnl@isNotEmpty({0}) and ",param)); + } + String ifStr = format("",sb.substring(0,sb.length()-4)); + return format("{0} {1} ", ifStr, sqlParamResult.getNewSql()); + + } + private static SqlParamResult getParamFromModel(String model,Dialect dialect){ + String startSym = "#{"; + String endSym = "}"; + int len = model.length(); + int startLen = startSym.length(); + int endLen = endSym.length(); + int i = 0; + Map paramMap = new HashMap<>(); + StringBuilder newSql = new StringBuilder(); + String param; + while (i < len) { + int ndx = model.indexOf(startSym, i); + if (ndx == -1) { + newSql.append(i == 0 ? model : model.substring(i)); + break; + } + newSql.append(model.substring(i, ndx)); + ndx += startLen; + int ndx2 = model.indexOf(endSym, ndx); + if (ndx2 == -1) { + throw new IllegalArgumentException("无结尾 } 符号 at: " + (ndx - startLen)); + } + param=model.substring(ndx, ndx2); + paramMap.put(getTrueParam(param),true); + newSql.append(getParamSql(param,dialect)); + i = ndx2 + endLen; + } + List list = new ArrayList<>(); + for(Map.Entry entry:paramMap.entrySet()){ + list.add(entry.getKey()); + } + return new SqlParamResult(list,newSql.toString()); + } + private static String getParamSql(String param,Dialect dialect){ + if(!param.contains(":")){ + if(param.contains("%")){ + AnalyeNamed analyeNamed = new AnalyeNamed(); + analyeNamed.setNamedFull(param); + return like(analyeNamed,dialect); + } + return format(PALCEHOLDERA, param); + } + String[] params = param.split(":"); + if("in".equalsIgnoreCase(params[params.length-1])){ + String itemProperty=""; + if(params.length>2){ + itemProperty="."+params[2]; + } + return in(params[0],itemProperty); + } + if("like".equalsIgnoreCase(params[params.length-1])){ + AnalyeNamed analyeNamed = new AnalyeNamed(); + analyeNamed.setNamedFull(params[0]); + return like(analyeNamed,dialect); + } + return format(PALCEHOLDERA, param); + } + private static String getTrueParam(String param){ + if(!param.contains(":")){ + if(param.contains("%")){ + return param.replace("%",""); + } + return param; + } + String[] params = param.split(":"); + if("like".equalsIgnoreCase(params[params.length-1])){ + return params[0].replace("%",""); + } + return params[0]; + } + + private static AnalyeNamed analyeNamed(List resultList) { + String four = resultList.get(3); + AnalyeNamed analyeNamed = new AnalyeNamed(); + String link = resultList.get(0); + String[] paramStrs = four.split(":"); + List strList = new ArrayList<>(Arrays.asList(paramStrs)); + if (strList.size() == 1) { + strList.add(""); + } else { + strList.set(1, "." + strList.get(1)); + } + String named = strList.get(0).trim(); + analyeNamed.setNamedFull(named); + analyeNamed.setCondition(resultList.get(2)); + analyeNamed.setItemProperty(strList.get(1)); + analyeNamed.setLink(link); + analyeNamed.setColumn(resultList.get(1)); + return analyeNamed; + } + + + private static String workNamed(AnalyeNamed analyeNamed,Dialect dialect) { + String named = format(PALCEHOLDERA, analyeNamed.getNamedFull()); + if ("in".equalsIgnoreCase(analyeNamed.getCondition())) { + named = in(analyeNamed.getNamedFull(), analyeNamed.getItemProperty()); + } + if ("like".equalsIgnoreCase(analyeNamed.getCondition())){ + named = like(analyeNamed,dialect); + } + boolean ifNullFlag=true; + String link = analyeNamed.getLink(); + if(analyeNamed.getLink().startsWith("@")){ + ifNullFlag=false; + link=link.substring(1); + } + String content = format(" {0} {1} {2} {3} ", link, analyeNamed.getColumn(), analyeNamed.getCondition(), named); + if(!ifNullFlag){ + return content.substring(1); + } + String ifStr = format("", analyeNamed.getNamedFull()); + return format("{0} {1} ", ifStr, content); + } + + private static String like(AnalyeNamed analyeNamed,Dialect dialect) { + String named=analyeNamed.getNamedFull(); + boolean all=!named.contains("%"); + boolean left = named.startsWith("%"); + boolean right =named.endsWith("%"); + LikeTemplate likeTemplate = dialect.getLikeTemplate(); + String str = likeTemplate.getFull(); + if (all) { + return format(str, named); + } + if(left&&right){ + analyeNamed.setNamedFull(named.substring(1,named.length()-1)); + return format(str, analyeNamed.getNamedFull()); + } + str = likeTemplate.getRight(); + if (right) { + analyeNamed.setNamedFull(named.substring(0,named.length()-1)); + return format(str, analyeNamed.getNamedFull()); + } + str = likeTemplate.getLeft(); + if (left) { + analyeNamed.setNamedFull(named.substring(1)); + return format(str, analyeNamed.getNamedFull()); + } + return format(PALCEHOLDERA, named); + } + + /** + * bind 方式 能通用 有bug = 和 like一起用 + */ + private static String likeNew(AnalyeNamed analyeNamed) { + String named=analyeNamed.getNamedFull(); + boolean all=!named.contains("%"); + boolean left = named.startsWith("%"); + boolean right =named.endsWith("%"); + // + String str = " #'{'{2}'}"; + if (all) { + return likeFormat(str, named,"_like"); + } + if(left&&right){ + analyeNamed.setNamedFull(named.substring(1,named.length()-1)); + return likeFormat(str, analyeNamed.getNamedFull(),"_like"); + } + str = " #'{'{2}'}"; + if (right) { + analyeNamed.setNamedFull(named.substring(0,named.length()-1)); + return likeFormat(str, analyeNamed.getNamedFull(),"_rightLike"); + } + str = " #'{'{2}'}"; + if (left) { + analyeNamed.setNamedFull(named.substring(1)); + return likeFormat(str, analyeNamed.getNamedFull(),"_leftLike"); + } + return format(PALCEHOLDERA, named); + } + private static String likeFormat(String tpl,String named,String type){ + return format(tpl, named+type,named,named+type); + } + + public static String in(String named, String itemProperty) { + String str = "" + + "#'{'item{1}'}'" + + ""; + return format(str, named, itemProperty); + } + + public static String format(String pattern, Object... arguments) { + MessageFormat temp = new MessageFormat(pattern); + return temp.format(arguments); + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/SqlParamResult.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/SqlParamResult.java new file mode 100644 index 0000000000000000000000000000000000000000..441e28d74f84aa15d9b659e71c2d49f08fec209d --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/sql/SqlParamResult.java @@ -0,0 +1,29 @@ +package com.vonchange.mybatis.sql; + +import java.util.List; + +public class SqlParamResult { + private List param; + private String newSql; + + public SqlParamResult(List param, String newSql) { + this.param = param; + this.newSql = newSql; + } + + public List getParam() { + return param; + } + + public void setParam(List param) { + this.param = param; + } + + public String getNewSql() { + return newSql; + } + + public void setNewSql(String newSql) { + this.newSql = newSql; + } +} diff --git a/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/tpl/MyOgnl.java b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/tpl/MyOgnl.java new file mode 100644 index 0000000000000000000000000000000000000000..7a281ad158eeb59cf03d8e59e70728b152e8a6b4 --- /dev/null +++ b/mybatis-sql-extend/src/main/java/com/vonchange/mybatis/tpl/MyOgnl.java @@ -0,0 +1,55 @@ +package com.vonchange.mybatis.tpl; + + + +import java.util.Collection; +import java.util.Map; + +public class MyOgnl { + private static boolean isBlank(final CharSequence cs) { + int strLen; + if (cs == null || (strLen = cs.length()) == 0) { + return true; + } + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(cs.charAt(i)) == false) { + return false; + } + } + return true; + } + public static boolean isEmpty(Object value){ + if(null==value){ + return true; + } + if(value instanceof String){ + if(isBlank((String)value)){ + return true; + } + return false; + } + if(value instanceof Collection){ + if(((Collection)value).isEmpty()){ + return true; + } + return false; + } + if(value.getClass().isArray()){ + if(((Object[])value).length == 0){ + return true; + } + return false; + } + if(value instanceof Map){ + if(((Map)value).isEmpty()){ + return true; + } + return false; + } + return false; + } + public static boolean isNotEmpty(Object value){ + return !isEmpty(value); + } + +} diff --git a/mybatis-template/pom.xml b/mybatis-template/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..278b4ad793bf1b81359efd7632b67c2ee8c272e6 --- /dev/null +++ b/mybatis-template/pom.xml @@ -0,0 +1,33 @@ + + + + mybatis-mini-parant + com.vonchange.common + 2.3.9 + + 4.0.0 + + mybatis-template + 2.3.9 + + + + + com.vonchange.common + mybatis-sql-extend + 2.3.9 + + + com.vonchange.common + mybati + 3.5.2.2 + + + org.hibernate.javax.persistence + hibernate-jpa-2.1-api + 1.0.0.Final + + + \ No newline at end of file diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/EntityUtil.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/EntityUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..2c4565eb7e3e4978a30e6014e4da81085d600a43 --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/EntityUtil.java @@ -0,0 +1,159 @@ +package com.vonchange.mybatis.tpl; + + +import com.vonchange.common.util.ClazzUtils; +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.tpl.annotation.ColumnNot; +import com.vonchange.mybatis.tpl.annotation.InsertIfNull; +import com.vonchange.mybatis.tpl.annotation.InsertReturn; +import com.vonchange.mybatis.tpl.annotation.UpdateDuplicateKeyIgnore; +import com.vonchange.mybatis.tpl.annotation.UpdateIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateNotNull; +import com.vonchange.mybatis.tpl.model.EntityField; +import com.vonchange.mybatis.tpl.model.EntityInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.persistence.Column; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; +import java.beans.IntrospectionException; +import java.beans.PropertyDescriptor; +import java.lang.annotation.Annotation; +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +/** + * + * Created by 冯昌义 on 2018/4/19. + */ +public class EntityUtil { + private static final Map entityMap = new ConcurrentHashMap<>(); + private static Logger logger = LoggerFactory.getLogger(EntityUtil.class); + public static void initEntityInfo(Class clazz) { + String entityName = clazz.getName(); + if(!entityMap.containsKey(entityName)){ + initEntity(clazz); + } + } + + public static EntityInfo getEntityInfo(Class clazz){ + String entityName = clazz.getName(); + if(!entityMap.containsKey(entityName)){ + initEntity(clazz); + } + return entityMap.get(entityName); + } + + private static void initEntity(Class clazz) { + logger.debug("初始化 {}", clazz.getName()); + EntityInfo entity = new EntityInfo(); + Table table=clazz.getAnnotation(Table.class); + String tableName=null; + if(null!=table){ + tableName=table.name(); + } + if(StringUtils.isBlank(tableName)){ + String tableEntity= clazz.getSimpleName(); + if(clazz.getSimpleName().toLowerCase().endsWith("do")){ + tableEntity=clazz.getSimpleName().substring(0,clazz.getSimpleName().length()-2); + } + tableName= OrmUtil.toSql(tableEntity); + } + entity.setTableName(tableName); + List fieldList = new ArrayList<>(); + getFieldList(clazz,fieldList); + //clazz.getDeclaredFields();// 只有本类 + Map entityFieldMap = new LinkedHashMap<>(); + Column column; + List columnReturns = new ArrayList<>(); + for (Field field : fieldList) { + Class type = field.getType(); + Boolean isBaseType = ClazzUtils.isBaseType(type); + String fieldName = field.getName(); + if(Boolean.FALSE.equals(isBaseType)||entityFieldMap.containsKey(fieldName)){ + continue; + } + EntityField entityField = new EntityField(); + PropertyDescriptor descriptor = null; + try { + descriptor = new PropertyDescriptor(field.getName(),clazz); + } catch (IntrospectionException e) { + logger.error("", e); + continue; + } + entityField.setWriteMethod(descriptor.getWriteMethod()); + entityField.setFieldName(fieldName); + column=field.getAnnotation(Column.class); + String columnName =null; + if(null!=column){ + columnName=column.name(); + } + if(StringUtils.isBlank(columnName)){ + columnName = OrmUtil.toSql(fieldName); + } + entityField.setColumnName(columnName); + entityField.setType(type); + entityField.setIsBaseType(isBaseType); + entityField.setIsColumn(true); + entityField.setUpdateNotNull(false); + entityField.setIgnoreDupUpdate(false); + + Annotation[] annotations = field.getAnnotations(); + for (Annotation annotation : annotations) { + if (annotation instanceof ColumnNot) { + entityField.setIsColumn(false); + continue; + } + if (annotation instanceof Id) { + entityField.setIsId(true); + entity.setIdFieldName(fieldName); + entity.setIdColumnName(columnName); + entity.setIdType(type.getSimpleName()); + if(null==entity.getGenColumn()){ + entity.setGenColumn(columnName); + } + // continue; + } + if(annotation instanceof GeneratedValue){ + entity.setGenColumn(columnName); + } + if(annotation instanceof InsertReturn){ + columnReturns.add(columnName); + } + if (annotation instanceof UpdateNotNull) { + entityField.setUpdateNotNull(true); + } + if (annotation instanceof InsertIfNull) { + entityField.setInsertIfNull(((InsertIfNull) annotation).value()); + entityField.setInsertIfNullFunc(((InsertIfNull) annotation).function()); + } + if (annotation instanceof UpdateIfNull) { + entityField.setUpdateIfNull(((UpdateIfNull) annotation).value()); + entityField.setUpdateIfNullFunc(((UpdateIfNull) annotation).function()); + } + if (annotation instanceof UpdateDuplicateKeyIgnore) { + entityField.setIgnoreDupUpdate(true); + } + } + entityFieldMap.put(fieldName, entityField); + } + entity.setColumnReturns(columnReturns); + entity.setFieldMap(entityFieldMap); + entityMap.put(clazz.getName(), entity); + } + + private static void getFieldList(Class clazz, List fieldList) { + fieldList.addAll(Arrays.asList(clazz.getDeclaredFields())); + if(null!=clazz.getSuperclass()){ + getFieldList(clazz.getSuperclass(), fieldList); + } + + } +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/MybatisTpl.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/MybatisTpl.java new file mode 100644 index 0000000000000000000000000000000000000000..9e92c5aad8d900b03cb6848586fc04b52bf4125b --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/MybatisTpl.java @@ -0,0 +1,119 @@ +package com.vonchange.mybatis.tpl; + + +import com.vonchange.common.ibatis.mapping.BoundSql; +import com.vonchange.common.ibatis.mapping.ParameterMapping; +import com.vonchange.common.ibatis.mapping.SqlSource; +import com.vonchange.common.ibatis.reflection.MetaObject; +import com.vonchange.common.ibatis.scripting.LanguageDriver; +import com.vonchange.common.ibatis.scripting.xmltags.XMLLanguageDriver; +import com.vonchange.common.ibatis.session.Configuration; +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; +import com.vonchange.mybatis.sql.DynamicSql; +import com.vonchange.mybatis.tpl.model.SqlWithParam; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * mybatis 模版主要代码 + */ +public class MybatisTpl { + private static Logger logger = LoggerFactory.getLogger(MybatisTpl.class); + public static final String MARKDOWN_SQL_ID ="markdown_sql_id"; + private MybatisTpl() { + throw new IllegalStateException("Utility class"); + } + @SuppressWarnings("unchecked") + public static SqlWithParam generate(String sqlInXml, Map parameter, Dialect dialect){ + SqlWithParam sqlWithParam= new SqlWithParam(); + if(StringUtils.isBlank(sqlInXml)){ + sqlWithParam.setSql(null); + sqlWithParam.setParams(null); + return sqlWithParam; + } + sqlInXml= DynamicSql.dynamicSql(sqlInXml,dialect); + sqlInXml=sqlInXml.trim(); + if(sqlInXml.contains(""+sqlInXml+""; + sqlInXml = StringUtils.replaceEach(sqlInXml,new String[]{" > "," < "," >= "," <= "," <> "}, + new String[]{" > "," < "," >= "," <= "," <> "}); + } + if(null==parameter){ + parameter=new LinkedHashMap<>(); + } + String id =null; + LanguageDriver languageDriver = new XMLLanguageDriver(); + Configuration configuration= new Configuration(); + Properties properties= new Properties(); + for (Map.Entry entry: parameter.entrySet()) { + if(null==entry.getValue()){ + continue; + } + properties.put(entry.getKey(),entry.getValue()); + } + configuration.setVariables(properties); + BoundSql boundSql = null; + try { + SqlSource sqlSource = languageDriver.createSqlSource(configuration, sqlInXml, Map.class); + boundSql=sqlSource.getBoundSql(parameter); + }catch (Exception e){ + logger.error("解析sqlxml出错",e); + logger.error("sqlxml:{}",sqlInXml); + sqlWithParam.setSql(null); + sqlWithParam.setParams(null); + return sqlWithParam; + } + + if(boundSql.getSql().contains("#{")){ + return generate(boundSql.getSql(),parameter,dialect); + } + if(parameter.containsKey(MARKDOWN_SQL_ID)){ + id= ConvertUtil.toString(parameter.get(MARKDOWN_SQL_ID)); + parameter.remove(MARKDOWN_SQL_ID); + } + List list= boundSql.getParameterMappings(); + List argList= new ArrayList<>(); + List propertyNames = new ArrayList<>(); + if(null!=list&&!list.isEmpty()){ + Map param =new LinkedHashMap<>(); + if(boundSql.getParameterObject() instanceof Map){ + param = (Map) boundSql.getParameterObject(); + } + for (ParameterMapping parameterMapping: list) { + Object value; + + String propertyName= parameterMapping.getProperty(); + if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params + value = boundSql.getAdditionalParameter(propertyName); + } else if (param == null) { + value = null; + }else { + MetaObject metaObject = configuration.newMetaObject(param); + if(!metaObject.hasGetter(propertyName)){ + throw new MybatisMinRuntimeException(id+" "+propertyName+" placeholder not found"); + } + value = metaObject.getValue(propertyName); + } + argList.add(value); + propertyNames.add(propertyName); + } + } + Object[] args=argList.toArray(); + String sql=boundSql.getSql(); + sqlWithParam.setSql(sql); + sqlWithParam.setParams(args); + sqlWithParam.setPropertyNames(propertyNames); + return sqlWithParam; + } + + +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/OrmUtil.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/OrmUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..e2372e58dbf467e2a27d46bf5737619561085e19 --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/OrmUtil.java @@ -0,0 +1,90 @@ +package com.vonchange.mybatis.tpl; + + +import com.vonchange.common.util.StringUtils; + +/** + * Orm field + * + */ +public class OrmUtil { + /** + * _ to up + * + */ + public static String toFiled(String colName) { + return toUp(colName); + } + private static String toUp(String colName){ + if(null==colName||!colName.contains("_")){ + return colName; + } + StringBuilder sb = new StringBuilder(); + boolean flag = false; + for (int i = 0; i < colName.length(); i++) { + char cur = colName.charAt(i); + if (cur == '_') { + flag = true; + + } else { + if (flag) { + sb.append(Character.toUpperCase(cur)); + flag = false; + } else { + sb.append(Character.toLowerCase(cur)); + } + } + } + return sb.toString(); + } + + + /** + * Hql to sql + * + */ + public static String toSql(String myHql) { + StringBuilder sb = new StringBuilder(); + boolean flag = false; + boolean isLetter = false; + for (int i = 0; i < myHql.length(); i++) { + char cur = myHql.charAt(i); + if (cur == '_') { + throw new RuntimeException("not allow _ !"); + } + if (cur == ':') { + flag = true; + } + if (cur != ':' && !Character.isLetter(cur)) { + flag = false; + } + if (flag) { + sb.append(cur); + continue; + } + if (Character.isUpperCase(cur) && isLetter) { + sb.append("_"); + sb.append(Character.toLowerCase(cur)); + } else { + sb.append(Character.toLowerCase(cur)); + } + if (!Character.isLetter(cur)) { + isLetter = false; + } else { + isLetter = true; + } + } + return sb.toString(); + } + + /** + * toEntity + */ + public static String toEntity(String tableName) { + return StringUtils.capitalize(toUp(tableName)); + } + + + + +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/ColumnNot.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/ColumnNot.java new file mode 100644 index 0000000000000000000000000000000000000000..36a9327f990c40025c1ba4f51cdb323dc4e7aa23 --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/ColumnNot.java @@ -0,0 +1,15 @@ +package com.vonchange.mybatis.tpl.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *排除字段 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface ColumnNot { + +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/InsertIfNull.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/InsertIfNull.java new file mode 100644 index 0000000000000000000000000000000000000000..c6fb7ecade711c97fc1d8d2df1b6224879c5346d --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/InsertIfNull.java @@ -0,0 +1,17 @@ +package com.vonchange.mybatis.tpl.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *排除字段 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface InsertIfNull { + String value() default ""; + String function() default ""; + +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/InsertReturn.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/InsertReturn.java new file mode 100644 index 0000000000000000000000000000000000000000..273f5e6b37c5b8c16f8f3841d6cafbbb4c3edbcc --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/InsertReturn.java @@ -0,0 +1,15 @@ +package com.vonchange.mybatis.tpl.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *排除字段 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface InsertReturn { + +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateDuplicateKeyIgnore.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateDuplicateKeyIgnore.java new file mode 100644 index 0000000000000000000000000000000000000000..3c941fec94f7a60cd47eb8908877205b4d53d63f --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateDuplicateKeyIgnore.java @@ -0,0 +1,13 @@ +package com.vonchange.mybatis.tpl.annotation; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface UpdateDuplicateKeyIgnore { +} \ No newline at end of file diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateIfNull.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateIfNull.java new file mode 100644 index 0000000000000000000000000000000000000000..a61f8bf9d88ed7dbd7d037d1fb1630db3b465214 --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateIfNull.java @@ -0,0 +1,16 @@ +package com.vonchange.mybatis.tpl.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *排除字段 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface UpdateIfNull { + String value() default ""; + String function() default ""; +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateNotNull.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateNotNull.java new file mode 100644 index 0000000000000000000000000000000000000000..863020eda86e2bf7daa3d94bffa40787ca13ea4f --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/annotation/UpdateNotNull.java @@ -0,0 +1,15 @@ +package com.vonchange.mybatis.tpl.annotation; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + *排除字段 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ElementType.FIELD}) +public @interface UpdateNotNull { + +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/EntityField.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/EntityField.java new file mode 100644 index 0000000000000000000000000000000000000000..eefa5a17279d72a283219edbc56ec35e2e2fe814 --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/EntityField.java @@ -0,0 +1,126 @@ +package com.vonchange.mybatis.tpl.model; + + +import java.lang.reflect.Method; + +/** + * 实体字段信息 + * @author vonchange@163.com + */ +public class EntityField { + private String fieldName; + private String columnName; + private Class type; + private Boolean isBaseType=false; + private Boolean isColumn=false; + private Boolean isId=false; + //private String function; + //private Boolean ignoreDupUpdate; + private Boolean updateNotNull; + private String insertIfNull; + private String insertIfNullFunc; + private String updateIfNull; + private String updateIfNullFunc; + private Boolean ignoreDupUpdate; + private Method writeMethod; + public String getFieldName() { + return fieldName; + } + public void setFieldName(String fieldName) { + this.fieldName = fieldName; + } + + + public Method getWriteMethod() { + return writeMethod; + } + + public void setWriteMethod(Method writeMethod) { + this.writeMethod = writeMethod; + } + + public String getColumnName() { + return columnName; + } + + public Boolean getIgnoreDupUpdate() { + return ignoreDupUpdate; + } + + public void setIgnoreDupUpdate(Boolean ignoreDupUpdate) { + this.ignoreDupUpdate = ignoreDupUpdate; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + public Boolean getIsBaseType() { + return isBaseType; + } + public void setIsBaseType(Boolean isBaseType) { + this.isBaseType = isBaseType; + } + + public Boolean getIsId() { + return isId; + } + public void setIsId(Boolean isId) { + this.isId = isId; + } + public Boolean getIsColumn() { + return isColumn; + } + public void setIsColumn(Boolean isColumn) { + this.isColumn = isColumn; + } + + public Boolean getUpdateNotNull() { + return updateNotNull; + } + + public void setUpdateNotNull(Boolean updateNotNull) { + this.updateNotNull = updateNotNull; + } + + public String getInsertIfNull() { + return insertIfNull; + } + + public void setInsertIfNull(String insertIfNull) { + this.insertIfNull = insertIfNull; + } + + public String getInsertIfNullFunc() { + return insertIfNullFunc; + } + + public void setInsertIfNullFunc(String insertIfNullFunc) { + this.insertIfNullFunc = insertIfNullFunc; + } + + public String getUpdateIfNull() { + return updateIfNull; + } + + public void setUpdateIfNull(String updateIfNull) { + this.updateIfNull = updateIfNull; + } + + public String getUpdateIfNullFunc() { + return updateIfNullFunc; + } + + public void setUpdateIfNullFunc(String updateIfNullFunc) { + this.updateIfNullFunc = updateIfNullFunc; + } + + + + public Class getType() { + return type; + } + + public void setType(Class type) { + this.type = type; + } +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/EntityInfo.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/EntityInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..5ec1da9ea35e3a5b8ad46f69487c62de29dec587 --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/EntityInfo.java @@ -0,0 +1,88 @@ +package com.vonchange.mybatis.tpl.model; + +import java.util.List; +import java.util.Map; + +/** + * 实体信息 + * @author vonchange@163.com + */ +public class EntityInfo { + private String entityName; + private String tableName; + private String idFieldName; + private String idColumnName; + private String idType; + //private List fieldReturns; + private List columnReturns; + private String genColumn; + private Map fieldMap; + + public String getEntityName() { + return entityName; + } + + public void setEntityName(String entityName) { + this.entityName = entityName; + } + + public String getTableName() { + return tableName; + } + + public void setTableName(String tableName) { + this.tableName = tableName; + } + + public String getIdFieldName() { + return idFieldName; + } + + + + public void setIdFieldName(String idFieldName) { + this.idFieldName = idFieldName; + } + + public String getIdColumnName() { + return idColumnName; + } + + public void setIdColumnName(String idColumnName) { + this.idColumnName = idColumnName; + } + + public String getIdType() { + return idType; + } + + public void setIdType(String idType) { + this.idType = idType; + } + + public Map getFieldMap() { + return fieldMap; + } + + public void setFieldMap(Map fieldMap) { + this.fieldMap = fieldMap; + } + + + + public List getColumnReturns() { + return columnReturns; + } + + public void setColumnReturns(List columnReturns) { + this.columnReturns = columnReturns; + } + + public String getGenColumn() { + return genColumn; + } + + public void setGenColumn(String genColumn) { + this.genColumn = genColumn; + } +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/SqlWithParam.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/SqlWithParam.java new file mode 100644 index 0000000000000000000000000000000000000000..87f13ef89dcf63d38045328011a70fc1846c3fa6 --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/model/SqlWithParam.java @@ -0,0 +1,54 @@ +package com.vonchange.mybatis.tpl.model; + +import java.util.Arrays; +import java.util.List; + +/** + * @author 冯昌义 + */ +public class SqlWithParam { + private String sql; + private Object[] params; + private List propertyNames; + private List columnReturns; + + public String getSql() { + return sql; + } + + public List getPropertyNames() { + return propertyNames; + } + + public void setPropertyNames(List propertyNames) { + this.propertyNames = propertyNames; + } + + public void setSql(String sql) { + this.sql = sql; + } + + public Object[] getParams() { + return params; + } + + public void setParams(Object[] params) { + this.params = params; + } + + public List getColumnReturns() { + return columnReturns; + } + + public void setColumnReturns(List columnReturns) { + this.columnReturns = columnReturns; + } + + @Override + public String toString() { + return "SqlWithParam{" + + "sql='" + sql + '\'' + + ", params=" + Arrays.toString(params) + + '}'; + } +} diff --git a/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/sql/SqlCommentUtil.java b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/sql/SqlCommentUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..62fbc894263e1ee9b3bea68980e0a7b41f4842ce --- /dev/null +++ b/mybatis-template/src/main/java/com/vonchange/mybatis/tpl/sql/SqlCommentUtil.java @@ -0,0 +1,40 @@ +package com.vonchange.mybatis.tpl.sql; + + +import com.vonchange.mybatis.config.Constant; + +/** + * + * Created by von change on 2018/4/19. + */ +public class SqlCommentUtil { + public static boolean getLowerNo(String sql){ + if(sql.contains(Constant.NOLOWER)){ + return false; + } + return true; + } + public static boolean getOrmNo(String sql){ + if(sql.contains(Constant.NOORM)){ + return false; + } + return true; + } + /* public static class Dialect{ + public static final String MYSQL="mysql"; + public static final String ORACLE="oracle"; + public static final String BASE="base"; + } + public static String getDialect(String sql){ + if(sql.contains("@mysql")){ + return Dialect.MYSQL; + } + if(sql.contains("@oracle")){ + return Dialect.ORACLE; + } + if(sql.contains("@base")){ + return Dialect.BASE; + } + return Dialect.MYSQL; + }*/ +} diff --git a/pom.xml b/pom.xml index a14c49108754e3a3312df8a9c67308887e4e6209..6183c974692ff47a94f8aa8e8cadb7c47d4a8c60 100644 --- a/pom.xml +++ b/pom.xml @@ -2,71 +2,166 @@ 4.0.0 - - spring-data-mybatis-mini - 2.3.8 - - spring data mybatis mini + com.vonchange.common + mybatis-mini-parant + pom + 2.3.9 + + spring-data-mybatis-mini + mybatis-template + mybatis-mini + common-util + spring-data-mybatis-mini-test + mybatis-sql-extend + spring-data-mybatis-mini-low + spring-data-mybatis-mini-low-test + mybatis-sql-extend-test + + + mini parant pom spring data jdbc with mybatis template dynamic query https://github.com/VonChange/spring-data-mybatis-mini - - com.vonchange.common - parent-jar - 1.2 - - + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + vonchange + vonchange@163.com + + + + scm:https://github.com/VonChange + scm:https://github.com/VonChange + https://github.com/VonChange + - 2.1.5.RELEASE - 5.1.5.RELEASE - 8.0.15 + UTF-8 + UTF-8 + 1.8 - - - - com.vonchange.common - mybatis-mini - 1.8.8 - - - org.springframework.data - spring-data-commons - ${springdata.commons} - provided - - - org.springframework - spring-tx - ${spring.commons} - provided - - - - org.springframework - spring-context - ${spring.commons} - provided - - - - org.springframework - spring-beans - ${spring.commons} - provided - - - - org.springframework - spring-jdbc - ${spring.commons} - provided - - - - org.springframework - spring-core - ${spring.commons} - provided - - - + + + aliyun-repos + Aliyun Repository + http://maven.aliyun.com/nexus/content/groups/public + + true + + + true + + + + sonatype-repos + Sonatype Repository + https://oss.sonatype.org/content/groups/public + + true + + + true + + + + sonatype-repos-s + Sonatype Repository + https://oss.sonatype.org/content/repositories/snapshots + + true + + + true + + + + + + oss + https://oss.sonatype.org/content/repositories/snapshots/ + + + oss + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + ${java.version} + ${java.version} + UTF-8 + false + -Xlint:unchecked + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + verify + + sign + + + gpg + + + --pinentry-mode + loopback + + change2012 + + + + + + org.apache.maven.plugins + maven-source-plugin + 3.1.0 + + + attach-sources + + jar + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.10.3 + + true + UTF-8 + UTF-8 + UTF-8 + + + + attach-javadocs + + jar + + + UTF-8 + -Xdoclint:none + + + + + + diff --git a/spring-data-mybatis-mini-low-test/pom.xml b/spring-data-mybatis-mini-low-test/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..ad8217127417de75ca90ce688a3d1d96fe4e660a --- /dev/null +++ b/spring-data-mybatis-mini-low-test/pom.xml @@ -0,0 +1,156 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + + 1.5.14.RELEASE + + + com.vonchange.common + spring-data-mybatis-mini-demo + 0.0.1-SNAPSHOT + spring-data-mybatis-mini-demo + spring-data-mybatis-mini-demo 测试 + + 2.3.9 + + 8.0.15 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-undertow + + + commons-io + commons-io + 2.5 + + + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.data + spring-data-commons + + + mysql + mysql-connector-java + 8.0.16 + + + com.vonchange.common + spring-data-mybatis-mini-low + ${spring.mybatis.mini} + + + com.h2database + h2 + 1.4.200 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.apache.ant + ant + RELEASE + compile + + + + + + aliyun-repos + Aliyun Repository + http://maven.aliyun.com/nexus/content/groups/public + + true + + + false + + + + sonatype-repos + Sonatype Repository + https://oss.sonatype.org/content/groups/public + + true + + + false + + + + sonatype-repos-s + Sonatype Repository + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + false + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + + diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/DemoApplication.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/DemoApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..1e990147e1443ca21ca3bc0d066ff1fd0726892c --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/DemoApplication.java @@ -0,0 +1,20 @@ +package com.vonchange.nine.demo; + +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.EnableMybatisMini; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +//@SpringBootApplication(exclude={JdbcConfiguration.class}) +@SpringBootApplication +//@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) +@EnableMybatisMini(basePackages ="com.vonchange.nine.demo.dao") +@EnableJpaRepositories(basePackages = "com.vonchange.nine.demo.jpa") +public class DemoApplication { + + public static void main(String[] args) { + + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/ApplicationConfig.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/ApplicationConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..88d3e46952a72abbff24176c684fde571292237e --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/ApplicationConfig.java @@ -0,0 +1,14 @@ +package com.vonchange.nine.demo.config; + +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.JdbcConfiguration; + +//@Configuration +class ApplicationConfig extends JdbcConfiguration { + + /* @Bean + public JdbcRepository initJdbcRepository(DataSource... dataSource){ + return new JdbcRepositoryReadWriteImpl(); + }*/ + + +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/DBConfig.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/DBConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..acb1f70ae5588d24cbbda780071f0a26125e6459 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/DBConfig.java @@ -0,0 +1,55 @@ +package com.vonchange.nine.demo.config; + + +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import com.vonchange.spring.data.mybatis.mini.repository.ReadDataSources; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import javax.sql.DataSource; + + +@Configuration +public class DBConfig implements InitializingBean { + @Bean(name = "dataSource") + @Primary + @ConfigurationProperties(prefix = "spring.datasource.hikari") + public DataSource mainDataSource() { + return DataSourceBuilder.create().build(); + } + + @Bean(name = "dataSourceRead") + @ConfigurationProperties(prefix = "spring.datasource.hikari") + public DataSource readDataSource() { + return DataSourceBuilder.create().build(); + } + + + //多数据源 定义 key 为你要设置@DataSourceKey的值 不建议多数据源 最好分服务 + @Bean + public DataSourceWrapper readDataSourceWrapper(@Qualifier("dataSourceRead") DataSource dataSource) { + return new DataSourceWrapper(dataSource,"dataSourceRead"); + } + //自定义 读库数据源 不自定义默认所有你设置的数据源 + //@Bean + public ReadDataSources initReadDataSources(){ + return new ReadDataSources() { + @Override + public DataSource[] allReadDataSources() { + return new DataSource[]{mainDataSource(),mainDataSource(),readDataSource()}; + } + }; + } + @Override + public void afterPropertiesSet() throws Exception { + /*DataSource dataSource=mainDataSource(); + Connection connection = DataSourceUtils.getConnection(dataSource); + DataSourceUtils.releaseConnection(connection,dataSource);*/ + } + +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/H2Dialect.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/H2Dialect.java new file mode 100644 index 0000000000000000000000000000000000000000..5f7f019ce210c2628eb660dca3ee60b721b012a3 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/H2Dialect.java @@ -0,0 +1,44 @@ +package com.vonchange.nine.demo.config; + + +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.config.Constant; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.dialect.LikeTemplate; + + +/** + *mysql方言 + * @author von_change@163.com + * 2015-6-14 下午12:47:21 + */ +public class H2Dialect implements Dialect { + + @Override + public String getPageSql(String sql, int beginNo, int pageSize) { + return StringUtils.format("{0} limit {1},{2} ", sql, ConvertUtil.toString(beginNo), ConvertUtil.toString(pageSize)); + } + + + + @Override + public int getBigDataFetchSize() { + return 200; + } + + @Override + public int getFetchSize() { + return -1; + } + + @Override + public String getDialogName() { + return Constant.Dialog.MYSQL; + } + + @Override + public LikeTemplate getLikeTemplate() { + return new LikeTemplate(" CONCAT(''%'',#'{'{0}'}',''%'') "," CONCAT(''%'',#'{'{0}'}')"," CONCAT(#'{'{0}'}',''%'') "); + } +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/IPConvert.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/IPConvert.java new file mode 100644 index 0000000000000000000000000000000000000000..2accae733e796cfb7954fff87c67138f046e8c49 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/config/IPConvert.java @@ -0,0 +1,68 @@ +package com.vonchange.nine.demo.config; + +import ch.qos.logback.classic.pattern.ClassicConverter; +import ch.qos.logback.classic.spi.ILoggingEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; + +public class IPConvert extends ClassicConverter { + private static Logger logger = LoggerFactory.getLogger(IPConvert.class); + + public static String IP_AND_ADDRESS; + + static { + try { + + Enumeration enumeration = NetworkInterface.getNetworkInterfaces(); + ArrayList ipv4Result = new ArrayList<>(); + + while (enumeration.hasMoreElements()) { + + final NetworkInterface networkInterface = enumeration.nextElement(); + final Enumeration en = networkInterface.getInetAddresses(); + + while (en.hasMoreElements()) { + + final InetAddress address = en.nextElement(); + + if (!address.isLoopbackAddress()&&address instanceof Inet4Address) { + ipv4Result.add(normalizeHostAddress(address)); + } + + } + } + // prefer ipv4 + if (!ipv4Result.isEmpty()) { + IP_AND_ADDRESS = ipv4Result.get(0); + } else { + // If failed to find,fall back to localhost + final InetAddress localHost = InetAddress.getLocalHost(); + IP_AND_ADDRESS = normalizeHostAddress(localHost); + } + } catch (SocketException e) { + logger.error("SocketException{}",e); + } catch (UnknownHostException e) { + logger.error("UnknownHostException{}",e); + } + } + + @Override + public String convert(ILoggingEvent event) { + return IP_AND_ADDRESS; + } + + public static String normalizeHostAddress(final InetAddress localHost) { + + return localHost.getHostAddress() + " | " + localHost.getHostName(); + } + +} + diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/controller/HelloController.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/controller/HelloController.java new file mode 100644 index 0000000000000000000000000000000000000000..78ba67d45a00881b42d6a085fbe0b117d0125ff3 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/controller/HelloController.java @@ -0,0 +1,31 @@ +package com.vonchange.nine.demo.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Random; + +/** + * Created by Zenger on 2018/5/21. + */ +@RestController +//@Slf4j +public class HelloController { + private static final Logger log = LoggerFactory.getLogger(HelloController.class); + + private static int num =new Random().nextInt(1000); + + @Value("${test.hello:ss}") + private String test; + @GetMapping("/test/hello") + public String hello() { + log.info("hello {}",test); + return "Demo project for Spring Boot2x ! 实例随机数"+num+test; + } + +} + + diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseQueryRepository.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseQueryRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..065f18755023cb52df7bc2182a3f1b5c8c5eff08 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseQueryRepository.java @@ -0,0 +1,16 @@ +package com.vonchange.nine.demo.dao; + +import com.vonchange.nine.demo.domain.UserBaseDO; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.support.BaseQueryRepository; +import org.springframework.data.repository.query.Param; + +import java.util.Date; +import java.util.List; + + + +public interface UserBaseQueryRepository extends BaseQueryRepository { + + List findList(@Param("userName") String userName, + @Param("createTime") Date createTime); +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseRepository.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..1259988bb8db1c297a3cf8ae69838c32d7458e8f --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseRepository.java @@ -0,0 +1,51 @@ +package com.vonchange.nine.demo.dao; + +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import com.vonchange.nine.demo.domain.SearchParam; +import com.vonchange.nine.demo.domain.UserBaseDO; +import com.vonchange.nine.demo.domain.UserBaseVO; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.BatchUpdate; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.ReadDataSource; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.support.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; + + +//@DataSourceKey("dataSourceRead") +public interface UserBaseRepository extends BaseRepository { + List findListBase(@Param("userName") String userName); + UserBaseDO findOne(@Param("userName") String userName); + @ReadDataSource + List findList(@Param("userName") String userName, + @Param("createTime") LocalDateTime createTime); + Page findList(Pageable pageable, @Param("userName") String userName,@Param("createTime") Date createTime); + String findUserName(@Param("userName") String userName); + List findListVo(@Param("userName") String userName, + @Param("createTime") Date createTime); + + List findListByBean(@Param("param") SearchParam searchParam); + + List findListByIds(@Param("userName") String userName, + @Param("createTime") Date createTime,@Param("idList")List idList); + + int updateIsDelete(@Param("isDelete") Integer isDelete,@Param("id") Long id); + + @BatchUpdate + int batchUpdate(List list); + + @BatchUpdate(size = 5000) + int batchInsert(List list); + + int updateTest(@Param("list")List list); + + List findByUserName(String test); + + int insertBatchNormal(@Param("list")List list); + + void findBigData(@Param("")AbstractPageWork abstractPageWork,@Param("userName") String userName); +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/BaseDO.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/BaseDO.java new file mode 100644 index 0000000000000000000000000000000000000000..9764f960bdabf8357827ff6261a4e76d8da4c512 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/BaseDO.java @@ -0,0 +1,65 @@ +package com.vonchange.nine.demo.domain; + +import com.vonchange.mybatis.tpl.annotation.InsertIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateDuplicateKeyIgnore; +import com.vonchange.mybatis.tpl.annotation.UpdateIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateNotNull; + +import javax.persistence.Id; +import java.util.Date; + +//@Data +//@AllArgsConstructor +//@NoArgsConstructor +//@Table(name = "user_base") +public class BaseDO { + @Id + private Long id; + @UpdateNotNull + private Integer isDelete; + @InsertIfNull(function = "now()") + @UpdateNotNull + private Date createTime; + @UpdateDuplicateKeyIgnore + @InsertIfNull(function = "now()") + @UpdateIfNull(function = "now()") + private Date updateTime; + + public BaseDO(){ + + } + + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/EnumDelete.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/EnumDelete.java new file mode 100644 index 0000000000000000000000000000000000000000..8cfc137c8454fc6722bc5cfb3634b67b0cc8f017 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/EnumDelete.java @@ -0,0 +1,38 @@ +package com.vonchange.nine.demo.domain; + +public enum EnumDelete { + deleted(1,"已删除"),unDeleted(0,"未删除"); + + private Integer value; + private String desc; + EnumDelete(Integer value, String desc){ + this.value=value; + this.desc=desc; + } + + public static EnumDelete getValue(Integer value) { + for (EnumDelete c : EnumDelete.values()) { + if (c.getValue().equals(value)) { + return c; + } + } + return null; + } + public Integer getValue() { + return value; + } + + public EnumDelete setValue(int value) { + this.value = value; + return this; + + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + } \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/SearchParam.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/SearchParam.java new file mode 100644 index 0000000000000000000000000000000000000000..dbeb8962d2807060010bbd275a8263f72b44b934 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/SearchParam.java @@ -0,0 +1,24 @@ +package com.vonchange.nine.demo.domain; + +import java.util.Date; + +public class SearchParam { + private String userName; + private Date createTime; + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseDO.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseDO.java new file mode 100644 index 0000000000000000000000000000000000000000..e2568e6fec0d6f7d993c06937a7e082e521d6688 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseDO.java @@ -0,0 +1,139 @@ +package com.vonchange.nine.demo.domain; + +import com.vonchange.mybatis.tpl.annotation.InsertIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateNotNull; + +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; +import java.util.Date; + +//@Data +//@AllArgsConstructor +//@NoArgsConstructor +@Table(name = "user_base") +public class UserBaseDO { + + //@GeneratedValue + @Id + private Long id; + //@InsertIfNull(function = "REPLACE(UUID(), '-', '')") + private String code; + @Column(name="user_name") + private String userName; + private String mobilePhone; + //@InsertIfNull("0") + @UpdateNotNull + private Integer isDelete; + @InsertIfNull(function = "now()") + @UpdateNotNull + private LocalDateTime createTime; + //@UpdateDuplicateKeyIgnore + @InsertIfNull(function = "now()") + @UpdateIfNull(function = "now()") + private Date updateTime; + private EnumDelete enumDelete; + private byte[] headImageData; + public UserBaseDO(){ + + } + public UserBaseDO(Long id,String userName,String mobilePhone,Integer isDelete,LocalDateTime createTime,Date updateTime){ + this.id=id; + this.userName=userName; + this.mobilePhone=mobilePhone; + this.isDelete=isDelete; + this.createTime=createTime; + this.updateTime=updateTime; + } + + public EnumDelete getEnumDelete() { + return enumDelete; + } + + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getMobilePhone() { + return mobilePhone; + } + + public void setMobilePhone(String mobilePhone) { + this.mobilePhone = mobilePhone; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + this.enumDelete=EnumDelete.getValue(isDelete); + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setEnumDelete(EnumDelete enumDelete) { + this.enumDelete = enumDelete; + } + + public byte[] getHeadImageData() { + return headImageData; + } + + public void setHeadImageData(byte[] headImageData) { + this.headImageData = headImageData; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "UserBaseDO{" + + "id=" + id + + ", code='" + code + '\'' + + ", userName='" + userName + '\'' + + ", mobilePhone='" + mobilePhone + '\'' + + ", isDelete=" + isDelete + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + ", enumDelete=" + enumDelete + + '}'; + } +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseVO.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseVO.java new file mode 100644 index 0000000000000000000000000000000000000000..d64320b2ad6ae44da4a06abdbcd42b17f3f51957 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseVO.java @@ -0,0 +1,41 @@ +package com.vonchange.nine.demo.domain; + +//@Data +public class UserBaseVO { + private int id; + private String userName; + private String firstPhone; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getFirstPhone() { + return firstPhone; + } + + public void setFirstPhone(String firstPhone) { + this.firstPhone = firstPhone; + } + + @Override + public String toString() { + return "UserBaseVO{" + + "id=" + id + + ", userName='" + userName + '\'' + + ", firstPhone='" + firstPhone + '\'' + + '}'; + } +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/jpa/UserBase.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/jpa/UserBase.java new file mode 100644 index 0000000000000000000000000000000000000000..3a11dcc6c6acfb1dc82db4ddfff3a2e519136029 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/jpa/UserBase.java @@ -0,0 +1,132 @@ +package com.vonchange.nine.demo.jpa; + +import com.vonchange.mybatis.tpl.annotation.InsertIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateNotNull; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; +import java.util.Date; + +//@Data +//@AllArgsConstructor +//@NoArgsConstructor +@Entity +@Table(name = "user_base") +public class UserBase { + + //@GeneratedValue + @Id + private Long id; + //@InsertIfNull(function = "REPLACE(UUID(), '-', '')") + private String code; + @Column(name="user_name") + private String userName; + private String mobilePhone; + //@InsertIfNull("0") + @UpdateNotNull + private Integer isDelete; + @InsertIfNull(function = "now()") + @UpdateNotNull + private LocalDateTime createTime; + //@UpdateDuplicateKeyIgnore + @InsertIfNull(function = "now()") + @UpdateIfNull(function = "now()") + private Date updateTime; + private byte[] headImageData; + public UserBase(){ + + } + public UserBase(Long id, String userName, String mobilePhone, Integer isDelete, LocalDateTime createTime, Date updateTime){ + this.id=id; + this.userName=userName; + this.mobilePhone=mobilePhone; + this.isDelete=isDelete; + this.createTime=createTime; + this.updateTime=updateTime; + } + + + + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getMobilePhone() { + return mobilePhone; + } + + public void setMobilePhone(String mobilePhone) { + this.mobilePhone = mobilePhone; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public byte[] getHeadImageData() { + return headImageData; + } + + public void setHeadImageData(byte[] headImageData) { + this.headImageData = headImageData; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "UserBaseDO{" + + "id=" + id + + ", code='" + code + '\'' + + ", userName='" + userName + '\'' + + ", mobilePhone='" + mobilePhone + '\'' + + ", isDelete=" + isDelete + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + '}'; + } +} diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepository.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..193a9471c8bd902d8d33624514fd98a635dffb58 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepository.java @@ -0,0 +1,16 @@ +package com.vonchange.nine.demo.jpa; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + + +@Repository +public interface UserBaseJpaRepository extends JpaRepository { + + @Query(value="from UserBase where userName = ?1 ") + List findList(String userName); + +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/util/H2DBFunctionExt.java b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/util/H2DBFunctionExt.java new file mode 100644 index 0000000000000000000000000000000000000000..8865226feb884ca96bb7d4583efbc47c94a647e2 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/main/java/com/vonchange/nine/demo/util/H2DBFunctionExt.java @@ -0,0 +1,17 @@ +package com.vonchange.nine.demo.util; + +import java.util.UUID; + +public class H2DBFunctionExt { + /** + * 用法:SELECT uuid(); H2数据库注册uuid函数:CREATE ALIAS uuid FOR + * "h2db.function.ext.H2DBFunctionExt.uuid"; + * + * @return + * @Method: uuid + * @Description: 实现MySQL数据库的uuid函数,用于生成UUID + */ + public static String uuid() { + return UUID.randomUUID().toString(); + } +} diff --git a/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/DemoApplicationTests.java b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/DemoApplicationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..11e13592f32043ae426c78a02e6709ad824c67da --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/DemoApplicationTests.java @@ -0,0 +1,16 @@ +package com.vonchange.nine.demo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class DemoApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/dao/UserBaseRepositoryTest.java b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/dao/UserBaseRepositoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..aee1bbd5f7c72d71cf76971f4c9765159620c5f5 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/dao/UserBaseRepositoryTest.java @@ -0,0 +1,301 @@ +package com.vonchange.nine.demo.dao; + +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import com.vonchange.nine.demo.domain.SearchParam; +import com.vonchange.nine.demo.domain.UserBaseDO; +import com.vonchange.nine.demo.domain.UserBaseVO; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + + +@RunWith(SpringRunner.class) +@SpringBootTest +//@Transactional +//@Slf4j +public class UserBaseRepositoryTest { + private static final Logger log = LoggerFactory.getLogger(UserBaseRepositoryTest.class); + + @Resource + private UserBaseRepository userBaseRepository; + + @Test + public void findList() { + List userBaseDOList = userBaseRepository.findList("张三日子",LocalDateTime.now().plusHours(1L)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + + @Test + public void findOne() { + UserBaseDO userBaseDO = userBaseRepository.findOne("test"); + log.info("\n {}",userBaseDO.toString()); + } + + @Test + public void findListBase() { + List userBaseDOList = userBaseRepository.findListBase("张三日子"); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + + @Test + public void findListByBean() { + SearchParam searchParam = new SearchParam(); + searchParam.setUserName("张三日子"); + List userBaseDOList = userBaseRepository.findListByBean(searchParam); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findListVo() { + List userBaseVOList = userBaseRepository.findListVo("张三日子",new Date()); + userBaseVOList.forEach(userBaseVO -> { + log.info("\n {}",userBaseVO.toString()); + }); + } + @Test + public void findListByPage() { + Pageable pageable = new PageRequest(0,3); + //PageRequest.of(0,3); + Page personRepositoryBy = userBaseRepository.findList(pageable,"张三日子",null); + log.info("\n {}",personRepositoryBy.toString()); + personRepositoryBy.getContent().forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findUserName() { + String userName = userBaseRepository.findUserName("test"); + log.info("\n userName {}",userName); + } + + @Test + public void findById() { + UserBaseDO userBaseDO = userBaseRepository.findById(1L); + log.info("\n userBaseDO {}",userBaseDO); + } + + @Test + public void findByXX() { + List userBaseDOList = userBaseRepository.findByUserName("test"); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n userBaseDO {}",userBaseDO); + }); + + } + @Test + public void findListByIds() { + List userBaseDOListQ = userBaseRepository.findListByIds("test",null,null); + userBaseDOListQ.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + List userBaseDOList = userBaseRepository.findListByIds("test",new Date(), Arrays.asList(1L,2L)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + + } + + @Test + @Transactional + @Rollback + public void updateIsDelete() { + int result = userBaseRepository.updateIsDelete(1,1L); + log.info("result {}",result); + } + @Test + public void insert() throws IOException { + UserBaseDO userBaseDO = new UserBaseDO(); + //userBaseDO.setId(3L); + userBaseDO.setUserName("test"); + userBaseDO.setCode(UUID.randomUUID().toString()); + //userBaseDO.setHeadImageData(FileUtils.readFileToByteArray(new File("/Users/vonchange/work/docment/cat.jpg"))); + // userBaseDO.setCode("1"); + //userBaseDO.setCreateTime(LocalDateTime.now().plusHours(1L)); + int result = userBaseRepository.insert(userBaseDO); + log.info("\nresult {} {} ",result,userBaseDO.toString()); + UserBaseDO userBaseDOFind =userBaseRepository.findById(userBaseDO.getId()); + //FileUtils.writeByteArrayToFile(new File("/Users/vonchange/work/docment/catcc.jpg"),userBaseDOFind.getHeadImageData()); + log.info("\nuserBaseDOFind {}",userBaseDOFind.toString()); + } + + + @Test + public void insertDuplicateKey() { + UserBaseDO userBaseDO = new UserBaseDO(); + userBaseDO.setUserName("UUUUU"); + userBaseDO.setMobilePhone("110"); + int result = userBaseRepository.insertDuplicateKey(userBaseDO); + log.info("\nresult {} {}",result,userBaseDO.getId()); + + } + @Test + //@Transactional + //@Rollback + public void update() { + UserBaseDO userBaseDO = new UserBaseDO(); + userBaseDO.setUserName("test_ss"); + userBaseDO.setId(1L); + int result = userBaseRepository.update(userBaseDO); + log.info("\nresult {}",result); + //UserBaseDO userBaseDOFind =userBaseRepository.findById(1L); + //log.info("\nuserBaseDOFind {}",userBaseDOFind.toString()); + } + + @Test + public void updateAllField() { + UserBaseDO userBaseDO = new UserBaseDO(); + userBaseDO.setUserName(null); + userBaseDO.setId(1L); + int result = userBaseRepository.updateAllField(userBaseDO); + log.info("\nresult {}",result); + } + + //13 + + /** + * 批量插入 + */ + @Test + @Transactional + public void insertBatch() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatch(list,5000); + log.info("id {}",list.get(0).getId()); + log.info("result {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//1554 + } + + + + /** + * 批量插入 + */ + @Test + @Transactional + public void insertBatchDuplicateKey() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatchDuplicateKey(list,5000); + log.info("id {}",list.get(0).getId()); + log.info("result {}",resultx); + int resulty = userBaseRepository.insertBatchDuplicateKey(list,5000); + log.info("result {}",resulty); + log.info("time {}",System.currentTimeMillis()-start);//1554 + } + + @Test + //@Transactional + //@Rollback + public void updateBatchBySqlId() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<2;i++) { + list.add(new UserBaseDO(1L+i,"RRR"+i,null,null,null,new Date())); + } + int resultx = userBaseRepository.batchUpdate(list); + log.info("resultx {}",resultx); + log.info("time {}",System.currentTimeMillis()-start); + } + + @Test + @Transactional + //@Rollback + public void insertBatchNormal() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatchNormal(list); + System.out.println(list.get(0).getId()); + log.info("resultx {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//908 + } + + @Test + @Transactional + //@Rollback + public void bachUpdate() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.batchInsert(list); + System.out.println(list.get(0).getId()); + log.info("resultx {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//563 + } + + + @Test + @Transactional + public void findBigData() { + + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10016;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatch(list,5000); + log.info("id {}",list.get(0).getId()); + log.info("result {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//1554 + AbstractPageWork abstractPageWork = new AbstractPageWork() { + @Override + protected void doPage(List pageContentList, int pageNum, Map extData) { + pageContentList.forEach(userBaseDO -> { + log.info("{}",userBaseDO.toString()); + }); + + } + + @Override + protected int getPageSize() { + return 500; + } + }; + userBaseRepository.findBigData(abstractPageWork,"三"); + log.info("{} {} {}",abstractPageWork.getSize(),abstractPageWork.getTotalPages(),abstractPageWork.getTotalElements()); + } +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepositoryTest.java b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepositoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cb3d3918f4f58f1e2cb2e9b8d66d9f178bab465a --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepositoryTest.java @@ -0,0 +1,34 @@ +package com.vonchange.nine.demo.jpa; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class UserBaseJpaRepositoryTest { + + private static final Logger log = LoggerFactory.getLogger(UserBaseJpaRepositoryTest.class); + @Resource + private UserBaseJpaRepository userBaseJpaRepository; + + @Test + public void findList() { + List userBaseList = userBaseJpaRepository.findList("张三日子"); + userBaseList.forEach(userBase -> { + log.info("\n {}",userBase.toString()); + }); + } + @Test + public void ttt() { + String goodsId= "xxx12345"; + System.out.println(goodsId.substring(goodsId.length()-1)); + } + +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/service/impl/JdbcQueryServiceImplTest.java b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/service/impl/JdbcQueryServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..400076c17b0b38088493f8f6bd7d098232186a85 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/java/com/vonchange/nine/demo/service/impl/JdbcQueryServiceImplTest.java @@ -0,0 +1,73 @@ +package com.vonchange.nine.demo.service.impl; + +import com.vonchange.common.util.map.MyHashMap; +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.nine.demo.domain.UserBaseDO; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class JdbcQueryServiceImplTest { + private static final Logger log = LoggerFactory.getLogger(JdbcQueryServiceImplTest.class); + @Resource + private JdbcRepository jdbcRepository; + @Test + public void findList() { + List userBaseDOList =jdbcRepository.queryList(UserBaseDO.class,"sql.UserBaseRepository.findList",new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findListToMap() { + List> userBaseDOList =jdbcRepository.queryMapList("sql.UserBaseRepository.findList",new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findListBySql() { + String sql ="select * from user_base\n" + + "where user_name = #{userName}"; + List userBaseDOList = jdbcRepository.queryList(UserBaseDO.class,"@sql"+sql,new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + + @Test + public void findListByMd() { + String sql ="### id findListByMd \n" + + "#### version 1.0 \n> 查询用户列表 含sql 片段\n" + + "\n" + + "```\n" + + "-- main\n" + + "select * from user_base\n" + + "where [@sql findListWhereSql]\n" + + "```\n" + + "\n" + + "> sql 片段\n" + + "```\n" + + "-- findListWhereSql\n" + + "user_name = #{userName} and 1=1\n" + + "{@and create_time < createTime}\n" + + "```"; + List userBaseDOList = jdbcRepository.queryList(UserBaseDO.class,"@md"+sql,new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/test/resources/application-dev.yml b/spring-data-mybatis-mini-low-test/src/test/resources/application-dev.yml new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/resources/application-dev.yml @@ -0,0 +1 @@ + diff --git a/spring-data-mybatis-mini-low-test/src/test/resources/application-local.yml b/spring-data-mybatis-mini-low-test/src/test/resources/application-local.yml new file mode 100644 index 0000000000000000000000000000000000000000..abcd8afc50f66c5edc381166e50d7f928da6eaaa --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/resources/application-local.yml @@ -0,0 +1,17 @@ +server: + port: 9001 + +mybatis-mini: + isReadAllScopeOpen: false + logRead: true + logWrite: true + logFullSql: true + +spring: + datasource: + hikari: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/test_b?autoReconnect=true&rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT + username: root + password: 123456 +# \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/test/resources/application-test.yml b/spring-data-mybatis-mini-low-test/src/test/resources/application-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..af4a00b68e952f3387e008768db1825cca810a10 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/resources/application-test.yml @@ -0,0 +1,18 @@ +server: + port: 9001 + + +mybatis-mini: + dialect: com.vonchange.nine.demo.config.H2Dialect + logRead: true + logWrite: true + logFullSql: true + +spring: + datasource: + hikari: + driver-class-name: org.h2.Driver + #jdbc-url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 + url: jdbc:h2:mem:db_users;MODE=MYSQL;INIT=RUNSCRIPT FROM './src/test/resources/db-init.sql' + username: root + password: 123456 diff --git a/spring-data-mybatis-mini-low-test/src/test/resources/application.yml b/spring-data-mybatis-mini-low-test/src/test/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..466b6eabc64d622c34b1d42f1197b39ff0bc4610 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/resources/application.yml @@ -0,0 +1,34 @@ +spring: + profiles: + active: test + application: + name: demo + datasource: + hikari: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/nine_user?autoReconnect=true&rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT + username: root + password: 123456 + connection-timeout: 20000 + minimum-idle: 5 + maximum-pool-size: 500 + idle-timeout: 60000 + max-lifetime: 600000 + leak-detection-threshold: 20000 + jpa: + database: MySQL + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + show-sql: true + hibernate: + ddl-auto: none + + +logback: + aliyun: + endpoint: cn-hangzhou.log.aliyuncs.com + + + + + + diff --git a/spring-data-mybatis-mini-low-test/src/test/resources/db-init.sql b/spring-data-mybatis-mini-low-test/src/test/resources/db-init.sql new file mode 100644 index 0000000000000000000000000000000000000000..4e30b84dc88f3a0511d6d7e26689bab0b170eab0 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/resources/db-init.sql @@ -0,0 +1,19 @@ +SET MODE=MySQL; +SET FOREIGN_KEY_CHECKS=0; +drop table if exists `user_base`; +CREATE TABLE IF NOT EXISTS `user_base` ( + `id` bigint(13) NOT NULL AUTO_INCREMENT COMMENT 'id序列,自增', + `code` varchar(36) DEFAULT NULL COMMENT '编码', + `user_name` varchar(30) DEFAULT NULL COMMENT '用户名', + `mobile_phone` varchar(13) DEFAULT NULL COMMENT '手机号', + `address` varchar(20) DEFAULT NULL COMMENT 'address', + `is_delete` tinyint(1) DEFAULT '0' COMMENT '是否已删除', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `head_image_data` blob DEFAULT NULL COMMENT '头像', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + insert into user_base(id,code,user_name,mobile_phone,address,create_time) values (1,UUID(),'test','120','xxx',now()); + insert into user_base(user_name,mobile_phone,address,create_time) values ('李4','110','xxx额',now()); + insert into user_base(user_name,mobile_phone,address,create_time,update_time) values ('张三日子','911','xxx是啥',now(),now()); + insert into user_base(user_name,mobile_phone,address,create_time) values ('test','333','ufo',now()); \ No newline at end of file diff --git a/spring-data-mybatis-mini-low-test/src/test/resources/logback-spring.xml b/spring-data-mybatis-mini-low-test/src/test/resources/logback-spring.xml new file mode 100644 index 0000000000000000000000000000000000000000..64951a56ed0adae9afefedc809d82f714c775ee4 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/resources/logback-spring.xml @@ -0,0 +1,49 @@ + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS}|${appDev}|${appName}|%-5level|%ipandhostname|[%thread]| %logger{50}| %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-mybatis-mini-low-test/src/test/resources/sql/UserBaseRepository.md b/spring-data-mybatis-mini-low-test/src/test/resources/sql/UserBaseRepository.md new file mode 100644 index 0000000000000000000000000000000000000000..2f791bda9ecea009314b5fc13e4f083951a2ad13 --- /dev/null +++ b/spring-data-mybatis-mini-low-test/src/test/resources/sql/UserBaseRepository.md @@ -0,0 +1,141 @@ +> 查询用户列表 +``` +-- findListX + +select * from user_base +where user_name = #{userName} +and create_time <= #{createTime} +``` + +``` +-- findListBase +select * from user_base where user_name = #{userName} +``` + + +``` +-- findOne +select * from user_base +where user_name = #{userName} +``` +> 查询用户列表 含sql 片段 + +``` +-- findList +select * from user_base +where [@sql findListWhereSql] +``` + +``` +-- findListVo +select * from user_base +where [@sql findListWhereSql] +``` + +``` +-- findListByBean +select * from user_base + +[@and user_name like param.userName] +[@and user_name like param.userName%] +[@and create_time <= param.createTime] + +``` + + + + +> sql 片段 +``` +-- findListWhereSql +user_name = #{userName} and 1=1 +[@and create_time < createTime] +``` + +> 查询用户名 返回1个字段的情况 比如查询行数等 +``` +-- findUserName +SELECT user_name FROM user_base +WHERE user_name = #{userName} +``` + + +> 根据Id列表查询列表 +``` +-- findListByIdsx +SELECT * FROM user_base + + and user_name <> #{userName} + and id in #{item} + and create_time < #{createTime} + + +``` + +> [@and create_time < createTime] + +> 根据Id列表查询列表 简写if 和in查询 可混用 +``` +-- findListByIds +SELECT * FROM user_base + +[@and id in #{idList:in} and user_name like #{userName:like}] +[@and user_name like userName%] +[@and id in idList] + and create_time < #{createTime} + +``` + +> 更新方法 update 开头 + +``` +-- updateIsDelete +update user_base set is_delete = #{isDelete} where id =#{id} +``` + +``` +-- batchUpdate +update user_base set is_delete = IFNULL(#{isDelete},is_delete),user_name =#{userName} where id =#{id} +``` + + +``` +-- batchInsert +insert into user_base(`user_name`,`mobile_phone`,create_time) values +(#{userName},#{mobilePhone},#{createTime}) +``` + +``` +-- updateTest + +insert into user_base(`user_name`,`mobile_phone`) values (#{item.userName},#{item.firstPhone}); + + +``` + +``` +-- insertBatchNormal +insert into user_base(`user_name`,`mobile_phone`,create_time) values + +(#{item.userName},#{item.mobilePhone},#{item.createTime}) + + +``` + +``` +-- insertBatchNormalX +insert into user_base(`id`,`code`,`user_name`,`mobile_phone`,`is_delete`,`create_time`,`update_time`,`head_image_data`) values + +(IFNULL(#{item.id},`id`),IFNULL(#{item.code},`code`),IFNULL(#{item.userName},`user_name`),IFNULL(#{item.mobilePhone},`mobile_phone`) +,IFNULL(#{item.isDelete},`is_delete`),IFNULL(#{item.createTime},now()),IFNULL(#{item.updateTime},now()),IFNULL(#{item.headImageData},`head_image_data`)) + +``` + + +``` +-- findBigData +select * from user_base + +[@and user_name like userName] + +``` \ No newline at end of file diff --git a/spring-data-mybatis-mini-low/pom.xml b/spring-data-mybatis-mini-low/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..de4334f41e9641afddd9f4e8b6ac342b6ff840c3 --- /dev/null +++ b/spring-data-mybatis-mini-low/pom.xml @@ -0,0 +1,67 @@ + + + + mybatis-mini-parant + com.vonchange.common + 2.3.9 + + 4.0.0 + spring-data-mybatis-mini-low + 2.3.9 + + + 1.13.1.RELEASE + 4.3.18.RELEASE + 8.0.15 + + + + + com.vonchange.common + mybatis-mini + 2.3.9 + + + org.springframework.data + spring-data-commons + ${springdata.commons} + provided + + + org.springframework + spring-tx + ${spring.commons} + provided + + + + org.springframework + spring-context + ${spring.commons} + provided + + + + org.springframework + spring-beans + ${spring.commons} + provided + + + + org.springframework + spring-jdbc + ${spring.commons} + provided + + + + org.springframework + spring-core + ${spring.commons} + provided + + + \ No newline at end of file diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/BindParameterWrapper.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/BindParameterWrapper.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/BindParameterWrapper.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/BindParameterWrapper.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/ConfigInfo.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/ConfigInfo.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/ConfigInfo.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/ConfigInfo.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelper.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelper.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelper.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelper.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelperImpl.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelperImpl.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelperImpl.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelperImpl.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableJdbcAuditing.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableJdbcAuditing.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableJdbcAuditing.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableJdbcAuditing.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableMybatisMini.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableMybatisMini.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableMybatisMini.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableMybatisMini.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcAuditingRegistrar.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcAuditingRegistrar.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcAuditingRegistrar.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcAuditingRegistrar.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcConfiguration.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcConfiguration.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcConfiguration.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcConfiguration.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoriesRegistrar.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoriesRegistrar.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoriesRegistrar.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoriesRegistrar.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoryConfigExtension.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoryConfigExtension.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoryConfigExtension.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoryConfigExtension.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/BatchUpdate.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/BatchUpdate.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/BatchUpdate.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/BatchUpdate.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/DataSourceKey.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/DataSourceKey.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/DataSourceKey.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/DataSourceKey.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/ReadDataSource.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/ReadDataSource.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/ReadDataSource.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/ReadDataSource.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/SqlPackage.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/SqlPackage.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/SqlPackage.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/SqlPackage.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseModel.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseModel.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseModel.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseModel.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseQueryRepository.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseQueryRepository.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseQueryRepository.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseQueryRepository.java diff --git a/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseRepository.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..0d34369fa6887d992fcaa841779893165d946738 --- /dev/null +++ b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseRepository.java @@ -0,0 +1,76 @@ +/* + * Copyright 2008-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +import org.springframework.data.repository.NoRepositoryBean; +import org.springframework.data.repository.Repository; + +import java.io.Serializable; +import java.util.List; + +/** + * Interface for generic CRUD operations on a repository for a specific type. + * + * @author Oliver Gierke + * @author Eberhard Wolff + */ +@NoRepositoryBean +public interface BaseRepository extends Repository { + + /** + * Saves a given entity. Use the returned instance for further operations as the save operation might have changed the + * entity instance completely. + * + * @param entity must not be {@literal null}. + * @return the saved entity; will never be {@literal null}. + * @throws IllegalArgumentException in case the given {@literal entity} is {@literal null}. + */ + int insert(S entity); + + int insertBatch(List entitys,int batchSize); + + int insertBatchDuplicateKey(List entitys,int batchSize); + + /** + * insert into on duplication key + * @param entity + * @param + */ + int insertDuplicateKey(S entity); + + /** + * 默认只更新不为空的字段 + * @param entity + * @param + */ + int update(S entity); + + /** + * 更新所有字段 + * @param entity + * @param + */ + int updateAllField(S entity); + /** + * Retrieves an entity by its id. + * + * @param id must not be {@literal null}. + * @return the entity with the given id or {@literal Optional#empty()} if none found. + * @throws IllegalArgumentException if {@literal id} is {@literal null}. + */ + T findById(ID id); + +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryLookupStrategy.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryLookupStrategy.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryLookupStrategy.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryLookupStrategy.java diff --git a/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryMethod.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..3a3e6de1a0b679bcb90da01c2c239b60f59f259b --- /dev/null +++ b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryMethod.java @@ -0,0 +1,59 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + + +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.BatchUpdate; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.ReadDataSource; +import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.data.projection.ProjectionFactory; +import org.springframework.data.repository.core.RepositoryMetadata; +import org.springframework.data.repository.query.QueryMethod; + +import java.lang.reflect.Method; + +/** + * {QueryMethod} implementation that implements a method by executing the query from a { Query} annotation on + * that method. Binds method arguments to named parameters in the SQL statement. + * + * @author Jens Schauder + * @author Kazuki Shimizu + */ +public class JdbcQueryMethod extends QueryMethod { + + private final Method method; + + public JdbcQueryMethod(Method method, RepositoryMetadata metadata, ProjectionFactory factory) { + super(method, metadata, factory); + this.method = method; + } + public boolean isReadDataSource() { + return AnnotationUtils.findAnnotation(method, ReadDataSource.class) != null; + } + + public boolean isBatchUpdate() { + return AnnotationUtils.findAnnotation(method, BatchUpdate.class) != null; + } + + public int getBatchSize() { + return AnnotationUtils.findAnnotation(method, BatchUpdate.class).size(); + } + + + + + +} diff --git a/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactory.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactory.java new file mode 100644 index 0000000000000000000000000000000000000000..6d4e6b28c0aee262e1ae18699df16629210cb817 --- /dev/null +++ b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactory.java @@ -0,0 +1,110 @@ +/* + * Copyright 2017-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.jdbc.abstractjdbc.util.markdown.MarkdownUtil; +import com.vonchange.mybatis.tpl.EntityUtil; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.ConfigInfo; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.DataSourceWrapperHelper; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.DataSourceKey; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.SqlPackage; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.data.repository.core.EntityInformation; +import org.springframework.data.repository.core.RepositoryInformation; +import org.springframework.data.repository.core.RepositoryMetadata; +import org.springframework.data.repository.core.support.RepositoryFactorySupport; +import org.springframework.data.repository.query.EvaluationContextProvider; +import org.springframework.data.repository.query.QueryLookupStrategy; + +import java.io.Serializable; + +/** + * Creates repository implementation based on JDBC. + * + * @author Jens Schauder + * @author Greg Turnquist + * @author Christoph Strobl + * @author Mark Paluch + */ +public class JdbcRepositoryFactory extends RepositoryFactorySupport { + + + private final JdbcRepository operations; + private final DataSourceWrapperHelper dataSourceWrapperHelper; + + /** + * + * and {@link ApplicationEventPublisher}. + * + * @param operations must not be {@literal null}. + */ + public JdbcRepositoryFactory(@Qualifier("jdbcRepository")JdbcRepository operations, DataSourceWrapperHelper dataSourceWrapperHelper) { + this.operations = operations; + this.dataSourceWrapperHelper=dataSourceWrapperHelper; + } + + + @Override + public EntityInformation getEntityInformation(Class aClass) { + return null; + } + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getTargetRepository(org.springframework.data.repository.core.RepositoryInformation) + */ + @Override + protected Object getTargetRepository(RepositoryInformation repositoryInformation) { + Class domainType =repositoryInformation.getDomainType(); + if(!domainType.equals(BaseModel.class)){ + EntityUtil.initEntityInfo(domainType); + } + String interfaceName =repositoryInformation.getRepositoryInterface().getSimpleName(); + SqlPackage sqlPackage= repositoryInformation.getRepositoryInterface().getAnnotation(SqlPackage.class); + String configLoc=null!=sqlPackage?sqlPackage.value():"sql"; + if(MarkdownUtil.markdownFileExist(configLoc,interfaceName+".md")){ + MarkdownUtil.readMarkdownFile(configLoc,interfaceName+".md",false); + } + DataSourceKey dataSourceKey=repositoryInformation.getRepositoryInterface().getAnnotation(DataSourceKey.class); + String dataSourceKeyValue=null!=dataSourceKey?dataSourceKey.value():null; + ConfigInfo configInfo= new ConfigInfo(); + configInfo.setType(repositoryInformation.getDomainType()); + configInfo.setDataSourceWrapper(null!=dataSourceKeyValue?dataSourceWrapperHelper.getDataSourceWrapperByKey(dataSourceKeyValue):null); + return new SimpleJdbcRepository<>(operations,configInfo); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.RepositoryFactorySupport#getRepositoryBaseClass(org.springframework.data.repository.core.RepositoryMetadata) + */ + @Override + protected Class getRepositoryBaseClass(RepositoryMetadata repositoryMetadata) { + return SimpleJdbcRepository.class; + } + + @Override + protected QueryLookupStrategy getQueryLookupStrategy( QueryLookupStrategy.Key key, EvaluationContextProvider evaluationContextProvider) { + if (key != null // + && key != QueryLookupStrategy.Key.USE_DECLARED_QUERY // + && key != QueryLookupStrategy.Key.CREATE_IF_NOT_FOUND // + ) { + throw new IllegalArgumentException(String.format("Unsupported query lookup strategy %s!", key)); + } + return new JdbcQueryLookupStrategy( operations,dataSourceWrapperHelper); + } + +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactoryBean.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactoryBean.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactoryBean.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactoryBean.java diff --git a/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java new file mode 100644 index 0000000000000000000000000000000000000000..f6703dbcc1ddac76184702ca4320f41e72899c2e --- /dev/null +++ b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java @@ -0,0 +1,175 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +import com.vonchange.common.util.ClazzUtils; +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.BindParameterWrapper; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.ConfigInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.dao.EmptyResultDataAccessException; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.query.Parameter; +import org.springframework.data.repository.query.Parameters; +import org.springframework.data.repository.query.RepositoryQuery; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; + +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * A query to be executed based on a repository method, it's annotated SQL query and the arguments provided to the + * method. + * + * @author Jens Schauder + * @author Kazuki Shimizu + * @author Oliver Gierke + * @author Maciej Walkowiak + */ + +class JdbcRepositoryQuery implements RepositoryQuery { + private static final Logger log = LoggerFactory.getLogger(JdbcRepositoryQuery.class); + private static final String PARAMETER_NEEDS_TO_BE_NAMED = "For queries with named parameters you need to provide names for method parameters. Use @Param for query method parameters, or when on Java 8+ use the javac flag -parameters."; + + private final JdbcQueryMethod queryMethod; + private final JdbcRepository operations; + private final ConfigInfo configInfo; + + /** + * Creates a new {@link JdbcRepositoryQuery} for the given {@link JdbcQueryMethod}, and + * {@link RowMapper}. + * + * @param queryMethod must not be {@literal null}. + * @param operations must not be {@literal null}. + */ + JdbcRepositoryQuery(JdbcQueryMethod queryMethod, @Qualifier("jdbcRepository") JdbcRepository operations, ConfigInfo configInfo) { + + Assert.notNull(queryMethod, "Query method must not be null!"); + Assert.notNull(operations, "NamedParameterJdbcOperations must not be null!"); + Assert.notNull(configInfo, "configLocation must not be null!"); + this.queryMethod = queryMethod; + this.operations = operations; + this.configInfo=configInfo; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.query.RepositoryQuery#execute(java.lang.Object[]) + */ + @Override + public Object execute(Object[] objects) { + return executeDo(objects); + } + + @SuppressWarnings("unchecked") + private Object executeDo(Object[] objects){ + BindParameterWrapper parameters = bindParameter(objects); + String sqlId= configInfo.getLocation()+"."+configInfo.getMethod(); + DataSourceWrapper dataSourceWrapper = configInfo.getDataSourceWrapper(); + if(null==dataSourceWrapper&&queryMethod.isReadDataSource()){ + dataSourceWrapper=operations.getReadDataSource(); + } + if (queryMethod.isBatchUpdate()){ + return operations.batchUpdate(dataSourceWrapper,sqlId,(List)parameters.getFirstParam(),queryMethod.getBatchSize()); + } + if (configInfo.getMethod().startsWith("update")||configInfo.getMethod().startsWith("delete")) { + int updatedCount = operations.update(dataSourceWrapper,sqlId,parameters.getParameter()); + Class returnedObjectType = queryMethod.getReturnedObjectType(); + return (returnedObjectType == boolean.class || returnedObjectType == Boolean.class) ? updatedCount != 0 + : updatedCount; + } + if (configInfo.getMethod().startsWith("insert")||configInfo.getMethod().startsWith("save")) { + return operations.insert(dataSourceWrapper,sqlId,parameters.getParameter()); + } + if(null!=parameters.getAbstractPageWork()){ + operations.queryBigData(dataSourceWrapper,parameters.getAbstractPageWorkClass(),sqlId,parameters.getAbstractPageWork(),parameters.getParameter()); + } + if (queryMethod.isCollectionQuery() || queryMethod.isStreamQuery()) { + return operations.queryList(dataSourceWrapper,queryMethod.getReturnedObjectType(), sqlId,parameters.getParameter()); + } + if(queryMethod.isPageQuery()){ + return operations.queryPage(dataSourceWrapper,queryMethod.getReturnedObjectType(), sqlId,parameters.getPageable(),parameters.getParameter()); + } + + if(ClazzUtils.isBaseType(queryMethod.getReturnedObjectType())){ + return operations.queryOneColumn(dataSourceWrapper,queryMethod.getReturnedObjectType(),sqlId,parameters.getParameter()); + } + try { + return operations.queryOne(dataSourceWrapper,queryMethod.getReturnedObjectType(),sqlId,parameters.getParameter()); + } catch (EmptyResultDataAccessException e) { + return null; + } + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.query.RepositoryQuery#getQueryMethod() + */ + @Override + public JdbcQueryMethod getQueryMethod() { + return queryMethod; + } + + + private BindParameterWrapper bindParameter(Object[] objects) { + Parameters parameters= queryMethod.getParameters(); + Map map = new HashMap<>(); + BindParameterWrapper bindParameterWrapper = new BindParameterWrapper(); + if(objects.length>0){ + if(parameters.getPageableIndex()>=0){ + bindParameterWrapper.setPageable((Pageable)objects[parameters.getPageableIndex()]); + } + Class type = queryMethod.getParameters().getParameter(0).getType(); + if(ClassUtils.isAssignable(AbstractPageWork.class, type)){ + bindParameterWrapper.setAbstractPageWork((AbstractPageWork) objects[0]); + Type superClass = objects[0].getClass().getGenericSuperclass(); + if( superClass instanceof ParameterizedType ){ + ParameterizedType pType = (ParameterizedType)superClass; + bindParameterWrapper.setAbstractPageWorkClass((Class) pType.getActualTypeArguments()[0] ); + } + } + bindParameterWrapper.setFirstParam(objects[0]); + } + if(queryMethod.isBatchUpdate()){ + return bindParameterWrapper; + } + for (Parameter p:queryMethod.getParameters().getBindableParameters()) { + String parameterName = p.getName(); + if(null==parameterName){ + throw new IllegalStateException(PARAMETER_NEEDS_TO_BE_NAMED); + } + map.put(parameterName, objects[p.getIndex()]); + } + bindParameterWrapper.setParameter(map); + return bindParameterWrapper; + } + + + + + + + +} diff --git a/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/SimpleJdbcRepository.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/SimpleJdbcRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..403e6666bc59d209df2dc5142338e1e2807e543b --- /dev/null +++ b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/SimpleJdbcRepository.java @@ -0,0 +1,82 @@ +/* + * Copyright 2017-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.ConfigInfo; +import org.springframework.beans.factory.annotation.Qualifier; + +import java.io.Serializable; +import java.util.List; + +/** + * @author Jens Schauder + * @author Oliver Gierke + */ + +public class SimpleJdbcRepository implements BaseRepository { + + private final JdbcRepository entityOperations; + private final ConfigInfo configInfo; + + public SimpleJdbcRepository(@Qualifier("jdbcRepository")JdbcRepository entityOperations, ConfigInfo configInfo) { + this.entityOperations = entityOperations; + this.configInfo = configInfo; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.CrudRepository#save(S) + */ + @Override + @SuppressWarnings("unchecked") + public int insert(S instance) { + return entityOperations.insert(configInfo.getDataSourceWrapper(),instance); + } + + @Override + public int insertBatch(List entitys,int batchSize) { + return entityOperations.insertBatch(configInfo.getDataSourceWrapper(),entitys,batchSize); + } + @Override + public int insertBatchDuplicateKey(List entitys,int batchSize){ + return entityOperations.insertBatchDuplicateKey(configInfo.getDataSourceWrapper(),entitys,batchSize); + } + @Override + @SuppressWarnings("unchecked") + public int insertDuplicateKey(S entity) { + return entityOperations.insertDuplicateKey(configInfo.getDataSourceWrapper(),entity); + } + + + @Override + public int update(S entity) { + return entityOperations.update(configInfo.getDataSourceWrapper(),entity); + } + + @Override + public int updateAllField(S entity) { + return entityOperations.updateAllField(configInfo.getDataSourceWrapper(),entity); + } + + + @Override + @SuppressWarnings("unchecked") + public T findById(ID id) { + return (T) entityOperations.queryById(configInfo.getDataSourceWrapper(),configInfo.getType(),id); + } + +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/DataSourceInSql.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/DataSourceInSql.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/repository/DataSourceInSql.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/DataSourceInSql.java diff --git a/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..b06ea441490611cabf8dd7e249a3a07de94fb279 --- /dev/null +++ b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java @@ -0,0 +1,138 @@ +package com.vonchange.spring.data.mybatis.mini.repository; + +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import com.vonchange.jdbc.springjdbc.repository.AbstractJbdcRepositoryMysql; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.dialect.MySQLDialect; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.beans.factory.annotation.Value; + +import javax.sql.DataSource; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + + +public class JdbcRepositorySpringDataImpl extends AbstractJbdcRepositoryMysql implements JdbcRepository { + private static final Logger log = LoggerFactory.getLogger(JdbcRepositorySpringDataImpl.class); + private static final Random RANDOM = new Random(); + private DataSource[] dataSources; + private DataSource dataSource; + private DataSourceInSql dataSourceInSql; + private ReadDataSources readDataSources; + @Value("${mybatis-mini.isReadAllScopeOpen:false}") + private boolean isReadAllScopeOpen; + @Value("${mybatis-mini.batchSize:5000}") + private int batchSize; + @Value("${mybatis-mini.logWrite:false}") + private boolean logWrite; + @Value("${mybatis-mini.logRead:false}") + private boolean logRead; + @Value("${mybatis-mini.logFullSql:false}") + private boolean logFullSql; + @Value("${mybatis-mini.dialect:}") + private String dialect; + @Autowired + public void setDataSource(@Qualifier("dataSource") DataSource dataSource) { + this.dataSource = dataSource; + } + + private static final String DATA_SOURCE_NAME="dataSource"; + public JdbcRepositorySpringDataImpl(DataSource... dataSources){ + this.dataSources=dataSources; + } + + @Override + protected Dialect getDefaultDialect() { + if("".equals(dialect)){ + return new MySQLDialect(); + } + try { + return (Dialect) Class.forName(dialect).getDeclaredConstructor().newInstance(); + } catch (Exception e) { + log.error("no dialect {}",dialect,e); + } + return new MySQLDialect(); + } + @Autowired(required = false) + public void setDataSourceInSql(DataSourceInSql dataSourceInSql) { + this.dataSourceInSql = dataSourceInSql; + } + @Autowired(required = false) + public void setReadDataSources(ReadDataSources readDataSources) { + this.readDataSources = readDataSources; + } + + @Override + public DataSourceWrapper getReadDataSource() { + DataSource[] dataSourcesRead; + if(null!=readDataSources&&null!=readDataSources.allReadDataSources()){ + dataSourcesRead=readDataSources.allReadDataSources(); + }else{ + dataSourcesRead=dataSources; + } + if(null==dataSourcesRead||dataSourcesRead.length==0){ + throw new MybatisMinRuntimeException("no dataSource"); + } + List dataSourceWrapperList = new ArrayList<>(); + int i=0; + for (DataSource dataSource: dataSourcesRead) { + dataSourceWrapperList.add(new DataSourceWrapper(dataSource,DATA_SOURCE_NAME+((i==0)?"":i))); + i++; + } + int random =RANDOM.nextInt(dataSourceWrapperList.size()); + log.debug("dataSource read random {}",random); + return dataSourceWrapperList.get(random); + } + + @Override + protected DataSourceWrapper getWriteDataSource() { + if(null==dataSources||dataSources.length==0){ + throw new MybatisMinRuntimeException("no dataSource"); + } + return new DataSourceWrapper(dataSource,DATA_SOURCE_NAME); + } + + /* @Override + protected boolean needInitEntityInfo() { + return false; + }*/ + @Override + protected DataSourceWrapper getDataSourceFromSql(String sql){ + if(null==dataSourceInSql){ + return null; + } + return dataSourceInSql.getDataSourceFromSql(sql); + } + @Override + protected int batchSize() { + return batchSize; + } + + @Override + protected boolean logRead() { + return logRead; + } + + @Override + protected boolean logWrite() { + return logWrite; + } + + @Override + protected boolean logFullSql() { + return logFullSql; + } + + + + @Override + protected boolean readAllScopeOpen(){ + return isReadAllScopeOpen; + } +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/ReadDataSources.java b/spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/ReadDataSources.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/repository/ReadDataSources.java rename to spring-data-mybatis-mini-low/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/ReadDataSources.java diff --git a/src/main/resources/META-INF/spring.factories b/spring-data-mybatis-mini-low/src/main/resources/META-INF/spring.factories similarity index 100% rename from src/main/resources/META-INF/spring.factories rename to spring-data-mybatis-mini-low/src/main/resources/META-INF/spring.factories diff --git a/spring-data-mybatis-mini-test/pom.xml b/spring-data-mybatis-mini-test/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..e8d539564aecf77fcc436327ea1171362b4b2d59 --- /dev/null +++ b/spring-data-mybatis-mini-test/pom.xml @@ -0,0 +1,155 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.1.3.RELEASE + + + com.vonchange.common + spring-data-mybatis-mini-test + 0.0.1-SNAPSHOT + spring-data-mybatis-mini-test + spring-data-mybatis-mini-test 测试 + + 2.3.9 + + 8.0.15 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-tomcat + + + + + org.springframework.boot + spring-boot-starter-undertow + + + commons-io + commons-io + 2.5 + + + org.projectlombok + lombok + 1.18.6 + + + + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.springframework.data + spring-data-commons + + + mysql + mysql-connector-java + 8.0.16 + + + com.vonchange.common + spring-data-mybatis-mini + ${spring.mybatis.mini} + + + com.h2database + h2 + 1.4.200 + + + + org.springframework.boot + spring-boot-starter-data-jpa + + + + org.springframework.boot + spring-boot-starter-test + test + + + org.apache.ant + ant + RELEASE + compile + + + + + + aliyun-repos + Aliyun Repository + http://maven.aliyun.com/nexus/content/groups/public + + true + + + false + + + + sonatype-repos + Sonatype Repository + https://oss.sonatype.org/content/groups/public + + true + + + false + + + + sonatype-repos-s + Sonatype Repository + https://oss.sonatype.org/content/repositories/snapshots + + false + + + true + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.1 + + 1.8 + 1.8 + UTF-8 + false + + + + org.springframework.boot + spring-boot-maven-plugin + + + + app + + + diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/DemoApplication.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/DemoApplication.java new file mode 100644 index 0000000000000000000000000000000000000000..1e990147e1443ca21ca3bc0d066ff1fd0726892c --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/DemoApplication.java @@ -0,0 +1,20 @@ +package com.vonchange.nine.demo; + +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.EnableMybatisMini; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +//@SpringBootApplication(exclude={JdbcConfiguration.class}) +@SpringBootApplication +//@EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class}) +@EnableMybatisMini(basePackages ="com.vonchange.nine.demo.dao") +@EnableJpaRepositories(basePackages = "com.vonchange.nine.demo.jpa") +public class DemoApplication { + + public static void main(String[] args) { + + SpringApplication.run(DemoApplication.class, args); + } + +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/ApplicationConfig.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/ApplicationConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..88d3e46952a72abbff24176c684fde571292237e --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/ApplicationConfig.java @@ -0,0 +1,14 @@ +package com.vonchange.nine.demo.config; + +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.JdbcConfiguration; + +//@Configuration +class ApplicationConfig extends JdbcConfiguration { + + /* @Bean + public JdbcRepository initJdbcRepository(DataSource... dataSource){ + return new JdbcRepositoryReadWriteImpl(); + }*/ + + +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/DBConfig.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/DBConfig.java new file mode 100644 index 0000000000000000000000000000000000000000..e84044faf17655815ba2d0640d429332de84ce58 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/DBConfig.java @@ -0,0 +1,56 @@ +package com.vonchange.nine.demo.config; + + +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import com.vonchange.spring.data.mybatis.mini.repository.ReadDataSources; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.jdbc.DataSourceBuilder; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import javax.sql.DataSource; + + +@Configuration +public class DBConfig implements InitializingBean { + @Bean(name = "dataSource") + @Primary + @ConfigurationProperties(prefix = "spring.datasource.hikari") + public DataSource mainDataSource() { + return DataSourceBuilder.create().build(); + } + + @Bean(name = "dataSourceRead") + @ConfigurationProperties(prefix = "spring.datasource.hikari") + public DataSource readDataSource() { + return DataSourceBuilder.create().build(); + } + + + //多数据源 定义 key 为你要设置@DataSourceKey的值 不建议多数据源 最好分服务 + @Bean + public DataSourceWrapper readDataSourceWrapper(@Qualifier("dataSourceRead") DataSource dataSource) { + return new DataSourceWrapper(dataSource,"dataSourceRead"); + } + //自定义 读库数据源 不自定义默认所有你设置的数据源 + //@Bean + public ReadDataSources initReadDataSources(){ + return new ReadDataSources() { + @Override + public DataSource[] allReadDataSources() { + //mainDataSource(),mainDataSource(), + return new DataSource[]{readDataSource()}; + } + }; + } + @Override + public void afterPropertiesSet() throws Exception { + /*DataSource dataSource=mainDataSource(); + Connection connection = DataSourceUtils.getConnection(dataSource); + DataSourceUtils.releaseConnection(connection,dataSource);*/ + } + +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/H2Dialect.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/H2Dialect.java new file mode 100644 index 0000000000000000000000000000000000000000..5f7f019ce210c2628eb660dca3ee60b721b012a3 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/H2Dialect.java @@ -0,0 +1,44 @@ +package com.vonchange.nine.demo.config; + + +import com.vonchange.common.util.ConvertUtil; +import com.vonchange.common.util.StringUtils; +import com.vonchange.mybatis.config.Constant; +import com.vonchange.mybatis.dialect.Dialect; +import com.vonchange.mybatis.dialect.LikeTemplate; + + +/** + *mysql方言 + * @author von_change@163.com + * 2015-6-14 下午12:47:21 + */ +public class H2Dialect implements Dialect { + + @Override + public String getPageSql(String sql, int beginNo, int pageSize) { + return StringUtils.format("{0} limit {1},{2} ", sql, ConvertUtil.toString(beginNo), ConvertUtil.toString(pageSize)); + } + + + + @Override + public int getBigDataFetchSize() { + return 200; + } + + @Override + public int getFetchSize() { + return -1; + } + + @Override + public String getDialogName() { + return Constant.Dialog.MYSQL; + } + + @Override + public LikeTemplate getLikeTemplate() { + return new LikeTemplate(" CONCAT(''%'',#'{'{0}'}',''%'') "," CONCAT(''%'',#'{'{0}'}')"," CONCAT(#'{'{0}'}',''%'') "); + } +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/IPConvert.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/IPConvert.java new file mode 100644 index 0000000000000000000000000000000000000000..2accae733e796cfb7954fff87c67138f046e8c49 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/config/IPConvert.java @@ -0,0 +1,68 @@ +package com.vonchange.nine.demo.config; + +import ch.qos.logback.classic.pattern.ClassicConverter; +import ch.qos.logback.classic.spi.ILoggingEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.net.Inet4Address; +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Enumeration; + +public class IPConvert extends ClassicConverter { + private static Logger logger = LoggerFactory.getLogger(IPConvert.class); + + public static String IP_AND_ADDRESS; + + static { + try { + + Enumeration enumeration = NetworkInterface.getNetworkInterfaces(); + ArrayList ipv4Result = new ArrayList<>(); + + while (enumeration.hasMoreElements()) { + + final NetworkInterface networkInterface = enumeration.nextElement(); + final Enumeration en = networkInterface.getInetAddresses(); + + while (en.hasMoreElements()) { + + final InetAddress address = en.nextElement(); + + if (!address.isLoopbackAddress()&&address instanceof Inet4Address) { + ipv4Result.add(normalizeHostAddress(address)); + } + + } + } + // prefer ipv4 + if (!ipv4Result.isEmpty()) { + IP_AND_ADDRESS = ipv4Result.get(0); + } else { + // If failed to find,fall back to localhost + final InetAddress localHost = InetAddress.getLocalHost(); + IP_AND_ADDRESS = normalizeHostAddress(localHost); + } + } catch (SocketException e) { + logger.error("SocketException{}",e); + } catch (UnknownHostException e) { + logger.error("UnknownHostException{}",e); + } + } + + @Override + public String convert(ILoggingEvent event) { + return IP_AND_ADDRESS; + } + + public static String normalizeHostAddress(final InetAddress localHost) { + + return localHost.getHostAddress() + " | " + localHost.getHostName(); + } + +} + diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/controller/HelloController.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/controller/HelloController.java new file mode 100644 index 0000000000000000000000000000000000000000..78ba67d45a00881b42d6a085fbe0b117d0125ff3 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/controller/HelloController.java @@ -0,0 +1,31 @@ +package com.vonchange.nine.demo.controller; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Random; + +/** + * Created by Zenger on 2018/5/21. + */ +@RestController +//@Slf4j +public class HelloController { + private static final Logger log = LoggerFactory.getLogger(HelloController.class); + + private static int num =new Random().nextInt(1000); + + @Value("${test.hello:ss}") + private String test; + @GetMapping("/test/hello") + public String hello() { + log.info("hello {}",test); + return "Demo project for Spring Boot2x ! 实例随机数"+num+test; + } + +} + + diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseQueryRepository.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseQueryRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..065f18755023cb52df7bc2182a3f1b5c8c5eff08 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseQueryRepository.java @@ -0,0 +1,16 @@ +package com.vonchange.nine.demo.dao; + +import com.vonchange.nine.demo.domain.UserBaseDO; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.support.BaseQueryRepository; +import org.springframework.data.repository.query.Param; + +import java.util.Date; +import java.util.List; + + + +public interface UserBaseQueryRepository extends BaseQueryRepository { + + List findList(@Param("userName") String userName, + @Param("createTime") Date createTime); +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseRepository.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..c0628444eb4632d36d03822a1c61372036dcfa48 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/dao/UserBaseRepository.java @@ -0,0 +1,56 @@ +package com.vonchange.nine.demo.dao; + +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import com.vonchange.nine.demo.domain.EnumDelete; +import com.vonchange.nine.demo.domain.SearchParam; +import com.vonchange.nine.demo.domain.UserBaseDO; +import com.vonchange.nine.demo.domain.UserBaseVO; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.BatchUpdate; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.ReadDataSource; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.support.BaseRepository; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; +import org.springframework.data.repository.query.Param; + +import java.time.LocalDateTime; +import java.util.Date; +import java.util.List; + + +//@DataSourceKey("dataSourceRead") +public interface UserBaseRepository extends BaseRepository { + List findListBase(@Param("userName") String userName); + UserBaseDO findOne(@Param("userName") String userName); + @ReadDataSource + List findList(@Param("userName") String userName, + @Param("createTime") LocalDateTime createTime,@Param("isDelete") EnumDelete isDelete); + Page findList(Pageable pageable, @Param("userName") String userName,@Param("createTime") Date createTime); + String findUserName(@Param("userName") String userName); + List findListVo(@Param("userName") String userName, + @Param("createTime") Date createTime); + + List findListByBean(@Param("param") SearchParam searchParam); + + List findListByIds(@Param("userName") String userName, + @Param("createTime") Date createTime,@Param("idList")List idList); + + int updateIsDelete(@Param("isDelete") Integer isDelete,@Param("id") Long id); + + @BatchUpdate + int batchUpdate(List list); + + @BatchUpdate(size = 5000) + int batchInsert(List list); + + List findLongList(); + + int updateTest(@Param("list")List list); + + List findByUserName(@Param("test")String test); + + int insertBatchNormal(@Param("list")List list); + + void findBigData(@Param("")AbstractPageWork abstractPageWork,@Param("userName") String userName); + + List findInList(@Param("userNames")List test, @Param("isDeletes")List isDeletes); +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/BaseDO.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/BaseDO.java new file mode 100644 index 0000000000000000000000000000000000000000..9764f960bdabf8357827ff6261a4e76d8da4c512 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/BaseDO.java @@ -0,0 +1,65 @@ +package com.vonchange.nine.demo.domain; + +import com.vonchange.mybatis.tpl.annotation.InsertIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateDuplicateKeyIgnore; +import com.vonchange.mybatis.tpl.annotation.UpdateIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateNotNull; + +import javax.persistence.Id; +import java.util.Date; + +//@Data +//@AllArgsConstructor +//@NoArgsConstructor +//@Table(name = "user_base") +public class BaseDO { + @Id + private Long id; + @UpdateNotNull + private Integer isDelete; + @InsertIfNull(function = "now()") + @UpdateNotNull + private Date createTime; + @UpdateDuplicateKeyIgnore + @InsertIfNull(function = "now()") + @UpdateIfNull(function = "now()") + private Date updateTime; + + public BaseDO(){ + + } + + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/EnumDelete.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/EnumDelete.java new file mode 100644 index 0000000000000000000000000000000000000000..8cfc137c8454fc6722bc5cfb3634b67b0cc8f017 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/EnumDelete.java @@ -0,0 +1,38 @@ +package com.vonchange.nine.demo.domain; + +public enum EnumDelete { + deleted(1,"已删除"),unDeleted(0,"未删除"); + + private Integer value; + private String desc; + EnumDelete(Integer value, String desc){ + this.value=value; + this.desc=desc; + } + + public static EnumDelete getValue(Integer value) { + for (EnumDelete c : EnumDelete.values()) { + if (c.getValue().equals(value)) { + return c; + } + } + return null; + } + public Integer getValue() { + return value; + } + + public EnumDelete setValue(int value) { + this.value = value; + return this; + + } + + public String getDesc() { + return desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + } \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/EnumStatus.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/EnumStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..48f0f232d8d9a0c03c3e4d9983a4e86e39705a72 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/EnumStatus.java @@ -0,0 +1,12 @@ +package com.vonchange.nine.demo.domain; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public enum EnumStatus { + on("还在世"),off("已驾崩"); + private String desc; + +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/SearchParam.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/SearchParam.java new file mode 100644 index 0000000000000000000000000000000000000000..dbeb8962d2807060010bbd275a8263f72b44b934 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/SearchParam.java @@ -0,0 +1,24 @@ +package com.vonchange.nine.demo.domain; + +import java.util.Date; + +public class SearchParam { + private String userName; + private Date createTime; + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public Date getCreateTime() { + return createTime; + } + + public void setCreateTime(Date createTime) { + this.createTime = createTime; + } +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseDO.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseDO.java new file mode 100644 index 0000000000000000000000000000000000000000..ad087f2479e1a254d3f143cb6bdbdc7f6ce114c5 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseDO.java @@ -0,0 +1,62 @@ +package com.vonchange.nine.demo.domain; + + + +import com.vonchange.mybatis.tpl.annotation.InsertIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateNotNull; +import lombok.AllArgsConstructor; +import lombok.Data; + +import javax.persistence.Column; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; +import java.util.Date; + +@Data +@AllArgsConstructor +@Table(name = "user_base") +public class UserBaseDO { + + //@GeneratedValue + @Id + private Long id; + //@InsertIfNull(function = "REPLACE(UUID(), '-', '')") + private String code; + @Column(name="user_name") + private String userName; + private String mobilePhone; + //@InsertIfNull("0") + //@UpdateNotNull + //private Integer isDelete; + @UpdateNotNull + private Integer isDelete; + @InsertIfNull(function = "now()") + @UpdateNotNull + private LocalDateTime createTime; + //@UpdateDuplicateKeyIgnore + @InsertIfNull(function = "now()") + @UpdateIfNull(function = "now()") + private Date updateTime; + + + private EnumStatus status; + + private byte[] headImageData; + public UserBaseDO(){ + + } + public UserBaseDO(Long id,String userName,String mobilePhone,Integer isDelete,LocalDateTime createTime,Date updateTime){ + this.id=id; + this.userName=userName; + this.mobilePhone=mobilePhone; + this.createTime=createTime; + this.updateTime=updateTime; + this.isDelete=isDelete; + } + + + + +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseVO.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseVO.java new file mode 100644 index 0000000000000000000000000000000000000000..d64320b2ad6ae44da4a06abdbcd42b17f3f51957 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/domain/UserBaseVO.java @@ -0,0 +1,41 @@ +package com.vonchange.nine.demo.domain; + +//@Data +public class UserBaseVO { + private int id; + private String userName; + private String firstPhone; + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getFirstPhone() { + return firstPhone; + } + + public void setFirstPhone(String firstPhone) { + this.firstPhone = firstPhone; + } + + @Override + public String toString() { + return "UserBaseVO{" + + "id=" + id + + ", userName='" + userName + '\'' + + ", firstPhone='" + firstPhone + '\'' + + '}'; + } +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/jpa/UserBase.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/jpa/UserBase.java new file mode 100644 index 0000000000000000000000000000000000000000..3a11dcc6c6acfb1dc82db4ddfff3a2e519136029 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/jpa/UserBase.java @@ -0,0 +1,132 @@ +package com.vonchange.nine.demo.jpa; + +import com.vonchange.mybatis.tpl.annotation.InsertIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateIfNull; +import com.vonchange.mybatis.tpl.annotation.UpdateNotNull; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; +import java.time.LocalDateTime; +import java.util.Date; + +//@Data +//@AllArgsConstructor +//@NoArgsConstructor +@Entity +@Table(name = "user_base") +public class UserBase { + + //@GeneratedValue + @Id + private Long id; + //@InsertIfNull(function = "REPLACE(UUID(), '-', '')") + private String code; + @Column(name="user_name") + private String userName; + private String mobilePhone; + //@InsertIfNull("0") + @UpdateNotNull + private Integer isDelete; + @InsertIfNull(function = "now()") + @UpdateNotNull + private LocalDateTime createTime; + //@UpdateDuplicateKeyIgnore + @InsertIfNull(function = "now()") + @UpdateIfNull(function = "now()") + private Date updateTime; + private byte[] headImageData; + public UserBase(){ + + } + public UserBase(Long id, String userName, String mobilePhone, Integer isDelete, LocalDateTime createTime, Date updateTime){ + this.id=id; + this.userName=userName; + this.mobilePhone=mobilePhone; + this.isDelete=isDelete; + this.createTime=createTime; + this.updateTime=updateTime; + } + + + + + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUserName() { + return userName; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public String getMobilePhone() { + return mobilePhone; + } + + public void setMobilePhone(String mobilePhone) { + this.mobilePhone = mobilePhone; + } + + public Integer getIsDelete() { + return isDelete; + } + + public void setIsDelete(Integer isDelete) { + this.isDelete = isDelete; + } + + public String getCode() { + return code; + } + + public void setCode(String code) { + this.code = code; + } + + public LocalDateTime getCreateTime() { + return createTime; + } + + public void setCreateTime(LocalDateTime createTime) { + this.createTime = createTime; + } + + public Date getUpdateTime() { + return updateTime; + } + + public byte[] getHeadImageData() { + return headImageData; + } + + public void setHeadImageData(byte[] headImageData) { + this.headImageData = headImageData; + } + + public void setUpdateTime(Date updateTime) { + this.updateTime = updateTime; + } + + @Override + public String toString() { + return "UserBaseDO{" + + "id=" + id + + ", code='" + code + '\'' + + ", userName='" + userName + '\'' + + ", mobilePhone='" + mobilePhone + '\'' + + ", isDelete=" + isDelete + + ", createTime=" + createTime + + ", updateTime=" + updateTime + + '}'; + } +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepository.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..193a9471c8bd902d8d33624514fd98a635dffb58 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepository.java @@ -0,0 +1,16 @@ +package com.vonchange.nine.demo.jpa; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + + +@Repository +public interface UserBaseJpaRepository extends JpaRepository { + + @Query(value="from UserBase where userName = ?1 ") + List findList(String userName); + +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/util/H2DBFunctionExt.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/util/H2DBFunctionExt.java new file mode 100644 index 0000000000000000000000000000000000000000..8865226feb884ca96bb7d4583efbc47c94a647e2 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/util/H2DBFunctionExt.java @@ -0,0 +1,17 @@ +package com.vonchange.nine.demo.util; + +import java.util.UUID; + +public class H2DBFunctionExt { + /** + * 用法:SELECT uuid(); H2数据库注册uuid函数:CREATE ALIAS uuid FOR + * "h2db.function.ext.H2DBFunctionExt.uuid"; + * + * @return + * @Method: uuid + * @Description: 实现MySQL数据库的uuid函数,用于生成UUID + */ + public static String uuid() { + return UUID.randomUUID().toString(); + } +} diff --git a/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/util/JsonUtil.java b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/util/JsonUtil.java new file mode 100644 index 0000000000000000000000000000000000000000..356a2bdb21420d32c9de8e4c743fc3a7f7776e59 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/java/com/vonchange/nine/demo/util/JsonUtil.java @@ -0,0 +1,72 @@ +package com.vonchange.nine.demo.util; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class JsonUtil { + private static Logger logger = LoggerFactory.getLogger(JsonUtil.class); + private JsonUtil() { + throw new IllegalStateException("Utility class"); + } + public static String toJson(Object object) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.writeValueAsString(object); + } catch (JsonProcessingException e) { + logger.error("序列化对象失败{}",e); + } + return null; + } + + public static T fromJson(String json, TypeReference type) { + return fromJson(json,null,type); + } + public static T evalJson(String json, TypeReference type) throws IOException { + return evalJson(json,null,type); + } + public static T evalJson(String json, Class clazz) throws IOException { + return evalJson(json,clazz,null); + } + public static T evalJson(String json, Class clazz,TypeReference type) throws IOException { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); + T t =null; + if(null!=clazz){ + t = mapper.readValue(json, clazz); + } + if(null!=type){ + t = mapper.readValue(json, type); + } + return t; + } + + private static T fromJson(String json, Class clazz,TypeReference type) { + ObjectMapper mapper = new ObjectMapper(); + mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES,true); + mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); + T t =null; + try { + if(null!=clazz){ + t = mapper.readValue(json, clazz); + } + if(null!=type){ + t = mapper.readValue(json, type); + } + } catch (IOException e) { + logger.error("反序列化对象失败{}",e); + } + return t; + } + public static T fromJson(String json, Class clazz) { + return fromJson(json,clazz,null); + } + +} diff --git a/spring-data-mybatis-mini-test/src/main/resources/application-dev.yml b/spring-data-mybatis-mini-test/src/main/resources/application-dev.yml new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/resources/application-dev.yml @@ -0,0 +1 @@ + diff --git a/spring-data-mybatis-mini-test/src/main/resources/application-local.yml b/spring-data-mybatis-mini-test/src/main/resources/application-local.yml new file mode 100644 index 0000000000000000000000000000000000000000..3945d2240403d8380d5d214e2a3a13320f59c76a --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/resources/application-local.yml @@ -0,0 +1,18 @@ +server: + port: 9001 + +mybatis-mini: + isReadExcludePrimary: false + isReadAllScopeOpen: false + logRead: true + logWrite: true + logFullSql: true + +spring: + datasource: + hikari: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/test_b?autoReconnect=true&rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT + username: root + password: 123456 +# \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/main/resources/application-test.yml b/spring-data-mybatis-mini-test/src/main/resources/application-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..38ffe5f88e55fbb1e816296688bcd349e7588547 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/resources/application-test.yml @@ -0,0 +1,14 @@ +server: + port: 9001 + +mybatis-mini: + isReadExcludePrimary: false + +spring: + datasource: + hikari: + driver-class-name: org.h2.Driver + #jdbc-url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 + jdbc-url: jdbc:h2:mem:db_users;MODE=MYSQL;INIT=RUNSCRIPT FROM './src/test/resources/db-init.sql' + username: root + password: 123456 diff --git a/spring-data-mybatis-mini-test/src/main/resources/application.yml b/spring-data-mybatis-mini-test/src/main/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..107711e2be248bed96e53b053cc4146f9694d938 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/resources/application.yml @@ -0,0 +1,28 @@ +spring: + profiles: + active: local + application: + name: demo + datasource: + hikari: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/nine_user?autoReconnect=true&rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT + username: root + password: 123456 + connection-timeout: 20000 + minimum-idle: 5 + maximum-pool-size: 500 + idle-timeout: 60000 + max-lifetime: 600000 + leak-detection-threshold: 20000 + + + +logback: + aliyun: + endpoint: cn-hangzhou.log.aliyuncs.com + + + + + diff --git a/spring-data-mybatis-mini-test/src/main/resources/logback-spring.xml b/spring-data-mybatis-mini-test/src/main/resources/logback-spring.xml new file mode 100644 index 0000000000000000000000000000000000000000..64951a56ed0adae9afefedc809d82f714c775ee4 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/resources/logback-spring.xml @@ -0,0 +1,49 @@ + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS}|${appDev}|${appName}|%-5level|%ipandhostname|[%thread]| %logger{50}| %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-mybatis-mini-test/src/main/resources/sql/UserBaseRepository.md b/spring-data-mybatis-mini-test/src/main/resources/sql/UserBaseRepository.md new file mode 100644 index 0000000000000000000000000000000000000000..67fc87adfbcb2cdc0ee5291bf1498b2c3c8e242e --- /dev/null +++ b/spring-data-mybatis-mini-test/src/main/resources/sql/UserBaseRepository.md @@ -0,0 +1,74 @@ +> 查询用户列表 +``` +-- findListX + +select * from user_base +where user_name = #{userName} +and create_time <= #{createTime} +``` + +> 查询用户列表 含sql 片段 + +``` +-- findList +select * from user_base +where [@sql findListWhereSql] +``` + +> sql 片段 +``` +-- findListWhereSql +user_name = #{userName} and 1=1 +[@and create_time < createTime] +``` + +> 查询用户名 返回1个字段的情况 比如查询行数等 +``` +-- findUserName +SELECT first_phone FROM user_base +WHERE user_name = #{userName} +``` + + +> 根据Id列表查询列表 +``` +-- findListByIds +SELECT * FROM user_base + + and user_name <> #{userName} + and id in #{item} + and create_time < #{createTime} + + +``` + +> 根据Id列表查询列表 简写if 和in查询 可混用 +``` +-- findListByIds +SELECT * FROM user_base + +[@and user_name like userName%] +[@and id in idList] + and create_time < #{createTime} + +``` + +> 更新方法 update 开头 + +``` +-- updateIsDelete +update user_base set is_delete = #{isDelete} where id =#{id} +``` + +``` +-- batchUpdate +update user_base set is_delete = IFNULL(#{isDelete},is_delete),user_name =#{userName} where id =#{id} +``` + +``` +-- updateTest + +insert into user_base(`user_name`,`first_phone`) values (#{item.userName},#{item.firstPhone}); + + +``` \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/DemoApplicationTests.java b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/DemoApplicationTests.java new file mode 100644 index 0000000000000000000000000000000000000000..11e13592f32043ae426c78a02e6709ad824c67da --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/DemoApplicationTests.java @@ -0,0 +1,16 @@ +package com.vonchange.nine.demo; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class DemoApplicationTests { + + @Test + public void contextLoads() { + } + +} diff --git a/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/dao/UserBaseRepositoryTest.java b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/dao/UserBaseRepositoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..97478252e2be080abf7d0f42b5b571dcad2c1fe1 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/dao/UserBaseRepositoryTest.java @@ -0,0 +1,327 @@ +package com.vonchange.nine.demo.dao; + +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import com.vonchange.nine.demo.domain.EnumDelete; +import com.vonchange.nine.demo.domain.EnumStatus; +import com.vonchange.nine.demo.domain.SearchParam; +import com.vonchange.nine.demo.domain.UserBaseDO; +import com.vonchange.nine.demo.domain.UserBaseVO; +import com.vonchange.nine.demo.util.JsonUtil; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.test.annotation.Rollback; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.transaction.annotation.Transactional; + +import javax.annotation.Resource; +import java.io.IOException; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; + + +@RunWith(SpringRunner.class) +@SpringBootTest +//@Transactional +//@Slf4j +public class UserBaseRepositoryTest { + private static final Logger log = LoggerFactory.getLogger(UserBaseRepositoryTest.class); + + @Resource + private UserBaseRepository userBaseRepository; + + @Test + public void findList() { + List userBaseDOList = userBaseRepository.findList("test",LocalDateTime.now().plusHours(1L), + EnumDelete.unDeleted); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",JsonUtil.toJson(userBaseDO)); + }); + UserBaseDO userBaseDO = userBaseRepository.findOne("test"); + log.info("\n {}",userBaseDO.toString()); + } + + + @Test + public void findInList() { + List userBaseDOList = userBaseRepository.findInList(Arrays.asList("test"), Arrays.asList(0)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",JsonUtil.toJson(userBaseDO)); + }); + + } + + @Test + public void findOne() { + UserBaseDO userBaseDO = userBaseRepository.findOne("test"); + log.info("\n {}",userBaseDO.toString()); + } + + @Test + public void findListBase() { + List userBaseDOList = userBaseRepository.findListBase("张三日子"); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + + @Test + public void findListByBean() { + SearchParam searchParam = new SearchParam(); + searchParam.setUserName("张三日子"); + List userBaseDOList = userBaseRepository.findListByBean(searchParam); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findListVo() { + List userBaseVOList = userBaseRepository.findListVo("张三日子",new Date()); + userBaseVOList.forEach(userBaseVO -> { + log.info("\n {}",userBaseVO.toString()); + }); + } + @Test + public void findListByPage() { + Pageable pageable = PageRequest.of(0,10); + //PageRequest.of(0,3); + Page personRepositoryBy = userBaseRepository.findList(pageable,"张三日子",null); + log.info("\n {}",personRepositoryBy.toString()); + personRepositoryBy.getContent().forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findUserName() { + String userName = userBaseRepository.findUserName("test"); + log.info("\n userName {}",userName); + } + + @Test + public void findById() { + UserBaseDO userBaseDO = userBaseRepository.findById(1L); + log.info("\n userBaseDO {}",userBaseDO); + } + + @Test + public void findByXX() { + List userBaseDOList = userBaseRepository.findByUserName("test"); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n userBaseDO {}",userBaseDO); + }); + + } + @Test + public void findLongList() { + List idList = userBaseRepository.findLongList(); + idList.forEach(id -> { + log.info("\n id {}",id); + }); + + } + @Test + public void findListByIds() { + List userBaseDOListQ = userBaseRepository.findListByIds("test",null,Arrays.asList(1L,2L)); + userBaseDOListQ.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + List userBaseDOList = userBaseRepository.findListByIds("test",new Date(), Arrays.asList(1L,2L)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + + } + + @Test + @Transactional + @Rollback + public void updateIsDelete() { + int result = userBaseRepository.updateIsDelete(1,1L); + log.info("result {}",result); + } + @Test + public void insert() throws IOException { + UserBaseDO userBaseDO = new UserBaseDO(); + //userBaseDO.setId(3L); + userBaseDO.setUserName("test"); + userBaseDO.setCode(UUID.randomUUID().toString()); + userBaseDO.setStatus(EnumStatus.on); + + //userBaseDO.setHeadImageData(FileUtils.readFileToByteArray(new File("/Users/vonchange/work/docment/cat.jpg"))); + // userBaseDO.setCode("1"); + //userBaseDO.setCreateTime(LocalDateTime.now().plusHours(1L)); + int result = userBaseRepository.insert(userBaseDO); + log.info("\nresult {} {} ",result,userBaseDO.toString()); + UserBaseDO userBaseDOFind =userBaseRepository.findById(userBaseDO.getId()); + //FileUtils.writeByteArrayToFile(new File("/Users/vonchange/work/docment/catcc.jpg"),userBaseDOFind.getHeadImageData()); + log.info("\nuserBaseDOFind {}",userBaseDOFind.toString()); + } + + + @Test + public void insertDuplicateKey() { + UserBaseDO userBaseDO = new UserBaseDO(); + userBaseDO.setUserName("UUUUU"); + userBaseDO.setMobilePhone("110"); + int result = userBaseRepository.insertDuplicateKey(userBaseDO); + log.info("\nresult {} {}",result,userBaseDO.getId()); + + } + @Test + //@Transactional + //@Rollback + public void update() { + UserBaseDO userBaseDO = new UserBaseDO(); + userBaseDO.setUserName("test_ss"); + userBaseDO.setId(1L); + int result = userBaseRepository.update(userBaseDO); + log.info("\nresult {}",result); + //UserBaseDO userBaseDOFind =userBaseRepository.findById(1L); + //log.info("\nuserBaseDOFind {}",userBaseDOFind.toString()); + } + + @Test + public void updateAllField() { + UserBaseDO userBaseDO = new UserBaseDO(); + userBaseDO.setUserName(null); + userBaseDO.setId(1L); + int result = userBaseRepository.updateAllField(userBaseDO); + log.info("\nresult {}",result); + } + + //13 + + /** + * 批量插入 + */ + @Test + @Transactional + public void insertBatch() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatch(list,5000); + log.info("id {}",list.get(0).getId()); + log.info("result {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//1554 + } + + + + /** + * 批量插入 + */ + @Test + @Transactional + public void insertBatchDuplicateKey() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatchDuplicateKey(list,5000); + log.info("id {}",list.get(0).getId()); + log.info("result {}",resultx); + int resulty = userBaseRepository.insertBatchDuplicateKey(list,5000); + log.info("result {}",resulty); + log.info("time {}",System.currentTimeMillis()-start);//1554 + } + + @Test + //@Transactional + //@Rollback + public void updateBatchBySqlId() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<2;i++) { + list.add(new UserBaseDO(1L+i,"RRR"+i,null,null,null,new Date())); + } + int resultx = userBaseRepository.batchUpdate(list); + log.info("resultx {}",resultx); + log.info("time {}",System.currentTimeMillis()-start); + } + + @Test + @Transactional + //@Rollback + public void insertBatchNormal() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatchNormal(list); + System.out.println(list.get(0).getId()); + log.info("resultx {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//908 + } + + @Test + @Transactional + //@Rollback + public void bachUpdate() { + int result = userBaseRepository.update(new UserBaseDO(1L,"testxx","",1,null,null)); + log.info("result {}",result); + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10000;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.batchInsert(list); + System.out.println(list.get(0).getId()); + log.info("resultx {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//563 + } + + + @Test + @Transactional + public void findBigData() { + + long start = System.currentTimeMillis(); + List list = new ArrayList<>(); + for (int i=0;i<10006;i++) { + list.add(new UserBaseDO(null,"三e"+i,"1100"+i,null, LocalDateTime.now(),null)); + } + int resultx = userBaseRepository.insertBatch(list,5000); + log.info("id {}",list.get(0).getId()); + log.info("result {}",resultx); + log.info("time {}",System.currentTimeMillis()-start);//1554 + AbstractPageWork abstractPageWork = new AbstractPageWork() { + @Override + protected void doPage(List pageContentList, int pageNum, Map extData) { + pageContentList.forEach(userBaseDO -> { + log.info("{}",userBaseDO.toString()); + }); + + } + + @Override + protected int getPageSize() { + return 500; + } + }; + userBaseRepository.findBigData(abstractPageWork,"三"); + log.info("{} {} {}",abstractPageWork.getSize(),abstractPageWork.getTotalPages(),abstractPageWork.getTotalElements()); + } +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepositoryTest.java b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepositoryTest.java new file mode 100644 index 0000000000000000000000000000000000000000..cb3d3918f4f58f1e2cb2e9b8d66d9f178bab465a --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/jpa/UserBaseJpaRepositoryTest.java @@ -0,0 +1,34 @@ +package com.vonchange.nine.demo.jpa; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class UserBaseJpaRepositoryTest { + + private static final Logger log = LoggerFactory.getLogger(UserBaseJpaRepositoryTest.class); + @Resource + private UserBaseJpaRepository userBaseJpaRepository; + + @Test + public void findList() { + List userBaseList = userBaseJpaRepository.findList("张三日子"); + userBaseList.forEach(userBase -> { + log.info("\n {}",userBase.toString()); + }); + } + @Test + public void ttt() { + String goodsId= "xxx12345"; + System.out.println(goodsId.substring(goodsId.length()-1)); + } + +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/service/impl/JdbcQueryServiceImplTest.java b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/service/impl/JdbcQueryServiceImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..400076c17b0b38088493f8f6bd7d098232186a85 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/java/com/vonchange/nine/demo/service/impl/JdbcQueryServiceImplTest.java @@ -0,0 +1,73 @@ +package com.vonchange.nine.demo.service.impl; + +import com.vonchange.common.util.map.MyHashMap; +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.nine.demo.domain.UserBaseDO; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit4.SpringRunner; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; + +@RunWith(SpringRunner.class) +@SpringBootTest +public class JdbcQueryServiceImplTest { + private static final Logger log = LoggerFactory.getLogger(JdbcQueryServiceImplTest.class); + @Resource + private JdbcRepository jdbcRepository; + @Test + public void findList() { + List userBaseDOList =jdbcRepository.queryList(UserBaseDO.class,"sql.UserBaseRepository.findList",new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findListToMap() { + List> userBaseDOList =jdbcRepository.queryMapList("sql.UserBaseRepository.findList",new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + @Test + public void findListBySql() { + String sql ="select * from user_base\n" + + "where user_name = #{userName}"; + List userBaseDOList = jdbcRepository.queryList(UserBaseDO.class,"@sql"+sql,new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } + + @Test + public void findListByMd() { + String sql ="### id findListByMd \n" + + "#### version 1.0 \n> 查询用户列表 含sql 片段\n" + + "\n" + + "```\n" + + "-- main\n" + + "select * from user_base\n" + + "where [@sql findListWhereSql]\n" + + "```\n" + + "\n" + + "> sql 片段\n" + + "```\n" + + "-- findListWhereSql\n" + + "user_name = #{userName} and 1=1\n" + + "{@and create_time < createTime}\n" + + "```"; + List userBaseDOList = jdbcRepository.queryList(UserBaseDO.class,"@md"+sql,new MyHashMap() + .set("userName","张三日子").set("createTime",null)); + userBaseDOList.forEach(userBaseDO -> { + log.info("\n {}",userBaseDO.toString()); + }); + } +} \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/test/resources/application-dev.yml b/spring-data-mybatis-mini-test/src/test/resources/application-dev.yml new file mode 100644 index 0000000000000000000000000000000000000000..8b137891791fe96927ad78e64b0aad7bded08bdc --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/resources/application-dev.yml @@ -0,0 +1 @@ + diff --git a/spring-data-mybatis-mini-test/src/test/resources/application-local.yml b/spring-data-mybatis-mini-test/src/test/resources/application-local.yml new file mode 100644 index 0000000000000000000000000000000000000000..abcd8afc50f66c5edc381166e50d7f928da6eaaa --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/resources/application-local.yml @@ -0,0 +1,17 @@ +server: + port: 9001 + +mybatis-mini: + isReadAllScopeOpen: false + logRead: true + logWrite: true + logFullSql: true + +spring: + datasource: + hikari: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/test_b?autoReconnect=true&rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT + username: root + password: 123456 +# \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/test/resources/application-test.yml b/spring-data-mybatis-mini-test/src/test/resources/application-test.yml new file mode 100644 index 0000000000000000000000000000000000000000..344248389a4d94cdb7cee4f98870d29906f1451a --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/resources/application-test.yml @@ -0,0 +1,18 @@ +server: + port: 9001 + + +mybatis-mini: + dialect: com.vonchange.nine.demo.config.H2Dialect + logRead: true + logWrite: true + logFullSql: true + +spring: + datasource: + hikari: + driver-class-name: org.h2.Driver + #jdbc-url: jdbc:h2:mem:test;DB_CLOSE_DELAY=-1 + jdbc-url: jdbc:h2:mem:db_users;MODE=MYSQL;INIT=RUNSCRIPT FROM './src/test/resources/db-init.sql' + username: root + password: 123456 diff --git a/spring-data-mybatis-mini-test/src/test/resources/application.yml b/spring-data-mybatis-mini-test/src/test/resources/application.yml new file mode 100644 index 0000000000000000000000000000000000000000..b37e08536d7980ede1b38c2d5e38fd31ffd9e424 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/resources/application.yml @@ -0,0 +1,34 @@ +spring: + profiles: + active: local + application: + name: demo + datasource: + hikari: + driver-class-name: com.mysql.cj.jdbc.Driver + jdbc-url: jdbc:mysql://127.0.0.1:3306/nine_user?autoReconnect=true&rewriteBatchedStatements=true&allowMultiQueries=true&useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=CTT + username: root + password: 123456 + connection-timeout: 20000 + minimum-idle: 5 + maximum-pool-size: 500 + idle-timeout: 60000 + max-lifetime: 600000 + leak-detection-threshold: 20000 + jpa: + database: MySQL + database-platform: org.hibernate.dialect.MySQL5InnoDBDialect + show-sql: true + hibernate: + ddl-auto: none + + +logback: + aliyun: + endpoint: cn-hangzhou.log.aliyuncs.com + + + + + + diff --git a/spring-data-mybatis-mini-test/src/test/resources/db-init.sql b/spring-data-mybatis-mini-test/src/test/resources/db-init.sql new file mode 100644 index 0000000000000000000000000000000000000000..4e30b84dc88f3a0511d6d7e26689bab0b170eab0 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/resources/db-init.sql @@ -0,0 +1,19 @@ +SET MODE=MySQL; +SET FOREIGN_KEY_CHECKS=0; +drop table if exists `user_base`; +CREATE TABLE IF NOT EXISTS `user_base` ( + `id` bigint(13) NOT NULL AUTO_INCREMENT COMMENT 'id序列,自增', + `code` varchar(36) DEFAULT NULL COMMENT '编码', + `user_name` varchar(30) DEFAULT NULL COMMENT '用户名', + `mobile_phone` varchar(13) DEFAULT NULL COMMENT '手机号', + `address` varchar(20) DEFAULT NULL COMMENT 'address', + `is_delete` tinyint(1) DEFAULT '0' COMMENT '是否已删除', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `head_image_data` blob DEFAULT NULL COMMENT '头像', + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + insert into user_base(id,code,user_name,mobile_phone,address,create_time) values (1,UUID(),'test','120','xxx',now()); + insert into user_base(user_name,mobile_phone,address,create_time) values ('李4','110','xxx额',now()); + insert into user_base(user_name,mobile_phone,address,create_time,update_time) values ('张三日子','911','xxx是啥',now(),now()); + insert into user_base(user_name,mobile_phone,address,create_time) values ('test','333','ufo',now()); \ No newline at end of file diff --git a/spring-data-mybatis-mini-test/src/test/resources/logback-spring.xml b/spring-data-mybatis-mini-test/src/test/resources/logback-spring.xml new file mode 100644 index 0000000000000000000000000000000000000000..41e98d2dda51e97dd9ff7a19ee572d040820f837 --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/resources/logback-spring.xml @@ -0,0 +1,49 @@ + + + + + + + + + + %d{yyyy-MM-dd HH:mm:ss SSS}|${appDev}|${appName}|%-5level|%ipandhostname|[%thread]| %logger{50}| %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-data-mybatis-mini-test/src/test/resources/sql/UserBaseRepository.md b/spring-data-mybatis-mini-test/src/test/resources/sql/UserBaseRepository.md new file mode 100644 index 0000000000000000000000000000000000000000..1ff44fa7b44bf98580a28cff18b66f4de786a45b --- /dev/null +++ b/spring-data-mybatis-mini-test/src/test/resources/sql/UserBaseRepository.md @@ -0,0 +1,160 @@ +> 查询用户列表 +``` +-- findListX + +select * from user_base +where user_name = #{userName} +and create_time <= #{createTime} +``` + +``` +-- findListBase +select * from user_base where user_name = #{userName} +``` + + +``` +-- findOne +select * from user_base +where user_name = #{userName} +``` +> 查询用户列表 含sql 片段 + +``` +-- findList +select * from user_base +where +user_name = #{userName} +[@@and is_delete = isDelete.value] +[@@and create_time < createTime] + +``` + +``` +-- findListVo +select * from user_base +where [@sql findListWhereSql] +``` + +``` +-- findListByBean +select * from user_base + +[@@and user_name like param.userName] +[@and user_name like param.userName%] +[@and create_time <= param.createTime] + +``` + + + + +> sql 片段 +``` +-- findListWhereSql +user_name = #{userName} and 1=1 +[@and create_time < createTime] +``` + +> 查询用户名 返回1个字段的情况 比如查询行数等 +``` +-- findUserName +SELECT user_name FROM user_base +WHERE user_name = #{userName} +``` + + +> 根据Id列表查询列表 +``` +-- findListByIdsx +SELECT * FROM user_base + + and user_name <> #{userName} + and id in #{item} + and create_time < #{createTime} + + +``` + +> [@and create_time < createTime] + +> 根据Id列表查询列表 简写if 和in查询 可混用 +``` +-- findListByIds +SELECT * FROM user_base + +[@@and id in #{idList:in} and user_name like #{userName:like}] +[@and user_name like userName%] +[@and id in idList] + and create_time < #{createTime} + +``` + +> 更新方法 update 开头 + +``` +-- updateIsDelete +update user_base set is_delete = #{isDelete} where id =#{id} +``` + +``` +-- batchUpdate +update user_base set is_delete = IFNULL(#{isDelete},is_delete),user_name =#{userName} where id =#{id} +``` + + +``` +-- batchInsert +insert into user_base(`user_name`,`mobile_phone`,create_time) values +(#{userName},#{mobilePhone},#{createTime}) +``` + +``` +-- updateTest + +insert into user_base(`user_name`,`mobile_phone`) values (#{item.userName},#{item.firstPhone}); + + +``` + +``` +-- insertBatchNormal +insert into user_base(`user_name`,`mobile_phone`,create_time) values + +(#{item.userName},#{item.mobilePhone},#{item.createTime}) + + +``` + +``` +-- insertBatchNormalX +insert into user_base(`id`,`code`,`user_name`,`mobile_phone`,`is_delete`,`create_time`,`update_time`,`head_image_data`) values + +(IFNULL(#{item.id},`id`),IFNULL(#{item.code},`code`),IFNULL(#{item.userName},`user_name`),IFNULL(#{item.mobilePhone},`mobile_phone`) +,IFNULL(#{item.isDelete},`is_delete`),IFNULL(#{item.createTime},now()),IFNULL(#{item.updateTime},now()),IFNULL(#{item.headImageData},`head_image_data`)) + +``` + + +``` +-- findBigData +select * from user_base + +[@and user_name like userName] + +``` + + +``` +-- findLongList +select id from user_base +``` + +``` +-- findInList + +select * from user_base +where 1=1 +[@@and user_name in userNames] +[@@and is_delete in isDeletes] +``` \ No newline at end of file diff --git a/spring-data-mybatis-mini/pom.xml b/spring-data-mybatis-mini/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..b9539cbc763eff89323dda5e6fe225452e22ca30 --- /dev/null +++ b/spring-data-mybatis-mini/pom.xml @@ -0,0 +1,70 @@ + + + + 4.0.0 + + mybatis-mini-parant + com.vonchange.common + 2.3.9 + + spring-data-mybatis-mini + 2.3.9 + + spring data mybatis mini + spring data jdbc with mybatis template dynamic query + https://github.com/VonChange/spring-data-mybatis-mini + + 2.1.5.RELEASE + 5.1.5.RELEASE + 8.0.15 + + + + + com.vonchange.common + mybatis-mini + 2.3.9 + + + org.springframework.data + spring-data-commons + ${springdata.commons} + provided + + + org.springframework + spring-tx + ${spring.commons} + provided + + + + org.springframework + spring-context + ${spring.commons} + provided + + + + org.springframework + spring-beans + ${spring.commons} + provided + + + + org.springframework + spring-jdbc + ${spring.commons} + provided + + + + org.springframework + spring-core + ${spring.commons} + provided + + + + diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/BindParameterWrapper.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/BindParameterWrapper.java new file mode 100644 index 0000000000000000000000000000000000000000..e7607f9aec2c0d486fe42fd6fec84699c58076e5 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/BindParameterWrapper.java @@ -0,0 +1,54 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; +import org.springframework.data.domain.Pageable; + +import java.util.Map; + +public class BindParameterWrapper { + private Pageable pageable; + private AbstractPageWork abstractPageWork; + private Class abstractPageWorkClass; + private Map parameter; + private Object firstParam; + + public Object getFirstParam() { + return firstParam; + } + + public void setFirstParam(Object firstParam) { + this.firstParam = firstParam; + } + + public AbstractPageWork getAbstractPageWork() { + return abstractPageWork; + } + + public void setAbstractPageWork(AbstractPageWork abstractPageWork) { + this.abstractPageWork = abstractPageWork; + } + + public Pageable getPageable() { + return pageable; + } + + public void setPageable(Pageable pageable) { + this.pageable = pageable; + } + + public Map getParameter() { + return parameter; + } + + public void setParameter(Map parameter) { + this.parameter = parameter; + } + + public Class getAbstractPageWorkClass() { + return abstractPageWorkClass; + } + + public void setAbstractPageWorkClass(Class abstractPageWorkClass) { + this.abstractPageWorkClass = abstractPageWorkClass; + } +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/ConfigInfo.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/ConfigInfo.java new file mode 100644 index 0000000000000000000000000000000000000000..61c9ee2e9b35f5219f31b9499ee83dabb1b8a89e --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/ConfigInfo.java @@ -0,0 +1,52 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; + +public class ConfigInfo { + private String location; + private String method; + private Class type; + private String repositoryName; + private DataSourceWrapper dataSourceWrapper; + + + public String getRepositoryName() { + return repositoryName; + } + + public DataSourceWrapper getDataSourceWrapper() { + return dataSourceWrapper; + } + + public void setDataSourceWrapper(DataSourceWrapper dataSourceWrapper) { + this.dataSourceWrapper = dataSourceWrapper; + } + + public void setRepositoryName(String repositoryName) { + this.repositoryName = repositoryName; + } + + public String getLocation() { + return location; + } + + public void setLocation(String location) { + this.location = location; + } + + public String getMethod() { + return method; + } + + public void setMethod(String method) { + this.method = method; + } + + public Class getType() { + return type; + } + + public void setType(Class type) { + this.type = type; + } +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelper.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelper.java new file mode 100644 index 0000000000000000000000000000000000000000..2c11379b3734e31c7717496348c0d8143cf0aafb --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelper.java @@ -0,0 +1,7 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; + +public interface DataSourceWrapperHelper { + DataSourceWrapper getDataSourceWrapperByKey(String key); +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelperImpl.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelperImpl.java new file mode 100644 index 0000000000000000000000000000000000000000..7de6340f25ba7ec185fdfaee0083ea607d27ce98 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/DataSourceWrapperHelperImpl.java @@ -0,0 +1,19 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; + +public class DataSourceWrapperHelperImpl implements DataSourceWrapperHelper{ + private DataSourceWrapper[] dataSourceWrappers; + public DataSourceWrapperHelperImpl(DataSourceWrapper... dataSourceWrappers){ + this.dataSourceWrappers=dataSourceWrappers; + } + @Override + public DataSourceWrapper getDataSourceWrapperByKey(String key){ + for (DataSourceWrapper dataSourceWrapper: dataSourceWrappers) { + if(key.equals(dataSourceWrapper.getKey())){ + return dataSourceWrapper; + } + } + return null; + } +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableJdbcAuditing.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableJdbcAuditing.java new file mode 100644 index 0000000000000000000000000000000000000000..c2a8b105a026c8a0cf9771a1fe3a5480348a70c4 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableJdbcAuditing.java @@ -0,0 +1,62 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import org.springframework.context.annotation.Import; +import org.springframework.data.auditing.DateTimeProvider; +import org.springframework.data.domain.AuditorAware; + +import java.lang.annotation.*; + +/** + * Annotation to enable auditing in JDBC via annotation configuration. + * + * + * @author Kazuki Shimizu + */ +@Inherited +@Documented +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Import(JdbcAuditingRegistrar.class) +public @interface EnableJdbcAuditing { + + /** + * Configures the {@link AuditorAware} bean to be used to lookup the current principal. + * + * @see AuditorAware + */ + String auditorAwareRef() default ""; + + /** + * Configures whether the creation and modification dates are set. + */ + boolean setDates() default true; + + /** + * Configures whether the entity shall be marked as modified on creation. + */ + boolean modifyOnCreate() default true; + + /** + * Configures a {@link DateTimeProvider} bean name that allows customizing the {@link java.time.LocalDateTime} to be + * used for setting creation and modification dates. + * + * @see DateTimeProvider + */ + String dateTimeProviderRef() default ""; + +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableMybatisMini.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableMybatisMini.java new file mode 100644 index 0000000000000000000000000000000000000000..d8f346f730aef78e085f67d4514e3f437a45172b --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/EnableMybatisMini.java @@ -0,0 +1,95 @@ +/* + * Copyright 2017-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import org.springframework.beans.factory.FactoryBean; +import org.springframework.context.annotation.ComponentScan.Filter; +import org.springframework.context.annotation.Import; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.support.JdbcRepositoryFactoryBean; + +import java.lang.annotation.*; + +/** + * Annotation to enable JDBC repositories. Will scan the package of the annotated configuration class for Spring Data + * repositories by default. + * + * @author Jens Schauder + * @author Greg Turnquist + * @author Mark Paluch + * @see JdbcConfiguration + */ +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +@Documented +@Inherited +@Import(JdbcRepositoriesRegistrar.class) +public @interface EnableMybatisMini { + + /** + * Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.: + * {@code @EnableJdbcRepositories("org.my.pkg")} instead of {@code @EnableJdbcRepositories(basePackages="org.my.pkg")}. + */ + String[] value() default {}; + + /** + * Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this + * attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names. + */ + String[] basePackages() default {}; + + /** + * Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The + * package of each class specified will be scanned. Consider creating a special no-op marker class or interface in + * each package that serves no purpose other than being referenced by this attribute. + */ + Class[] basePackageClasses() default {}; + + /** + * Specifies which types are eligible for component scanning. Further narrows the set of candidate components from + * everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters. + */ + Filter[] includeFilters() default {}; + + /** + * Specifies which types are not eligible for component scanning. + */ + Filter[] excludeFilters() default {}; + + /** + * Configures whether nested repository-interfaces (e.g. defined as inner classes) should be discovered by the + * repositories infrastructure. + */ + boolean considerNestedRepositories() default false; + + /** + * Returns the {@link FactoryBean} class to be used for each repository instance. Defaults to + * {@link JdbcRepositoryFactoryBean}. + */ + Class repositoryFactoryBeanClass() default JdbcRepositoryFactoryBean.class; + + /** + * Configures the location of where to find the Spring Data named queries properties file. Will default to + * {@code META-INF/jdbc-named-queries.properties}. + */ + String namedQueriesLocation() default ""; + + /** + * Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So + * for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning + * for {@code PersonRepositoryImpl}. + */ + String repositoryImplementationPostfix() default "Impl"; +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcAuditingRegistrar.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcAuditingRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..8f53be6d233e59327b6693fa90778ec285b82abc --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcAuditingRegistrar.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.support.BeanDefinitionBuilder; +import org.springframework.beans.factory.support.BeanDefinitionRegistry; +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.auditing.IsNewAwareAuditingHandler; +import org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport; +import org.springframework.data.auditing.config.AuditingConfiguration; +import org.springframework.util.Assert; + +import java.lang.annotation.Annotation; + +/** + * {@link ImportBeanDefinitionRegistrar} which registers additional beans in order to enable auditing via the + * {@link EnableJdbcAuditing} annotation. + * + * @see EnableJdbcAuditing + * @author Kazuki Shimizu + * @author Jens Schauder + */ +class JdbcAuditingRegistrar extends AuditingBeanDefinitionRegistrarSupport { + + private static final String AUDITING_HANDLER_BEAN_NAME = "jdbcAuditingHandler"; + private static final String JDBC_MAPPING_CONTEXT_BEAN_NAME = "jdbcMappingContext"; + + /** + * {@inheritDoc} + * + * @return return the {@link EnableJdbcAuditing} + * @see AuditingBeanDefinitionRegistrarSupport#getAnnotation() + */ + @Override + protected Class getAnnotation() { + return EnableJdbcAuditing.class; + } + + /** + * {@inheritDoc} + * + * @return return "{@literal jdbcAuditingHandler}" + * @see AuditingBeanDefinitionRegistrarSupport#getAuditingHandlerBeanName() + */ + @Override + protected String getAuditingHandlerBeanName() { + return AUDITING_HANDLER_BEAN_NAME; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.auditing.config.AuditingBeanDefinitionRegistrarSupport#getAuditHandlerBeanDefinitionBuilder(org.springframework.data.auditing.config.AuditingConfiguration) + */ + @Override + protected BeanDefinitionBuilder getAuditHandlerBeanDefinitionBuilder(AuditingConfiguration configuration) { + + Assert.notNull(configuration, "AuditingConfiguration must not be null!"); + + BeanDefinitionBuilder builder = configureDefaultAuditHandlerAttributes(configuration, + BeanDefinitionBuilder.rootBeanDefinition(IsNewAwareAuditingHandler.class)); + return builder.addConstructorArgReference(JDBC_MAPPING_CONTEXT_BEAN_NAME); + } + + /** + * Register the bean definition of{@inheritDoc} + * + * @see AuditingBeanDefinitionRegistrarSupport#registerAuditListenerBeanDefinition(BeanDefinition, + * BeanDefinitionRegistry) + */ + @Override + protected void registerAuditListenerBeanDefinition(BeanDefinition auditingHandlerDefinition, + BeanDefinitionRegistry registry) { + + } + +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcConfiguration.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcConfiguration.java new file mode 100644 index 0000000000000000000000000000000000000000..010f2fdd219445d28eb3745dfa054ee9a2b9f666 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcConfiguration.java @@ -0,0 +1,49 @@ +/* + * Copyright 2017-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + + +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; +import com.vonchange.spring.data.mybatis.mini.repository.JdbcRepositorySpringDataImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import javax.sql.DataSource; + +/** + * Beans that must be registered for Spring Data JDBC to work. + * + * @author Greg Turnquist + * @author Jens Schauder + * @author Mark Paluch + * @author Michael Simons + * @author Christoph Strobl + */ +@Configuration +public class JdbcConfiguration { + + + @Bean(name = "jdbcRepository") + public JdbcRepository initJdbcRepository(DataSource... dataSource){ + return new JdbcRepositorySpringDataImpl(dataSource); + } + @Bean + public DataSourceWrapperHelper initDataSourceWrapperHelper(@Autowired(required = false)DataSourceWrapper... dataSourceWrapper){ + return new DataSourceWrapperHelperImpl(dataSourceWrapper); + } +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoriesRegistrar.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoriesRegistrar.java new file mode 100644 index 0000000000000000000000000000000000000000..bf8b8c7473fd0986c5f8ed7029eaa52caf904110 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoriesRegistrar.java @@ -0,0 +1,48 @@ +/* + * Copyright 2017-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import org.springframework.context.annotation.ImportBeanDefinitionRegistrar; +import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport; +import org.springframework.data.repository.config.RepositoryConfigurationExtension; + +import java.lang.annotation.Annotation; + +/** + * {@link ImportBeanDefinitionRegistrar} to enable {@link EnableMybatisMini} annotation. + * + * @author Jens Schauder + */ +class JdbcRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport { + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation() + */ + @Override + protected Class getAnnotation() { + return EnableMybatisMini.class; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension() + */ + @Override + protected RepositoryConfigurationExtension getExtension() { + return new JdbcRepositoryConfigExtension(); + } +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoryConfigExtension.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoryConfigExtension.java new file mode 100644 index 0000000000000000000000000000000000000000..b503d9140007a87234a8d48fe60b628267d4582b --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/config/JdbcRepositoryConfigExtension.java @@ -0,0 +1,35 @@ + +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.config; + +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.support.JdbcRepositoryFactoryBean; +import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport; + +import java.util.Locale; + + + + +public class JdbcRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport { + + + + @Override + public String getModuleName() { + return "JDBC"; + } + + public String getRepositoryFactoryClassName() { + return JdbcRepositoryFactoryBean.class.getName(); + } + + public String getRepositoryFactoryBeanClassName() { + return JdbcRepositoryFactoryBean.class.getName(); + } + + @Override + protected String getModulePrefix() { + return getModuleName().toLowerCase(Locale.US); + } + + +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/BatchUpdate.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/BatchUpdate.java new file mode 100644 index 0000000000000000000000000000000000000000..5b35e63040938f76b84f8af09f00f2723b8f7dd6 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/BatchUpdate.java @@ -0,0 +1,13 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.query; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) +@Documented +public @interface BatchUpdate { + /** + * Batch Size + */ + int size() default 5000; +} \ No newline at end of file diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/DataSourceKey.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/DataSourceKey.java new file mode 100644 index 0000000000000000000000000000000000000000..fe800d863f854011cb1f745d0251aacaf2c7d274 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/DataSourceKey.java @@ -0,0 +1,15 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.query; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +@Inherited +public @interface DataSourceKey { + + /** + * 数据源key + */ + String value() default ""; +} \ No newline at end of file diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Insert.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Insert.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Insert.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Insert.java diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/ReadDataSource.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/ReadDataSource.java new file mode 100644 index 0000000000000000000000000000000000000000..b02c3758ecdeeb3b9713386a58d35ffa8bdcaea6 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/ReadDataSource.java @@ -0,0 +1,10 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.query; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.METHOD, ElementType.ANNOTATION_TYPE }) +@Documented +public @interface ReadDataSource { + +} \ No newline at end of file diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/SqlPackage.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/SqlPackage.java new file mode 100644 index 0000000000000000000000000000000000000000..69310ac93f3f2038b38f5dbb8dd5ffcc1ab6637f --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/SqlPackage.java @@ -0,0 +1,15 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.query; + +import java.lang.annotation.*; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@Documented +@Inherited +public @interface SqlPackage { + + /** + * sql package location + */ + String value() default ""; +} \ No newline at end of file diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Update.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Update.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Update.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/query/Update.java diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseModel.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseModel.java new file mode 100644 index 0000000000000000000000000000000000000000..bff2ef97b3edbc9ce12a14807db621ac1f73b6fd --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseModel.java @@ -0,0 +1,13 @@ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +public class BaseModel { + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseQueryRepository.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseQueryRepository.java new file mode 100644 index 0000000000000000000000000000000000000000..bc3e30977c53de89efaa5b8f4de880b1822a14c2 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseQueryRepository.java @@ -0,0 +1,30 @@ +/* + * Copyright 2008-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +import org.springframework.data.repository.NoRepositoryBean; +import org.springframework.data.repository.Repository; + +/** + * Interface for generic CRUD operations on a repository for a specific type. + * + * @author Oliver Gierke + * @author Eberhard Wolff + */ +@NoRepositoryBean +public interface BaseQueryRepository extends Repository { + +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseRepository.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseRepository.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseRepository.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/BaseRepository.java diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryLookupStrategy.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryLookupStrategy.java new file mode 100644 index 0000000000000000000000000000000000000000..f84d61b0d27f1f29ad425e0f1922c9a77167b7b7 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryLookupStrategy.java @@ -0,0 +1,80 @@ +/* + * Copyright 2018-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.ConfigInfo; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.DataSourceWrapperHelper; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.DataSourceKey; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.query.SqlPackage; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.data.projection.ProjectionFactory; +import org.springframework.data.repository.core.NamedQueries; +import org.springframework.data.repository.core.RepositoryMetadata; +import org.springframework.data.repository.query.QueryLookupStrategy; +import org.springframework.data.repository.query.RepositoryQuery; +import org.springframework.util.Assert; + +import java.lang.reflect.Method; + +/** + * {@link QueryLookupStrategy} for JDBC repositories. Currently only supports annotated queries. + * + * @author Jens Schauder + * @author Kazuki Shimizu + * @author Oliver Gierke + * @author Mark Paluch + * @author Maciej Walkowiak + */ +class JdbcQueryLookupStrategy implements QueryLookupStrategy { + + private final JdbcRepository operations; + private final DataSourceWrapperHelper dataSourceWrapperHelper; + + /** + * Creates a new {@link JdbcQueryLookupStrategy} for the given + * + */ + JdbcQueryLookupStrategy(@Qualifier("jdbcRepository")JdbcRepository operations, DataSourceWrapperHelper dataSourceWrapperHelper) { + + Assert.notNull(operations, "operations must not be null!"); + this.operations = operations; + this.dataSourceWrapperHelper=dataSourceWrapperHelper; + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.query.QueryLookupStrategy#resolveQuery(java.lang.reflect.Method, org.springframework.data.repository.core.RepositoryMetadata, org.springframework.data.projection.ProjectionFactory, org.springframework.data.repository.core.NamedQueries) + */ + @Override + public RepositoryQuery resolveQuery(Method method, RepositoryMetadata repositoryMetadata, + ProjectionFactory projectionFactory, NamedQueries namedQueries) { + String interfaceName =repositoryMetadata.getRepositoryInterface().getSimpleName(); + SqlPackage sqlPackage= repositoryMetadata.getRepositoryInterface().getAnnotation(SqlPackage.class); + DataSourceKey dataSourceKey= repositoryMetadata.getRepositoryInterface().getAnnotation(DataSourceKey.class); + String configLoc=null!=sqlPackage?sqlPackage.value()+"."+interfaceName:"sql."+interfaceName; + String dataSourceKeyValue=null!=dataSourceKey?dataSourceKey.value():null; + JdbcQueryMethod queryMethod = new JdbcQueryMethod(method, repositoryMetadata, projectionFactory); + ConfigInfo configInfo= new ConfigInfo(); + configInfo.setMethod(method.getName()); + configInfo.setLocation(configLoc); + configInfo.setRepositoryName(interfaceName); + configInfo.setType(repositoryMetadata.getDomainType()); + configInfo.setDataSourceWrapper(null!=dataSourceKeyValue?dataSourceWrapperHelper.getDataSourceWrapperByKey(dataSourceKeyValue):null); + return new JdbcRepositoryQuery(queryMethod, operations,configInfo); + } + +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryMethod.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryMethod.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryMethod.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcQueryMethod.java diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactory.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactory.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactory.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactory.java diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactoryBean.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactoryBean.java new file mode 100644 index 0000000000000000000000000000000000000000..40d521ae5ece64023ef31d6e981be61221eef44f --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryFactoryBean.java @@ -0,0 +1,88 @@ +/* + * Copyright 2017-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; + +import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; +import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.DataSourceWrapperHelper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationEventPublisherAware; +import org.springframework.data.repository.Repository; +import org.springframework.data.repository.core.support.RepositoryFactorySupport; +import org.springframework.data.repository.core.support.TransactionalRepositoryFactoryBeanSupport; + +import java.io.Serializable; + +//import org.springframework.data.jdbc.core.DefaultDataAccessStrategy; + +/** + * Special adapter for Springs {@link org.springframework.beans.factory.FactoryBean} interface to allow easy setup of + * repository factories via Spring configuration. + * + * @author Jens Schauder + * @author Greg Turnquist + * @author Christoph Strobl + * @author Oliver Gierke + * @author Mark Paluch + */ +public class JdbcRepositoryFactoryBean, S, ID extends Serializable> // + extends TransactionalRepositoryFactoryBeanSupport implements ApplicationEventPublisherAware { + + private JdbcRepository jdbcRepository; + private DataSourceWrapperHelper dataSourceWrapperHelper; + + /** + * Creates a new {@link JdbcRepositoryFactoryBean} for the given repository interface. + * + * @param repositoryInterface must not be {@literal null}. + */ + JdbcRepositoryFactoryBean(Class repositoryInterface) { + super(repositoryInterface); + } + + /* + * (non-Javadoc) + * @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher) + */ + @Override + public void setApplicationEventPublisher(ApplicationEventPublisher publisher) { + + super.setApplicationEventPublisher(publisher); + } + + /** + * Creates the actual {@link RepositoryFactorySupport} instance. + */ + @Override + protected RepositoryFactorySupport doCreateRepositoryFactory() { + JdbcRepositoryFactory jdbcRepositoryFactory = new JdbcRepositoryFactory( + jdbcRepository,dataSourceWrapperHelper); + return jdbcRepositoryFactory; + } + + + + @Autowired + public void setDataSourceWrapperHelper(DataSourceWrapperHelper dataSourceWrapperHelper) { + this.dataSourceWrapperHelper = dataSourceWrapperHelper; + } + @Autowired + public void setJdbcOperations(@Qualifier("jdbcRepository") JdbcRepository jdbcRepository) { + this.jdbcRepository = jdbcRepository; + } + +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java similarity index 99% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java index f11eb34ea9f9224b88ae9312375543de03778fd1..d71989c11b223720e8ddf2e8b5ab903b6e5de3f3 100644 --- a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/JdbcRepositoryQuery.java @@ -15,10 +15,10 @@ */ package com.vonchange.spring.data.mybatis.mini.jdbc.repository.support; +import com.vonchange.common.util.ClazzUtils; import com.vonchange.jdbc.abstractjdbc.core.JdbcRepository; import com.vonchange.jdbc.abstractjdbc.handler.AbstractPageWork; import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; -import com.vonchange.mybatis.tpl.clazz.ClazzUtils; import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.BindParameterWrapper; import com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.ConfigInfo; import org.slf4j.Logger; diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/SimpleJdbcRepository.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/SimpleJdbcRepository.java similarity index 100% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/SimpleJdbcRepository.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/jdbc/repository/support/SimpleJdbcRepository.java diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/DataSourceInSql.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/DataSourceInSql.java new file mode 100644 index 0000000000000000000000000000000000000000..a6d55bfaf8ee14efd2c0807dbf26b8dc4f9821b9 --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/DataSourceInSql.java @@ -0,0 +1,7 @@ +package com.vonchange.spring.data.mybatis.mini.repository; + +import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; + +public interface DataSourceInSql { + DataSourceWrapper getDataSourceFromSql(String sql); +} diff --git a/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java similarity index 98% rename from src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java rename to spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java index d32327c16bde9d728994a7c0ecf59cbfd31954f2..03df044eb4537d7d8ed2a05db44714f1482aa536 100644 --- a/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/JdbcRepositorySpringDataImpl.java @@ -5,7 +5,7 @@ import com.vonchange.jdbc.abstractjdbc.model.DataSourceWrapper; import com.vonchange.jdbc.springjdbc.repository.AbstractJbdcRepositoryMysql; import com.vonchange.mybatis.dialect.Dialect; import com.vonchange.mybatis.dialect.MySQLDialect; -import com.vonchange.mybatis.tpl.exception.MybatisMinRuntimeException; +import com.vonchange.mybatis.exception.MybatisMinRuntimeException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/ReadDataSources.java b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/ReadDataSources.java new file mode 100644 index 0000000000000000000000000000000000000000..5a2597da682940821411c15c31418e18d75461fb --- /dev/null +++ b/spring-data-mybatis-mini/src/main/java/com/vonchange/spring/data/mybatis/mini/repository/ReadDataSources.java @@ -0,0 +1,7 @@ +package com.vonchange.spring.data.mybatis.mini.repository; + +import javax.sql.DataSource; + +public interface ReadDataSources { + DataSource[] allReadDataSources(); +} diff --git a/spring-data-mybatis-mini/src/main/resources/META-INF/spring.factories b/spring-data-mybatis-mini/src/main/resources/META-INF/spring.factories new file mode 100644 index 0000000000000000000000000000000000000000..2817844d8260feedf55d21381f44bce607db767c --- /dev/null +++ b/spring-data-mybatis-mini/src/main/resources/META-INF/spring.factories @@ -0,0 +1,2 @@ +org.springframework.data.repository.core.support.RepositoryFactorySupport=com.vonchange.spring.data.mybatis.mini.jdbc.repository.support.JdbcRepositoryFactory +org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.vonchange.spring.data.mybatis.mini.jdbc.repository.config.JdbcConfiguration \ No newline at end of file