日常开发填坑

一、logback填坑,log4j2填坑:

1.logback填坑

bootstrap.yml(bootstrap.properties)先加载,用于应用程序上下文的引导阶段。
application.yml(application.properties)后加载,由父Spring ApplicationContext加载。
bootstrap.yml 是系统级别的一些参数配置,这些参数一般是不变的。
application.yml 一般用来定义单个应用级别的,如果搭配 spring-cloud-config 使用 application.yml 里面定义的文件可以实现动态替换。

由于将指定logback配置文件地址的配置项(logging.config=classpath:logback-custom.xml)写在了bootstrap.yml中,log_base_dir配置项位于配置中心,bootstrap.yml会先加载,将读取不到log_base_dir从而logback会自动建一个名为log_base_dir_IS_UNDEFINED的文件夹
logback-custom.xml:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
    <contextName>logback-custom</contextName>
    <!--该配置项位于配置中心,若该配置文件先加载,将读取不到log_base_dir从而logback会自动建一个名为log_base_dir_IS_UNDEFINED的文件夹-->
    <springProperty scope="context" name="log_base_dir" source="my.log_base_dir"/>
    <springProperty scope="context" name="log_app_dir" source="spring.application.name"/>
    <!--输出到控制台-->
    <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%p][%c][%M][%L]-> %m%n</pattern>
            <charset class="java.nio.charset.Charset">UTF-8</charset>
        </encoder>
    </appender>
    <appender name="rollingfile_other" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log_base_dir:-/my_log}/%d{yyyy-MM-dd}/${log_app_dir}/other_%i.log
            </fileNamePattern>
            <maxHistory>30</maxHistory>
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>DENY</onMatch>
            <onMismatch>ACCEPT</onMismatch>
        </filter>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%p][%c][%M][%L]-> %m%n</pattern>
        </layout>
    </appender>
    <appender name="rollingfile_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log_base_dir:-/my_log}/%d{yyyy-MM-dd}/${log_app_dir}/error_%i.log
            </fileNamePattern>
            <maxHistory>30</maxHistory>
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>ERROR</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%p][%c][%M][%L]-> %m%n</pattern>
        </layout>
    </appender>
    <appender name="rollingfile_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <fileNamePattern>${log_base_dir:-/my_log}/%d{yyyy-MM-dd}/${log_app_dir}/operation_%i.log
            </fileNamePattern>
            <maxHistory>30</maxHistory>
            <maxFileSize>100MB</maxFileSize>
        </rollingPolicy>
        <filter class="ch.qos.logback.classic.filter.LevelFilter">
            <level>INFO</level>
            <onMatch>ACCEPT</onMatch>
            <onMismatch>DENY</onMismatch>
        </filter>
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss} [%p][%c]-> %m%n</pattern>
        </layout>
    </appender>

    <root level="Info">
        <appender-ref ref="console" />
        <appender-ref ref="rollingfile_error" />
        <appender-ref ref="rollingfile_other" />
        <appender-ref ref="rollingfile_info" />
    </root>
</configuration>

解决方案:
将logging.config=classpath:logback-custom.xml放于配置中心的该应用的配置下即可。
附上:
1️⃣外部配置加载
Spring Boot 支持多种外部配置方式,如下所示,从上往下加载优先级由高到低,内容相同时覆盖,不相同时累加。
命令行参数
来自java:comp/env的JNDI属性
使用“spring.config.location”改变默认的配置文件位置
Java系统属性(System.getProperties())
操作系统环境变量
RandomValuePropertySource配置的random.*属性值
jar包外部的application-{profile}.properties或application.yml(带spring.profile)配置文件
jar包内部的application-{profile}.properties或application.yml(带spring.profile)配置文件
jar包外部的application.properties或application.yml(不带spring.profile)配置文件
jar包内部的application.properties或application.yml(不带spring.profile)配置文件
@Configuration注解类上的@PropertySource
通过SpringApplication.setDefaultProperties指定的默认属性
官方文档:文档

