Springboot应用、多配置文件、日志、mybatis、邮件、缓存、动态多数据源切换、异常处理

多配置文件:

不同环境需要用到不同的配置文件: 比如dev .pro .local
格式:application-{profile}.properties/yml:
• application-dev.properties、application-prod.properties
2、多profile文档块模式:
3、激活方式:
– 命令行 --spring.profiles.active=dev
– 配置文件 spring.profiles.active=dev
– jvm参数 –Dspring.profiles.active=dev
一般开发直接配置在tomcat的环境变量里就可以,然后通过占位符获取

SpringBoot读取配置文件的顺序:

1、项目jar包同级下的config文件夹是优先级最高的,是在执行命令的目录下建config文件夹。执行命令需要在jar包目录下才行
2、项目jar包同级下直接放properties文件是次优先级,是直接把配置文件放到jar包的同级目录。
3、项目内部的classpath同级config文件夹是第三优先级,在classpath下建一个config文件夹,然后把配置文件放进去。
4、项目内部的classpath同级放properties文件是最低优先级,是在classpath下直接放配置文件。

日志:

SpringBoot默认帮我们配置好了日志;
直接创建即可

@SpringBootTest
class DemoApplicationTests {
	Logger logger = LoggerFactory.getLogger(Controllerhello.class);
	@Test
	void contextLoads() {
		logger.info("kkkkkkkkkkkk");
	}

}

可以修改日志模式;

logging.level.com.springboottest.demo.DemoApplicationTests=info


日志输出格式: 
%d表示日期时间,
%thread表示线程名, 
%5level:级别从左显示5个字符宽度 
%logger{50} 表示logger名字最长50个字符,否则按照句点分割。
%msg:日志消息, 
%n是换行符 ‐‐>
logging.pattern.console=%d{yyyy-MM-dd} [%thread] %-5level %logger{50} - %msg%n

日志的配置文件springboot其实默认配好了,如果想要自己的配置文件,直接在resources下面添加即可:logback-spring.xml,最好带spring。这样可以支持
既可以配置在不同环境下用不通过格式

<?xml version="1.0" encoding="UTF-8"?>
<!--
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
-->
<configuration scan="false" scanPeriod="60 seconds" debug="false">
    <!-- 定义日志的根目录 -->
    <property name="LOG_HOME" value="/app/log" />
    <!-- 定义日志文件名称 -->
    <property name="appName" value="demo-springboot"></property>
    <!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
    <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
        <!--
        日志输出格式:
			%d表示日期时间,
			%thread表示线程名,
			%-5level:级别从左显示5个字符宽度
			%logger{50} 表示logger名字最长50个字符,否则按照句点分割。 
			%msg:日志消息,
			%n是换行符
        -->
        <layout class="ch.qos.logback.classic.PatternLayout">
            <springProfile name="dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} ----> [%thread] ---> %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
            <springProfile name="!dev">
                <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} =+++=== [%thread] ==== %-5level %logger{50} - %msg%n</pattern>
            </springProfile>
        </layout>
    </appender>

    <!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->  
    <appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <!-- 指定日志文件的名称 -->
        <file>${LOG_HOME}/${appName}.log</file>
        <!--
        当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
        TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
        -->
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--
            滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动 
            %i:当文件大小超过maxFileSize时,按照i进行文件滚动
            -->
            <fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
            <!-- 
            可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
            且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
            那些为了归档而创建的目录也会被删除。
            -->
            <MaxHistory>365</MaxHistory>
            <!-- 
            当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
            -->
            <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>100MB</maxFileSize>
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <!-- 日志输出格式: -->     
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [ %thread ] - [ %-5level ] [ %logger{50} : %line ] - %msg%n</pattern>
        </layout>
    </appender>

    <!-- 
		logger主要用于存放日志对象,也可以定义日志类型、级别
		name:表示匹配的logger类型前缀,也就是包的前半部分
		level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
		additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
		false:表示只用当前logger的appender-ref,true:
		表示当前logger的appender-ref和rootLogger的appender-ref都有效
    -->
    <!-- hibernate logger -->
    <logger name="com.springboottest" level="debug" />
    <!-- Spring framework logger -->
    <logger name="org.springframework" level="debug" additivity="false"></logger>



    <!-- 
    root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
    要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。 
    -->
    <root level="info">
        <appender-ref ref="stdout" />
        <appender-ref ref="appLogAppender" />
    </root>
