001/**
002 * Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
003 * <p>
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 * <p>
008 * http://www.apache.org/licenses/LICENSE-2.0
009 * <p>
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package com.mybatisflex.spring.boot;
017
018import org.apache.ibatis.io.VFS;
019import org.apache.ibatis.logging.Log;
020import org.apache.ibatis.mapping.ResultSetType;
021import org.apache.ibatis.scripting.LanguageDriver;
022import org.apache.ibatis.session.*;
023import org.apache.ibatis.type.JdbcType;
024import org.apache.ibatis.type.TypeHandler;
025import org.springframework.boot.context.properties.ConfigurationProperties;
026import org.springframework.boot.context.properties.PropertyMapper;
027import org.springframework.core.io.Resource;
028import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
029import org.springframework.core.io.support.ResourcePatternResolver;
030
031import java.io.IOException;
032import java.util.Map;
033import java.util.Optional;
034import java.util.Properties;
035import java.util.Set;
036import java.util.stream.Stream;
037
038/**
039 * Mybatis-Flex 的配置属性
040 * 设置 mapUnderscoreToCamelCase 默认值为 true
041 */
042@ConfigurationProperties(prefix = "mybatis-flex")
043public class MybatisFlexProperties {
044
045
046    private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
047
048    //多数据源的配置
049    //mybatis-flex.datasource.ds1.url=***
050    //mybatis-flex.datasource.ds2.url=***
051    private Map<String, Map<String,String>> datasource;
052
053    /**
054     * Location of MyBatis xml config file.
055     */
056    private String configLocation;
057
058    /**
059     * Locations of MyBatis mapper files.
060     */
061    private String[] mapperLocations = new String[]{"classpath*:/mapper/**/*.xml"};
062
063    /**
064     * Packages to search type aliases. (Package delimiters are ",; \t\n")
065     */
066    private String typeAliasesPackage;
067
068    /**
069     * The super class for filtering type alias. If this not specifies, the MyBatis deal as type alias all classes that
070     * searched from typeAliasesPackage.
071     */
072    private Class<?> typeAliasesSuperType;
073
074    /**
075     * Packages to search for type handlers. (Package delimiters are ",; \t\n")
076     */
077    private String typeHandlersPackage;
078
079    /**
080     * Indicates whether perform presence check of the MyBatis xml config file.
081     */
082    private boolean checkConfigLocation = false;
083
084    /**
085     * Execution mode for {@link org.mybatis.spring.SqlSessionTemplate}.
086     */
087    private ExecutorType executorType;
088
089    /**
090     * The default scripting language driver class. (Available when use together with mybatis-spring 2.0.2+)
091     */
092    private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;
093
094    /**
095     * Externalized properties for MyBatis configuration.
096     */
097    private Properties configurationProperties;
098
099    /**
100     * A Configuration object for customize default settings. If {@link #configLocation} is specified, this property is
101     * not used.
102     */
103    private CoreConfiguration configuration;
104
105    public Map<String, Map<String, String>> getDatasource() {
106        return datasource;
107    }
108
109    public void setDatasource(Map<String, Map<String, String>> datasource) {
110        this.datasource = datasource;
111    }
112
113    /**
114     * @since 1.1.0
115     */
116    public String getConfigLocation() {
117        return this.configLocation;
118    }
119
120    /**
121     * @since 1.1.0
122     */
123    public void setConfigLocation(String configLocation) {
124        this.configLocation = configLocation;
125    }
126
127    public String[] getMapperLocations() {
128        return this.mapperLocations;
129    }
130
131    public void setMapperLocations(String[] mapperLocations) {
132        this.mapperLocations = mapperLocations;
133    }
134
135    public String getTypeHandlersPackage() {
136        return this.typeHandlersPackage;
137    }
138
139    public void setTypeHandlersPackage(String typeHandlersPackage) {
140        this.typeHandlersPackage = typeHandlersPackage;
141    }
142
143    public String getTypeAliasesPackage() {
144        return this.typeAliasesPackage;
145    }
146
147    public void setTypeAliasesPackage(String typeAliasesPackage) {
148        this.typeAliasesPackage = typeAliasesPackage;
149    }
150
151    /**
152     * @since 1.3.3
153     */
154    public Class<?> getTypeAliasesSuperType() {
155        return typeAliasesSuperType;
156    }
157
158    /**
159     * @since 1.3.3
160     */
161    public void setTypeAliasesSuperType(Class<?> typeAliasesSuperType) {
162        this.typeAliasesSuperType = typeAliasesSuperType;
163    }
164
165    public boolean isCheckConfigLocation() {
166        return this.checkConfigLocation;
167    }
168
169    public void setCheckConfigLocation(boolean checkConfigLocation) {
170        this.checkConfigLocation = checkConfigLocation;
171    }
172
173    public ExecutorType getExecutorType() {
174        return this.executorType;
175    }
176
177    public void setExecutorType(ExecutorType executorType) {
178        this.executorType = executorType;
179    }
180
181    /**
182     * @since 2.1.0
183     */
184    public Class<? extends LanguageDriver> getDefaultScriptingLanguageDriver() {
185        return defaultScriptingLanguageDriver;
186    }
187
188    /**
189     * @since 2.1.0
190     */
191    public void setDefaultScriptingLanguageDriver(Class<? extends LanguageDriver> defaultScriptingLanguageDriver) {
192        this.defaultScriptingLanguageDriver = defaultScriptingLanguageDriver;
193    }
194
195    /**
196     * @since 1.2.0
197     */
198    public Properties getConfigurationProperties() {
199        return configurationProperties;
200    }
201
202    /**
203     * @since 1.2.0
204     */
205    public void setConfigurationProperties(Properties configurationProperties) {
206        this.configurationProperties = configurationProperties;
207    }
208
209    public CoreConfiguration getConfiguration() {
210        return configuration;
211    }
212
213    public void setConfiguration(CoreConfiguration configuration) {
214        this.configuration = configuration;
215    }
216
217    public Resource[] resolveMapperLocations() {
218        return Stream.of(Optional.ofNullable(this.mapperLocations).orElse(new String[0]))
219                .flatMap(location -> Stream.of(getResources(location))).toArray(Resource[]::new);
220    }
221
222    private Resource[] getResources(String location) {
223        try {
224            return resourceResolver.getResources(location);
225        } catch (IOException e) {
226            return new Resource[0];
227        }
228    }
229
230    /**
231     * The configuration properties for mybatis core module.
232     *
233     * @since 3.0.0
234     */
235    public static class CoreConfiguration {
236
237        /**
238         * Allows using RowBounds on nested statements. If allow, set the false. Default is false.
239         */
240        private Boolean safeRowBoundsEnabled;
241
242        /**
243         * Allows using ResultHandler on nested statements. If allow, set the false. Default is true.
244         */
245        private Boolean safeResultHandlerEnabled;
246
247        /**
248         * Enables automatic mapping from classic database column names A_COLUMN to camel case classic Java property names
249         * aColumn. Default is true.
250         */
251        private Boolean mapUnderscoreToCamelCase = true;
252
253        /**
254         * When enabled, any method call will load all the lazy properties of the object. Otherwise, each property is loaded
255         * on demand (see also lazyLoadTriggerMethods). Default is false.
256         */
257        private Boolean aggressiveLazyLoading;
258
259        /**
260         * Allows or disallows multiple ResultSets to be returned from a single statement (compatible driver required).
261         * Default is true.
262         */
263        private Boolean multipleResultSetsEnabled;
264
265        /**
266         * Allows JDBC support for generated keys. A compatible driver is required. This setting forces generated keys to be
267         * used if set to true, as some drivers deny compatibility but still work (e.g. Derby). Default is false.
268         */
269        private Boolean useGeneratedKeys;
270
271        /**
272         * Uses the column label instead of the column name. Different drivers behave differently in this respect. Refer to
273         * the driver documentation, or test out both modes to determine how your driver behaves. Default is true.
274         */
275        private Boolean useColumnLabel;
276
277        /**
278         * Globally enables or disables any caches configured in any mapper under this configuration. Default is true.
279         */
280        private Boolean cacheEnabled;
281
282        /**
283         * Specifies if setters or map's put method will be called when a retrieved value is null. It is useful when you
284         * rely on Map.keySet() or null value initialization. Note primitives such as (int,boolean,etc.) will not be set to
285         * null. Default is false.
286         */
287        private Boolean callSettersOnNulls;
288
289        /**
290         * Allow referencing statement parameters by their actual names declared in the method signature. To use this
291         * feature, your project must be compiled in Java 8 with -parameters option. Default is true.
292         */
293        private Boolean useActualParamName;
294
295        /**
296         * MyBatis, by default, returns null when all the columns of a returned row are NULL. When this setting is enabled,
297         * MyBatis returns an empty instance instead. Note that it is also applied to nested results (i.e. collectioin and
298         * association). Default is false.
299         */
300        private Boolean returnInstanceForEmptyRow;
301
302        /**
303         * Removes extra whitespace characters from the SQL. Note that this also affects literal strings in SQL. Default is
304         * false.
305         */
306        private Boolean shrinkWhitespacesInSql;
307
308        /**
309         * Specifies the default value of 'nullable' attribute on 'foreach' tag. Default is false.
310         */
311        private Boolean nullableOnForEach;
312
313        /**
314         * When applying constructor auto-mapping, argument name is used to search the column to map instead of relying on
315         * the column order. Default is false.
316         */
317        private Boolean argNameBasedConstructorAutoMapping;
318
319        /**
320         * Globally enables or disables lazy loading. When enabled, all relations will be lazily loaded. This value can be
321         * superseded for a specific relation by using the fetchType attribute on it. Default is False.
322         */
323        private Boolean lazyLoadingEnabled;
324
325        /**
326         * Sets the number of seconds the driver will wait for a response from the database.
327         */
328        private Integer defaultStatementTimeout;
329
330        /**
331         * Sets the driver a hint as to control fetching size for return results. This parameter value can be override by a
332         * query setting.
333         */
334        private Integer defaultFetchSize;
335
336        /**
337         * MyBatis uses local cache to prevent circular references and speed up repeated nested queries. By default
338         * (SESSION) all queries executed during a session are cached. If localCacheScope=STATEMENT local session will be
339         * used just for statement execution, no data will be shared between two different calls to the same SqlSession.
340         * Default is SESSION.
341         */
342        private LocalCacheScope localCacheScope;
343
344        /**
345         * Specifies the JDBC type for null values when no specific JDBC type was provided for the parameter. Some drivers
346         * require specifying the column JDBC type but others work with generic values like NULL, VARCHAR or OTHER. Default
347         * is OTHER.
348         */
349        private JdbcType jdbcTypeForNull;
350
351        /**
352         * Specifies a scroll strategy when omit it per statement settings.
353         */
354        private ResultSetType defaultResultSetType;
355
356        /**
357         * Configures the default executor. SIMPLE executor does nothing special. REUSE executor reuses prepared statements.
358         * BATCH executor reuses statements and batches updates. Default is SIMPLE.
359         */
360        private ExecutorType defaultExecutorType;
361
362        /**
363         * Specifies if and how MyBatis should automatically map columns to fields/properties. NONE disables auto-mapping.
364         * PARTIAL will only auto-map results with no nested result mappings defined inside. FULL will auto-map result
365         * mappings of any complexity (containing nested or otherwise). Default is PARTIAL.
366         */
367        private AutoMappingBehavior autoMappingBehavior;
368
369        /**
370         * Specify the behavior when detects an unknown column (or unknown property type) of automatic mapping target.
371         * Default is NONE.
372         */
373        private AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior;
374
375        /**
376         * Specifies the prefix string that MyBatis will add to the logger names.
377         */
378        private String logPrefix;
379
380        /**
381         * Specifies which Object's methods trigger a lazy load. Default is [equals,clone,hashCode,toString].
382         */
383        private Set<String> lazyLoadTriggerMethods;
384
385        /**
386         * Specifies which logging implementation MyBatis should use. If this setting is not present logging implementation
387         * will be autodiscovered.
388         */
389        private Class<? extends Log> logImpl;
390
391        /**
392         * Specifies VFS implementations.
393         */
394        private Class<? extends VFS> vfsImpl;
395
396        /**
397         * Specifies an sql provider class that holds provider method. This class apply to the type(or value) attribute on
398         * sql provider annotation(e.g. @SelectProvider), when these attribute was omitted.
399         */
400        private Class<?> defaultSqlProviderType;
401
402        /**
403         * Specifies the TypeHandler used by default for Enum.
404         */
405        Class<? extends TypeHandler> defaultEnumTypeHandler;
406
407        /**
408         * Specifies the class that provides an instance of Configuration. The returned Configuration instance is used to
409         * load lazy properties of deserialized objects. This class must have a method with a signature static Configuration
410         * getConfiguration().
411         */
412        private Class<?> configurationFactory;
413
414        /**
415         * Specify any configuration variables.
416         */
417        private Properties variables;
418
419        public Boolean getSafeRowBoundsEnabled() {
420            return safeRowBoundsEnabled;
421        }
422
423        public void setSafeRowBoundsEnabled(Boolean safeRowBoundsEnabled) {
424            this.safeRowBoundsEnabled = safeRowBoundsEnabled;
425        }
426
427        public Boolean getSafeResultHandlerEnabled() {
428            return safeResultHandlerEnabled;
429        }
430
431        public void setSafeResultHandlerEnabled(Boolean safeResultHandlerEnabled) {
432            this.safeResultHandlerEnabled = safeResultHandlerEnabled;
433        }
434
435        public Boolean getMapUnderscoreToCamelCase() {
436            return mapUnderscoreToCamelCase;
437        }
438
439        public void setMapUnderscoreToCamelCase(Boolean mapUnderscoreToCamelCase) {
440            this.mapUnderscoreToCamelCase = mapUnderscoreToCamelCase;
441        }
442
443        public Boolean getAggressiveLazyLoading() {
444            return aggressiveLazyLoading;
445        }
446
447        public void setAggressiveLazyLoading(Boolean aggressiveLazyLoading) {
448            this.aggressiveLazyLoading = aggressiveLazyLoading;
449        }
450
451        public Boolean getMultipleResultSetsEnabled() {
452            return multipleResultSetsEnabled;
453        }
454
455        public void setMultipleResultSetsEnabled(Boolean multipleResultSetsEnabled) {
456            this.multipleResultSetsEnabled = multipleResultSetsEnabled;
457        }
458
459        public Boolean getUseGeneratedKeys() {
460            return useGeneratedKeys;
461        }
462
463        public void setUseGeneratedKeys(Boolean useGeneratedKeys) {
464            this.useGeneratedKeys = useGeneratedKeys;
465        }
466
467        public Boolean getUseColumnLabel() {
468            return useColumnLabel;
469        }
470
471        public void setUseColumnLabel(Boolean useColumnLabel) {
472            this.useColumnLabel = useColumnLabel;
473        }
474
475        public Boolean getCacheEnabled() {
476            return cacheEnabled;
477        }
478
479        public void setCacheEnabled(Boolean cacheEnabled) {
480            this.cacheEnabled = cacheEnabled;
481        }
482
483        public Boolean getCallSettersOnNulls() {
484            return callSettersOnNulls;
485        }
486
487        public void setCallSettersOnNulls(Boolean callSettersOnNulls) {
488            this.callSettersOnNulls = callSettersOnNulls;
489        }
490
491        public Boolean getUseActualParamName() {
492            return useActualParamName;
493        }
494
495        public void setUseActualParamName(Boolean useActualParamName) {
496            this.useActualParamName = useActualParamName;
497        }
498
499        public Boolean getReturnInstanceForEmptyRow() {
500            return returnInstanceForEmptyRow;
501        }
502
503        public void setReturnInstanceForEmptyRow(Boolean returnInstanceForEmptyRow) {
504            this.returnInstanceForEmptyRow = returnInstanceForEmptyRow;
505        }
506
507        public Boolean getShrinkWhitespacesInSql() {
508            return shrinkWhitespacesInSql;
509        }
510
511        public void setShrinkWhitespacesInSql(Boolean shrinkWhitespacesInSql) {
512            this.shrinkWhitespacesInSql = shrinkWhitespacesInSql;
513        }
514
515        public Boolean getNullableOnForEach() {
516            return nullableOnForEach;
517        }
518
519        public void setNullableOnForEach(Boolean nullableOnForEach) {
520            this.nullableOnForEach = nullableOnForEach;
521        }
522
523        public Boolean getArgNameBasedConstructorAutoMapping() {
524            return argNameBasedConstructorAutoMapping;
525        }
526
527        public void setArgNameBasedConstructorAutoMapping(Boolean argNameBasedConstructorAutoMapping) {
528            this.argNameBasedConstructorAutoMapping = argNameBasedConstructorAutoMapping;
529        }
530
531        public String getLogPrefix() {
532            return logPrefix;
533        }
534
535        public void setLogPrefix(String logPrefix) {
536            this.logPrefix = logPrefix;
537        }
538
539        public Class<? extends Log> getLogImpl() {
540            return logImpl;
541        }
542
543        public void setLogImpl(Class<? extends Log> logImpl) {
544            this.logImpl = logImpl;
545        }
546
547        public Class<? extends VFS> getVfsImpl() {
548            return vfsImpl;
549        }
550
551        public void setVfsImpl(Class<? extends VFS> vfsImpl) {
552            this.vfsImpl = vfsImpl;
553        }
554
555        public Class<?> getDefaultSqlProviderType() {
556            return defaultSqlProviderType;
557        }
558
559        public void setDefaultSqlProviderType(Class<?> defaultSqlProviderType) {
560            this.defaultSqlProviderType = defaultSqlProviderType;
561        }
562
563        public LocalCacheScope getLocalCacheScope() {
564            return localCacheScope;
565        }
566
567        public void setLocalCacheScope(LocalCacheScope localCacheScope) {
568            this.localCacheScope = localCacheScope;
569        }
570
571        public JdbcType getJdbcTypeForNull() {
572            return jdbcTypeForNull;
573        }
574
575        public void setJdbcTypeForNull(JdbcType jdbcTypeForNull) {
576            this.jdbcTypeForNull = jdbcTypeForNull;
577        }
578
579        public Set<String> getLazyLoadTriggerMethods() {
580            return lazyLoadTriggerMethods;
581        }
582
583        public void setLazyLoadTriggerMethods(Set<String> lazyLoadTriggerMethods) {
584            this.lazyLoadTriggerMethods = lazyLoadTriggerMethods;
585        }
586
587        public Integer getDefaultStatementTimeout() {
588            return defaultStatementTimeout;
589        }
590
591        public void setDefaultStatementTimeout(Integer defaultStatementTimeout) {
592            this.defaultStatementTimeout = defaultStatementTimeout;
593        }
594
595        public Integer getDefaultFetchSize() {
596            return defaultFetchSize;
597        }
598
599        public void setDefaultFetchSize(Integer defaultFetchSize) {
600            this.defaultFetchSize = defaultFetchSize;
601        }
602
603        public ResultSetType getDefaultResultSetType() {
604            return defaultResultSetType;
605        }
606
607        public void setDefaultResultSetType(ResultSetType defaultResultSetType) {
608            this.defaultResultSetType = defaultResultSetType;
609        }
610
611        public ExecutorType getDefaultExecutorType() {
612            return defaultExecutorType;
613        }
614
615        public void setDefaultExecutorType(ExecutorType defaultExecutorType) {
616            this.defaultExecutorType = defaultExecutorType;
617        }
618
619        public AutoMappingBehavior getAutoMappingBehavior() {
620            return autoMappingBehavior;
621        }
622
623        public void setAutoMappingBehavior(AutoMappingBehavior autoMappingBehavior) {
624            this.autoMappingBehavior = autoMappingBehavior;
625        }
626
627        public AutoMappingUnknownColumnBehavior getAutoMappingUnknownColumnBehavior() {
628            return autoMappingUnknownColumnBehavior;
629        }
630
631        public void setAutoMappingUnknownColumnBehavior(AutoMappingUnknownColumnBehavior autoMappingUnknownColumnBehavior) {
632            this.autoMappingUnknownColumnBehavior = autoMappingUnknownColumnBehavior;
633        }
634
635        public Properties getVariables() {
636            return variables;
637        }
638
639        public void setVariables(Properties variables) {
640            this.variables = variables;
641        }
642
643        public Boolean getLazyLoadingEnabled() {
644            return lazyLoadingEnabled;
645        }
646
647        public void setLazyLoadingEnabled(Boolean lazyLoadingEnabled) {
648            this.lazyLoadingEnabled = lazyLoadingEnabled;
649        }
650
651        public Class<?> getConfigurationFactory() {
652            return configurationFactory;
653        }
654
655        public void setConfigurationFactory(Class<?> configurationFactory) {
656            this.configurationFactory = configurationFactory;
657        }
658
659        public Class<? extends TypeHandler> getDefaultEnumTypeHandler() {
660            return defaultEnumTypeHandler;
661        }
662
663        public void setDefaultEnumTypeHandler(Class<? extends TypeHandler> defaultEnumTypeHandler) {
664            this.defaultEnumTypeHandler = defaultEnumTypeHandler;
665        }
666
667        void applyTo(Configuration target) {
668            PropertyMapper mapper = PropertyMapper.get().alwaysApplyingWhenNonNull();
669            mapper.from(getSafeRowBoundsEnabled()).to(target::setSafeRowBoundsEnabled);
670            mapper.from(getSafeResultHandlerEnabled()).to(target::setSafeResultHandlerEnabled);
671            mapper.from(getMapUnderscoreToCamelCase()).to(target::setMapUnderscoreToCamelCase);
672            mapper.from(getAggressiveLazyLoading()).to(target::setAggressiveLazyLoading);
673            mapper.from(getMultipleResultSetsEnabled()).to(target::setMultipleResultSetsEnabled);
674            mapper.from(getUseGeneratedKeys()).to(target::setUseGeneratedKeys);
675            mapper.from(getUseColumnLabel()).to(target::setUseColumnLabel);
676            mapper.from(getCacheEnabled()).to(target::setCacheEnabled);
677            mapper.from(getCallSettersOnNulls()).to(target::setCallSettersOnNulls);
678            mapper.from(getUseActualParamName()).to(target::setUseActualParamName);
679            mapper.from(getReturnInstanceForEmptyRow()).to(target::setReturnInstanceForEmptyRow);
680            mapper.from(getShrinkWhitespacesInSql()).to(target::setShrinkWhitespacesInSql);
681            mapper.from(getNullableOnForEach()).to(target::setNullableOnForEach);
682            mapper.from(getArgNameBasedConstructorAutoMapping()).to(target::setArgNameBasedConstructorAutoMapping);
683            mapper.from(getLazyLoadingEnabled()).to(target::setLazyLoadingEnabled);
684            mapper.from(getLogPrefix()).to(target::setLogPrefix);
685            mapper.from(getLazyLoadTriggerMethods()).to(target::setLazyLoadTriggerMethods);
686            mapper.from(getDefaultStatementTimeout()).to(target::setDefaultStatementTimeout);
687            mapper.from(getDefaultFetchSize()).to(target::setDefaultFetchSize);
688            mapper.from(getLocalCacheScope()).to(target::setLocalCacheScope);
689            mapper.from(getJdbcTypeForNull()).to(target::setJdbcTypeForNull);
690            mapper.from(getDefaultResultSetType()).to(target::setDefaultResultSetType);
691            mapper.from(getDefaultExecutorType()).to(target::setDefaultExecutorType);
692            mapper.from(getAutoMappingBehavior()).to(target::setAutoMappingBehavior);
693            mapper.from(getAutoMappingUnknownColumnBehavior()).to(target::setAutoMappingUnknownColumnBehavior);
694            mapper.from(getVariables()).to(target::setVariables);
695            mapper.from(getLogImpl()).to(target::setLogImpl);
696            mapper.from(getVfsImpl()).to(target::setVfsImpl);
697            mapper.from(getDefaultSqlProviderType()).to(target::setDefaultSqlProviderType);
698            mapper.from(getConfigurationFactory()).to(target::setConfigurationFactory);
699            mapper.from(getDefaultEnumTypeHandler()).to(target::setDefaultEnumTypeHandler);
700        }
701
702    }
703
704}