springCloud 微服务日志配置

springCloud 微服务日志配置

项目日志配置

logback-spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<!-- 日志级别从低到高分为TRACE < DEBUG < INFO < WARN < ERROR < FATAL,
如果设置为WARN,则低于WARN的信息都不会输出 -->
<!-- scan:当此属性设置为true时,配置文档如果发生改变,将会被重新加载,默认值为true -->
<!-- scanPeriod:设置监测配置文档是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒。
                 当scan为true时,此属性生效。默认的时间间隔为1分钟。 -->
<!-- debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。
默认值为false。 -->
<configuration  scan="true" scanPeriod="10 seconds">


    <!-- name的值是变量的名称,value的值时变量定义的值。通过定义的值会被插入到logger上下文中。定义后,可以使“${}”来使用变量。 -->
    <!-- <property name="log.path" value="F:/logs" />-->
    <springProperty scop="context" name="spring.application.name" source="spring.application.name" defaultValue=""/>
    <property name="log.path" value="logs/${spring.application.name}"/>


    <!-- 日志格式和颜色渲染 -->
    <!-- 彩色日志依赖的渲染类 -->
    <conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
    <conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
    <conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
    <!-- 彩色日志格式 -->
    <property name="CONSOLE_LOG_PATTERN" value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}"/>

    <!--输出到控制台-->

    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--此日志appender是为开发使用,只配置最底级别,控制台输出的日志级别是大于或等于此级别的日志信息-->
        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
            <level>info</level>
        </filter>
        <encoder>
            <Pattern>${CONSOLE_LOG_PATTERN}</Pattern>
            <!-- 设置字符集 -->
            <charset>UTF-8</charset>
        </encoder>
    </appender>
    <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <!--
        日志输出格式:
			%d表示日期时间,
			%thread表示线程名,
			%-5level:级别从左显示5个字符宽度
			%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
			%msg:日志消息,
			%n是换行符
			%-15.15():如果记录的线程字符长度小于15(第一个)则用空格在右侧补齐,如果字符长度大于15(第二个),则从开头开始截断多余的字符
			%-50.50():如果记录的logger字符长度小于50(第一个)则用空格在右侧补齐,如果字符长度大于50(第二个),则从开头开始截断多余的字符
			%highlight():颜色,info为蓝色,warn为浅红,error为加粗红,debug为黑色
			%boldMagenta:粗红
			%magenta:洋红
			$cyan:青色
			%white:白色
        -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <springProfile name="dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}  %highlight(%-5level) %magenta([%-15.15(%thread)])  %cyan( %-50.50(%logger{50} )) : %msg%n</pattern>
            </springProfile>
            <springProfile name="!dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS}  %highlight(%-5level) %magenta([%-15.15(%thread)])  %cyan( %-50.50(%logger{50} )) : %msg%n</pattern>
            </springProfile>
        </layout>
    </appender>

    <!--控制台打印警告信息的单独处理-->
    <appender name="consoleWarn" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <springProfile name="dev">
                <pattern>%magenta(%d{yyyy-MM-dd HH:mm:ss.SSS}  %highlight(%-5level) %magenta([%-15.15(%thread)])  %cyan( %-50.50(%logger{50} )) : %msg%n)</pattern>
            </springProfile>
            <springProfile name="!dev">
                <pattern>%magenta(%d{yyyy-MM-dd HH:mm:ss.SSS}  %highlight(%-5level) %magenta([%-15.15(%thread)])  %cyan( %-50.50(%logger{50} )) : %msg%n)</pattern>
            </springProfile>
        </layout>
    </appender>

    <!--控制台打印错误信息的单独处理-->
    <appender name="consoleError" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <springProfile name="dev">
                <pattern>%boldMagenta(%d{yyyy-MM-dd HH:mm:ss.SSS}  %highlight(%-5level) %magenta([%-15.15(%thread)])  %cyan( %-50.50(%logger{50} )) : %msg%n)</pattern>
            </springProfile>
            <springProfile name="!dev">
                <pattern>%boldMagenta(%d{yyyy-MM-dd HH:mm:ss.SSS}  %highlight(%-5level) %magenta([%-15.15(%thread)])  %cyan( %-50.50(%logger{50} )) : %msg%n)</pattern>
            </springProfile>
        </layout>
    </appender>


    <!--输出到文档-->
    <!--level为 DEBUG 日志,时间滚动输出  -->
    <appender name="DEBUG_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/web_debug.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 日志归档 -->
            <fileNamePattern>${log.path}/web-debug-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
            <!--
                   当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy
                   是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
               -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>

        </rollingPolicy>
        <!-- 此日志文档只记录debug级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>debug</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--level为 INFO 日志,时间滚动输出  -->
    <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/web_info.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset>
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!-- 每天日志归档路径以及格式 -->
            <fileNamePattern>${log.path}/web-info-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录info级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>info</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--level为 WARN 日志,时间滚动输出  -->
    <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/web_warn.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/web-warn-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录warn级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>warn</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>

    <!--level为 ERROR 日志,时间滚动输出  -->
    <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 正在记录的日志文档的路径及文档名 -->
        <file>${log.path}/web_error.log</file>
        <!--日志文档输出格式-->
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
            <charset>UTF-8</charset> <!-- 此处设置字符集 -->
        </encoder>
        <!-- 日志记录器的滚动策略,按日期,按大小记录 -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>${log.path}/web-error-%d{yyyy-MM-dd}.%i.log</fileNamePattern>
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
            <!--日志文档保留天数-->
            <maxHistory>15</maxHistory>
        </rollingPolicy>
        <!-- 此日志文档只记录ERROR级别的 -->
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
    </appender>
    <!--nacos 心跳 INFO 屏蔽-->
    <logger name="com.alibaba.nacos" level="OFF">
        <appender-ref ref="ERROR_FILE"/>
    </logger>
    <!--
        <logger>用来设置某一个包或者具体的某一个类的日志打印级别、
        以及指定<appender>。<logger>仅有一个name属性,
        一个可选的level和一个可选的addtivity属性。
        name:用来指定受此logger约束的某一个包或者具体的某一个类。
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
              还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。
              如果未设置此属性,那么当前logger将会继承上级的级别。
        addtivity:是否向上级logger传递打印信息。默认是true。
        <logger name="org.springframework.web" level="info"/>
        <logger name="org.springframework.scheduling.annotation.ScheduledAnnotationBeanPostProcessor" level="INFO"/>
    -->

    <!--
        使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话,有以下两种操作:
        第一种把<root level="info">改成<root level="DEBUG">这样就会打印sql,不过这样日志那边会出现很多其他消息
        第二种就是单独给dao下目录配置debug模式,代码如下,这样配置sql语句会打印,其他还是正常info级别:
        【logging.level.org.mybatis=debug logging.level.dao=debug】
     -->

    <!--
        root节点是必选节点,用来指定最基础的日志输出级别,只有一个level属性
        level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,
        不能设置为INHERITED或者同义词NULL。默认是DEBUG
        可以包含零个或多个元素,标识这个appender将会添加到这个logger。
    -->


    <!--开发环境:打印控制台-->
    <springProfile name="dev">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="WARN_FILE" />
            <appender-ref ref="ERROR_FILE" />
        </root>
    </springProfile>

    <springProfile name="prod">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="WARN_FILE" />
        </root>
    </springProfile>

    <springProfile name="test">
        <root level="info">
            <appender-ref ref="CONSOLE" />
            <appender-ref ref="DEBUG_FILE" />
            <appender-ref ref="INFO_FILE" />
            <appender-ref ref="ERROR_FILE" />
            <appender-ref ref="WARN_FILE" />
        </root>
    </springProfile>