</configuration> 

也可以切换日志框架,改下pom文件

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <exclusions>
                <exclusion>
                    <artifactId>spring-boot-starter-logging</artifactId>
                    <groupId>org.springframework.boot</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-log4j2</artifactId>
        </dependency>

同样log4j2也被默认配置了,同样可以添加自己的logj2-spring.xml配置文件

整合Mybatis

引入依赖,配置好数据源,配置文件可以直接配置mybatis的一些属性,比如驼峰啊,别名扫描,mapper扫描

mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.kk.domain
mybatis.configuration.map-underscore-to-camel-case=true

然后直接就可以用了,写好相应的mapper, 对应的mapper.xml即可

<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.0</version>
		</dependency>

邮件功能

引入依赖

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-mail</artifactId>
        </dependency>

看下自动配置包的有关mail的
在这里插入图片描述
mail的配置前缀 spring.mail 例如spring.mail.host;spring.mail.properties.mail.smtp.ssl.enable

	@Test
	void sendMail() throws MessagingException {
		//简单邮件
		SimpleMailMessage mailMessage = new SimpleMailMessage();
		mailMessage.setSubject("K");
		mailMessage.setText("kkkkkk");
		mailMessage.setTo("2315644@qq.com");
		mailMessage.setFrom("afasfa4@qq.com");
		javaMailSender.send(mailMessage);
		//复杂邮件
		MimeMessage mimeMessage = javaMailSender.createMimeMessage();
		MimeMessageHelper messageHelper = new MimeMessageHelper(mimeMessage,true);
		messageHelper.setText("<b>KKKKK</b>",true);
		messageHelper.setSubject("K");
		messageHelper.addAttachment("kk.jpg",new File("D://hh/kk.jpg"));
		messageHelper.setTo("2315644@qq.com");
		messageHelper.setFrom("afasfa4@qq.com");
		javaMailSender.send(mimeMessage);
	}

使用redis作为缓存

引入依赖,添加配置即可使用,domain记得序列化
application.properties配置redis
spring.redis.host=
@EnableCaching

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

Springboot多数据源

使用的是spring自带的抽象类AbstractRoutingDataSource
先写个DataSourceObserver

/**
 * 动态数据源上下文,保证每个线程都可以独立改变
 */
public class DataSourceObserver{
    private static final ThreadLocal<String> local = new ThreadLocal<>();
    public static void setDataSourceName(String name){
        local.set(name);
    }
    public static String getDataSourceName(){
        return local.get();
    }
    public static void clearDataSourceName(){
        local.remove();
    }
}

然后写个DynamicDataSource 继续AbstractRoutingDataSource

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceObserver.getDataSourceName();
    }
}

为什么重写这个方法,从AbstractRoutingDataSource源码里可以看到determineCurrentLookupKey这个方法是获取你传入的数据源的key,即你传入redshift,你就可以得到redshift的连接池;

@Override
	public Connection getConnection() throws SQLException {
		return determineTargetDataSource().getConnection();
	}
	
    protected DataSource determineTargetDataSource() {
		Assert.notNull(this.resolvedDataSources, "DataSource router not initialized");
		Object lookupKey = determineCurrentLookupKey();
		DataSource dataSource = this.resolvedDataSources.get(lookupKey);
		if (dataSource == null && (this.lenientFallback || lookupKey == null)) {
			dataSource = this.resolvedDefaultDataSource;
		}
		if (dataSource == null) {
			throw new IllegalStateException("Cannot determine target DataSource for lookup key [" + lookupKey + "]");
		}
		return dataSource;
	}