2️⃣logback.xml加载早于application.yml,用这种方式:logging.config=classpath:logback-custom.xml 会延迟加载logback的配置文件

2.log4j2填坑

log4j2想实现的也是能够读取配置中心的配置项-日志输出路径
但是,log4j2.xml不像logback似乎没有办法获取配置中心的配置;

解决方案:参考RollingFileAppender,写一个自定义的日志输出类
因为该类加载时,spring容器尚未注入bean,因此通过rest请求直接向配置中心获取配置。

@Plugin(
    name = "CustomRollingFile",//自定义标签名<CustomRollingFile></CustomRollingFile>
    category = "Core",
    elementType = "appender",
    printObject = true
)
public final class CustomRollingFileAppender extends AbstractOutputStreamAppender<RollingFileManager> {
    public static final String PLUGIN_NAME = "CustomRollingFile";
    private static final int DEFAULT_BUFFER_SIZE = 8192;
    //配置中心请求路径
    private static final String CONFIG_REQUEST_URL = "http://localhost:7010/application-pro.yml";
    //日志输出地址基地址
    private static String log_base_dir;
    private static RestTemplate restTemplate = new RestTemplate ();
    private final String fileName;
    private final String filePattern;
    private Object advertisement;
    private final Advertiser advertiser;

    private CustomRollingFileAppender(String name, Layout<? extends Serializable> layout, Filter filter, RollingFileManager manager, String fileName, String filePattern, boolean ignoreExceptions, boolean immediateFlush, Advertiser advertiser) {
        super(name, layout, filter, ignoreExceptions, immediateFlush, manager);
        if (advertiser != null) {
            Map<String, String> configuration = new HashMap(layout.getContentFormat());
            configuration.put("contentType", layout.getContentType());
            configuration.put("name", name);
            this.advertisement = advertiser.advertise(configuration);
        }
        this.fileName = fileName;
        this.filePattern = filePattern;
        this.advertiser = advertiser;
    }

    public boolean stop(long timeout, TimeUnit timeUnit) {
        this.setStopping();
        boolean stopped = super.stop(timeout, timeUnit, false);
        if (this.advertiser != null) {
            this.advertiser.unadvertise(this.advertisement);
        }

        this.setStopped();
        return stopped;
    }

    public void append(LogEvent event) {
        ((RollingFileManager)this.getManager()).checkRollover(event);
        super.append(event);
    }

    public String getFileName() {
        return this.fileName;
    }

    public String getFilePattern() {
        return this.filePattern;
    }

    public <T extends TriggeringPolicy> T getTriggeringPolicy() {
        return ((RollingFileManager)this.getManager()).getTriggeringPolicy();
    }

    @PluginBuilderFactory
    public static <B extends CustomRollingFileAppender.Builder<B>> B newBuilder() {
        return (B) (new Builder()).asBuilder();
    }

    public static class Builder<B extends CustomRollingFileAppender.Builder<B>> extends org.apache.logging.log4j.core.appender.AbstractOutputStreamAppender.Builder<B> implements org.apache.logging.log4j.core.util.Builder<CustomRollingFileAppender> {
        @PluginBuilderAttribute
        private String fileName;
        @PluginBuilderAttribute
        @Required
        private String filePattern;
        @PluginBuilderAttribute
        private boolean append = true;
        @PluginBuilderAttribute
        private boolean locking;
        @PluginElement("Policy")
        @Required
        private TriggeringPolicy policy;
        @PluginElement("Strategy")
        private RolloverStrategy strategy;
        @PluginBuilderAttribute
        private boolean advertise;
        @PluginBuilderAttribute
        private String advertiseUri;
        @PluginBuilderAttribute
        private boolean createOnDemand;
        @PluginBuilderAttribute
        private String filePermissions;
        @PluginBuilderAttribute
        private String fileOwner;
        @PluginBuilderAttribute
        private String fileGroup;

        public Builder() {
        }