</configuration>

使用mybatis的时候,sql语句是debug下才会打印,而这里我们只配置了info,所以想要查看sql语句的话

mybatis-plus:
  global-config:
    db-config:
      field-strategy: not_empty
      #驼峰下划线转换
      column-underline: true
      #逻辑删除配置
      logic-delete-value: 0
      logic-not-delete-value: 1
      db-type: mysql
    refresh: false
  configuration:
    map-underscore-to-camel-case: true
    cache-enabled: false
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志

此配置,mysql显示打印sql语句为

Preparing: SELECT id,task_id,url,title,name,content,type,channel_id,labels,original_time,created_time,submited_time,status,publish_time,reason,article_id,no FROM cl_news WHERE id=?

> Parameters: 1(Integer)
<
Columns: id, task_id, url, title, name, content, type, channel_id, labels, original_time, created_time, submited_time, status, publish_time, reason, article_id, no
<== Row: 1, 1, 1, 11, 11, <>, 11, 11, 11, 2021-07-21 12:28:51, 2021-07-21 12:28:57, 2021-07-21 12:29:07, null, null, null, null, null
<== Total: 1

此处若显示多个参数的话,拿到sql还得替换占位符,完全打印整个sql语句操作如下

重写com.baomidou.mybatisplus.core.MybatisParameterHandler类的setParameters 方法