然后配置下数据源和配置类

@Configuration
public class DataSourceConfig{
    @Bean(name="maria")
    @ConfigurationProperties(prefix = "spring.datasource.maria")
    public DataSource mariaDBDataSource() {
        return new HikariDataSource();
    }

    @Bean(name = "redshift")
    @ConfigurationProperties(prefix = "spring.datasource.redshift")
    public DataSource redshiftDataSource() {
        return new HikariDataSource();
    }

    @Bean(name = "vertica")
    @ConfigurationProperties(prefix = "spring.datasource.vertica")
    public DataSource verticaDataSource(){
        return new HikariDataSource();
    }

    @Bean(name = "dynamic")
    public DataSource dynamicDataSource(@Qualifier("redshift") DataSource redshift,
                                        @Qualifier("maria") DataSource maria,
                                        @Qualifier("vertica") DataSource vertica
                                        ){
        DynamicDataSource dynamicDataSource = new DynamicDataSource();

        Map<Object, Object> resolvedDataSources = new HashMap<>();
        resolvedDataSources.put(ProgramConstant.REDSHIFT,redshift);
        resolvedDataSources.put(ProgramConstant.MARIA,maria);
        resolvedDataSources.put(ProgramConstant.VERTICA,vertica);
        //设置所有的数据源
        dynamicDataSource.setTargetDataSources(resolvedDataSources);
        //设置默认的数据源
        dynamicDataSource.setDefaultTargetDataSource(maria);
        return dynamicDataSource;
    }

    @Bean(name = "template")
    public JdbcTemplate template(@Qualifier("dynamic") DataSource dynamicDatasource) {
        return new JdbcTemplate(dynamicDatasource);
    }

    @Bean(name = "namedTemplate")
    public NamedParameterJdbcTemplate namedTemplate(@Qualifier("dynamic") DataSource dynamicDatasource) {
        return new NamedParameterJdbcTemplate(dynamicDatasource);
    }
}

这个时候就可以通过 DataSourceObserver.setDataSourceName(“redshift”)实现动态切换了;

可以通过aop对每个方法进行自动切换,可以搭配个注解

@Target(ElementType.METHOD)
@Retention(RUNTIME)
@Documented
public @interface SelectDatasoure {
    String value() default "maria";
}

写好注解就可以在service层使用了

    @SelectDatasoure(value = "redshift")
    public List<User> findUser(){
        return null;
    }

    @SelectDatasoure(value = "maria")
    public List<User> findUse2r(){
        return null;
    }

运用AOP拦截注解为SelectDatasoure的方法

@Aspect
@Component
@Order(-1)//保证在事务之前执行
public class DynamicDataSourceAspect {
//sd 表示的是我们要拦截的注解,其他的不会拦截
    @Before("@annotation(sd)")
    public void changeDataSource(JoinPoint point, SelectDatasoure  sd) throws Throwable {
        String dsId = ds.value();
        DataSourceObserver.setDataSourceName(dsId);
    }

    @After("@annotation(sd)")
    public void restoreDataSource(JoinPoint point, SelectDatasoure  sd) {
        DataSourceObserver.clearDataSourceName();
    }
}

到这里动态切换就完成了;

异常处理

创建一个全局异常处理类即可,注意注解@ControllerAdvice
常用于:
全局异常处理
全局数据绑定
全局数据预处理

@ControllerAdvice
public class MyExceptionHandler {

    //指定出现什么异常执行这个方法
    @ExceptionHandler(Exception.class)
    @ResponseBody //为了返回数据
    public String error(Exception e) {
        e.printStackTrace();
        return"执行了全局异常处理..";
    }
}

你可以指定异常处理,例在@ExceptionHandler(ArithmeticException.class)里写入即可

同样你可以自定义异常,写个异常类继承RuntimeException,在try{}catch(Excepetion e){ throw new 自定义异常类 }中 throw即可

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值