        public CustomRollingFileAppender build() {
            try{
                Yaml yaml = new Yaml ();
                String urlStr = restTemplate.getForEntity (CONFIG_REQUEST_URL, String.class, new HashMap<> ()).getBody ();
                log_base_dir = ((Map<String,String>)((Map)yaml.load (urlStr)).get ("idm")).get ("log_base_dir");
            }catch (Exception e){
                log_base_dir = "/idm_log";
            }
            SimpleDateFormat format = new SimpleDateFormat ("yyyy-MM-dd");
            //修改的生成的文件名
            this.fileName = log_base_dir + "/" + format.format (new Date ()) + fileName;
            //修改追加生成的文件名
            this.filePattern = log_base_dir + filePattern;
           
            boolean isBufferedIo = this.isBufferedIo();
            int bufferSize = this.getBufferSize();
            if (this.getName() == null) {
                CustomRollingFileAppender.LOGGER.error("CustomRollingFileAppender '{}': No name provided.", this.getName());
                return null;
            } else {
                if (!isBufferedIo && bufferSize > 0) {
                    CustomRollingFileAppender.LOGGER.warn("CustomRollingFileAppender '{}': The bufferSize is set to {} but bufferedIO is not true", this.getName(), bufferSize);
                }

                if (this.filePattern == null) {
                    CustomRollingFileAppender.LOGGER.error("CustomRollingFileAppender '{}': No file name pattern provided.", this.getName());
                    return null;
                } else if (this.policy == null) {
                    CustomRollingFileAppender.LOGGER.error("CustomRollingFileAppender '{}': No TriggeringPolicy provided.", this.getName());
                    return null;
                } else {
                    if (this.strategy == null) {
                        if (this.fileName != null) {
                            this.strategy = DefaultRolloverStrategy.newBuilder().withCompressionLevelStr(String.valueOf(-1)).withConfig(this.getConfiguration()).build();
                        } else {
                            this.strategy = DirectWriteRolloverStrategy.newBuilder().withCompressionLevelStr(String.valueOf(-1)).withConfig(this.getConfiguration()).build();
                        }
                    } else if (this.fileName == null && !(this.strategy instanceof DirectFileRolloverStrategy)) {
                        CustomRollingFileAppender.LOGGER.error("CustomRollingFileAppender '{}': When no file name is provided a DirectFilenameRolloverStrategy must be configured");
                        return null;
                    }

                    Layout<? extends Serializable> layout = this.getOrCreateLayout();
                    RollingFileManager manager = RollingFileManager.getFileManager(this.fileName, this.filePattern, this.append, isBufferedIo, this.policy, this.strategy, this.advertiseUri, layout, bufferSize, this.isImmediateFlush(), this.createOnDemand, this.filePermissions, this.fileOwner, this.fileGroup, this.getConfiguration());
                    if (manager == null) {
                        return null;
                    } else {
                        manager.initialize();
                        return new CustomRollingFileAppender(this.getName(), layout, this.getFilter(), manager, this.fileName, this.filePattern, this.isIgnoreExceptions(), this.isImmediateFlush(), this.advertise ? this.getConfiguration().getAdvertiser() : null);
                    }
                }
            }
        }

        public String getAdvertiseUri() {
            return this.advertiseUri;
        }

        public String getFileName() {
            return this.fileName;
        }

        public boolean isAdvertise() {
            return this.advertise;
        }

        public boolean isAppend() {
            return this.append;
        }

        public boolean isCreateOnDemand() {
            return this.createOnDemand;
        }

        public boolean isLocking() {
            return this.locking;
        }

        public String getFilePermissions() {
            return this.filePermissions;
        }

        public String getFileOwner() {
            return this.fileOwner;
        }

        public String getFileGroup() {
            return this.fileGroup;
        }

        public B withAdvertise(boolean advertise) {
            this.advertise = advertise;
            return this.asBuilder();
        }

        public B withAdvertiseUri(String advertiseUri) {
            this.advertiseUri = advertiseUri;
            return this.asBuilder();
        }

        public B withAppend(boolean append) {
            this.append = append;
            return this.asBuilder();
        }