package com.baomidou.mybatisplus.core;
/*
 * Copyright (c) 2011-2021, baomidou (jobob@qq.com).
 *
 * 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.
 */

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.baomidou.mybatisplus.core.toolkit.GlobalConfigUtils;
import com.baomidou.mybatisplus.core.toolkit.ReflectionKit;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import org.apache.ibatis.executor.ErrorContext;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.mapping.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.type.JdbcType;
import org.apache.ibatis.type.TypeException;
import org.apache.ibatis.type.TypeHandler;
import org.apache.ibatis.type.TypeHandlerRegistry;

import java.math.BigDecimal;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.*;

/**
 * 自定义 ParameterHandler 重装构造函数,填充插入方法主键 ID
 *
 * @author nieqiuqiu 2020/6/5
 * @since 3.4.0
 */
public class MybatisParameterHandler implements ParameterHandler {

	private final TypeHandlerRegistry typeHandlerRegistry;
	private final MappedStatement mappedStatement;
	private final Object parameterObject;
	private final BoundSql boundSql;
	private final Configuration configuration;
	private final SqlCommandType sqlCommandType;

	public MybatisParameterHandler(MappedStatement mappedStatement, Object parameter, BoundSql boundSql) {
		this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
		this.mappedStatement = mappedStatement;
		this.boundSql = boundSql;
		this.configuration = mappedStatement.getConfiguration();
		this.sqlCommandType = mappedStatement.getSqlCommandType();
		this.parameterObject = processParameter(parameter);
	}

	public Object processParameter(Object parameter) {
		/* 只处理插入或更新操作 */
		if (parameter != null
				&& (SqlCommandType.INSERT == this.sqlCommandType || SqlCommandType.UPDATE == this.sqlCommandType)) {
			//检查 parameterObject
			if (ReflectionKit.isPrimitiveOrWrapper(parameter.getClass())
					|| parameter.getClass() == String.class) {
				return parameter;
			}
			Collection<Object> parameters = getParameters(parameter);
			if (null != parameters) {
				// 感觉这里可以稍微优化一下,理论上都是同一个.
				parameters.forEach(this::process);
			} else {
				process(parameter);
			}
		}
		return parameter;
	}

	@Override
	public Object getParameterObject() {
		return this.parameterObject;
	}

	private void process(Object parameter) {
		if (parameter != null) {
			TableInfo tableInfo = null;
			Object entity = parameter;
			if (parameter instanceof Map) {
				Map<?, ?> map = (Map<?, ?>) parameter;
				if (map.containsKey(Constants.ENTITY)) {
					Object et = map.get(Constants.ENTITY);
					if (et != null) {
						entity = et;
						tableInfo = TableInfoHelper.getTableInfo(entity.getClass());
					}
				}
			} else {
				tableInfo = TableInfoHelper.getTableInfo(parameter.getClass());
			}
			if (tableInfo != null) {
				//到这里就应该转换到实体参数对象了,因为填充和ID处理都是争对实体对象处理的,不用传递原参数对象下去.
				MetaObject metaObject = this.configuration.newMetaObject(entity);
				if (SqlCommandType.INSERT == this.sqlCommandType) {
					populateKeys(tableInfo, metaObject, entity);
					insertFill(metaObject, tableInfo);
				} else {
					updateFill(metaObject, tableInfo);
				}
			}
		}
	}


	protected void populateKeys(TableInfo tableInfo, MetaObject metaObject, Object entity) {
		final IdType idType = tableInfo.getIdType();
		final String keyProperty = tableInfo.getKeyProperty();
		if (StringUtils.isNotBlank(keyProperty) && null != idType && idType.getKey() >= 3) {
			final IdentifierGenerator identifierGenerator = GlobalConfigUtils.getGlobalConfig(this.configuration).getIdentifierGenerator();
			Object idValue = metaObject.getValue(keyProperty);
			if (StringUtils.checkValNull(idValue)) {
				if (idType.getKey() == IdType.ASSIGN_ID.getKey()) {
					if (Number.class.isAssignableFrom(tableInfo.getKeyType())) {
						metaObject.setValue(keyProperty, identifierGenerator.nextId(entity));
					} else {
						metaObject.setValue(keyProperty, identifierGenerator.nextId(entity).toString());
					}
				} else if (idType.getKey() == IdType.ASSIGN_UUID.getKey()) {
					metaObject.setValue(keyProperty, identifierGenerator.nextUUID(entity));
				}
			}
		}
	}


	protected void insertFill(MetaObject metaObject, TableInfo tableInfo) {
		GlobalConfigUtils.getMetaObjectHandler(this.configuration).ifPresent(metaObjectHandler -> {
			if (metaObjectHandler.openInsertFill() && tableInfo.isWithInsertFill()) {
				metaObjectHandler.insertFill(metaObject);
			}
		});
	}