        public B withFileName(String fileName) {
            this.fileName = fileName;
            return this.asBuilder();
        }

        public B withCreateOnDemand(boolean createOnDemand) {
            this.createOnDemand = createOnDemand;
            return this.asBuilder();
        }

        public B withLocking(boolean locking) {
            this.locking = locking;
            return this.asBuilder();
        }

        public String getFilePattern() {
            return this.filePattern;
        }

        public TriggeringPolicy getPolicy() {
            return this.policy;
        }

        public RolloverStrategy getStrategy() {
            return this.strategy;
        }

        public B withFilePattern(String filePattern) {
            this.filePattern = filePattern;
            return this.asBuilder();
        }

        public B withPolicy(TriggeringPolicy policy) {
            this.policy = policy;
            return this.asBuilder();
        }

        public B withStrategy(RolloverStrategy strategy) {
            this.strategy = strategy;
            return this.asBuilder();
        }

        public B withFilePermissions(String filePermissions) {
            this.filePermissions = filePermissions;
            return this.asBuilder();
        }

        public B withFileOwner(String fileOwner) {
            this.fileOwner = fileOwner;
            return this.asBuilder();
        }

        public B withFileGroup(String fileGroup) {
            this.fileGroup = fileGroup;
            return this.asBuilder();
        }
    }
}

二、设置jpa.hibernate.ddl-auto: update启动服务器自动建表报错

More than one table found in namespace (, ) - SchemaExtractionException

因为在同一个数据源下存在多个相同表结构的schema。

解决办法:指定schema
jpa:
properties:
hibernate:
default_schema: IDM

jsonView填坑:
当一个对象有子对象时,该怎么控制其子对象的输出?
解决方法

public class UserInfoDto {
    public interface SimpleView{}
    @JsonView(SimpleView.class)
    private String id;

    /**
     * 姓名
     */
    @JsonView(SimpleView.class)
    private String name;
    /**
     * 账号信息
     */
    @JsonView(SimpleView.class)
    private AccountDto account;
    /**getter and setter**/
}
public class AccountDto {
    @JsonView(UserInfoDto.SimpleView.class)
    private String id;
    /**
     * 账号名
     */
    @JsonView(UserInfoDto.SimpleView.class)
    private String name;
    /**
     * 密码
     */
    private String password;
    /**getter and setter**/
}

三、因为Date,DateTime类型没有时区数据,所以决定用LocalDate

springboot jdk8 LocalDate LocalDateTime jpa 映射字段是tinyblob 解决办法
hibernate版本低于5.1.2会这样,加依赖compile ‘org.hibernate:hibernate-java8:5.1.2.Final’
或者用转换器

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.sql.Timestamp;
import java.time.LocalDateTime;

@Converter(autoApply = true)
public class LocalDateTimeAttributeConverter implements AttributeConverter<LocalDateTime, Timestamp> {
    
    @Override
    public Timestamp convertToDatabaseColumn(LocalDateTime locDateTime) {
        return (locDateTime == null ? null : Timestamp.valueOf(locDateTime));
    }

    @Override
    public LocalDateTime convertToEntityAttribute(Timestamp sqlTimestamp) {
        return (sqlTimestamp == null ? null : sqlTimestamp.toLocalDateTime());
    }
}

@Convert(converter = LocalDateTimeAttributeConverter.class)
private LocalDateTime verificationDate;

错误记录:有多个LocalDateTime字段,我只讲数据库中的一个字段重置了类型,因此一直报PGSQL转换日期类型错误。。。

LocalDateTime反序列化失败
解决办法:加注解
@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime verificationDate;

Swagger自动生成代码工具会把实体的LocalDateTime类型换成org.threeten.bp.OffsetDateTime,若不对LocalDatetime类型做格式化处理,则会报日期类型转换的相关错误;
解决方法:在属性上加上日期格式化注解
@JsonFormat(pattern=“yyyy-MM-dd’T’HH:mm:ss’Z’”)

四、jpa 分页查询 踩坑

0,1页码 index是从0开始的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Funnee

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值