	protected void updateFill(MetaObject metaObject, TableInfo tableInfo) {
		GlobalConfigUtils.getMetaObjectHandler(this.configuration).ifPresent(metaObjectHandler -> {
			if (metaObjectHandler.openUpdateFill() && tableInfo.isWithUpdateFill()) {
				metaObjectHandler.updateFill(metaObject);
			}
		});
	}

	/**
	 * 处理正常批量插入逻辑
	 * <p>
	 * org.apache.ibatis.session.defaults.DefaultSqlSession$StrictMap 该类方法
	 * wrapCollection 实现 StrictMap 封装逻辑
	 * </p>
	 *
	 * @return 集合参数
	 */
	@SuppressWarnings({"rawtypes", "unchecked"})
	protected Collection<Object> getParameters(Object parameterObject) {
		Collection<Object> parameters = null;
		if (parameterObject instanceof Collection) {
			parameters = (Collection) parameterObject;
		} else if (parameterObject instanceof Map) {
			Map parameterMap = (Map) parameterObject;
			if (parameterMap.containsKey("collection")) {
				parameters = (Collection) parameterMap.get("collection");
			} else if (parameterMap.containsKey("list")) {
				parameters = (List) parameterMap.get("list");
			} else if (parameterMap.containsKey("array")) {
				parameters = Arrays.asList((Object[]) parameterMap.get("array"));
			}
		}
		return parameters;
	}

	@Override
	@SuppressWarnings("unchecked")
	public void setParameters(PreparedStatement ps) {
		ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());
		List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
		if (parameterMappings != null) {
			String sql = boundSql.getSql();
			List<Object> parameters = new ArrayList<>();
			for (int i = 0; i < parameterMappings.size(); i++) {
				ParameterMapping parameterMapping = parameterMappings.get(i);
				if (parameterMapping.getMode() != ParameterMode.OUT) {
					Object value;
					String propertyName = parameterMapping.getProperty();
					if (this.boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
						value = this.boundSql.getAdditionalParameter(propertyName);
					} else if (this.parameterObject == null) {
						value = null;
					} else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
						value = parameterObject;
					} else {
						MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
						value = metaObject.getValue(propertyName);
					}
					TypeHandler typeHandler = parameterMapping.getTypeHandler();
					JdbcType jdbcType = parameterMapping.getJdbcType();
					if (value == null && jdbcType == null) {
						jdbcType = this.configuration.getJdbcTypeForNull();
					}
					try {
						typeHandler.setParameter(ps, i + 1, value, jdbcType);
						parameters.add(value);
					} catch (TypeException | SQLException e) {
						throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
					}


				}
			}


			try {
				sql = handleListParameter(sql, parameters);
				System.out.println("输出完整的sql-------------------->>>" + sql);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
	}


	/**
	 * 是否基本数据类型或者基本数据类型的包装类
	 */
	private boolean isPrimitiveOrPrimitiveWrapper(Class<?> parameterObjectClass) {
		return parameterObjectClass.isPrimitive() ||
				(parameterObjectClass.isAssignableFrom(BigDecimal.class) || parameterObjectClass.isAssignableFrom(Byte.class) || parameterObjectClass.isAssignableFrom(Short.class) ||
						parameterObjectClass.isAssignableFrom(Integer.class) || parameterObjectClass.isAssignableFrom(Long.class) ||
						parameterObjectClass.isAssignableFrom(Double.class) || parameterObjectClass.isAssignableFrom(Float.class) ||
						parameterObjectClass.isAssignableFrom(Character.class) || parameterObjectClass.isAssignableFrom(Boolean.class));
	}

	/**
	 * 参数转换拼接替换
	 * @param sql
	 * @param col
	 * @return
	 */
	private String handleListParameter(String sql, Collection<?> col) {
		if (col != null && col.size() != 0) {
			for (Object obj : col) {
				String value = null;
				Class<?> objClass = obj.getClass();

				// 类型匹配输出
				if (isPrimitiveOrPrimitiveWrapper(objClass)) {
					value = obj.toString();
				} else if (objClass.isAssignableFrom(String.class)) {
					value = "\'" + obj.toString() + "\'";
				} else if (objClass.isAssignableFrom(Date.class)) {
					try {
						value = cn.hutool.core.date.DateUtil.format((Date) obj, "yyyy-MM-dd HH:mm:ss");
						value = "to_date('" + value + "','yyyy-mm-dd hh24:mi:ss')";
					} catch (Exception e) {
						e.printStackTrace();
						value = "\'" + obj.toString() + "\'";

					}
				} else {
					//暂定吧
					value = "\'" + obj.toString() + "\'";
				}

				sql = sql.replaceFirst("\\?", value);

			}

		}

		return sql;
	}

}



  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值