跟着大宇学SpringBoot

第一节 SpringBoot项目基础搭建

spring.profiles.active 可以用于项目启动加载哪个分支的application-${env}.yaml

server:
  servlet:
    #项目根目录
    context-path: /study/springboot
spring:
  #激活的分支
  profiles:
    active: dev

第二节 SpringBoot使用日志

'%d{HH:mm:ss.SSS} %-5level %logger{36} [%line] - %msg%n'
image.png

第三节 SpringBoot参数校验

import lombok.Data;
import org.hibernate.validator.constraints.Length;
 
import javax.validation.constraints.*;
 
@Data
public class Phone {
 
    @NotNull(message = "电话号码不能为空")
    private Long number;
 
 
    @Max(value = 5000, message = "预算价格不能超过{value}元")
    @Min(value = 1000, message = "预算价格不能低于{value}元")
    private double price;
 
    @NotBlank(message = "品牌不能为空")
    @Length(max = 5, message = "品牌长度不能超过{max}")
    private String brand;
}

GET请求方法,它没有使用BindingResult参数来接收校验结果。如果参数里面的dicTypeId为null,那么就会抛出异常BindingException。

    @GetMapping("/dic/list")
    public MultiResponse getDicList(@Valid DicListQry dicListQry) {
        return null;
    }

如果我再把Get请求转成Post请求,dicTypeId的值还是传null。那么抛出的异常不一样,抛出 MethodArgumentNotValidException。

    @PostMapping("/dic/list")
    public MultiResponse getDicListPost(@RequestBody 
                                                   @Valid DicListQry dicList) {
        return null;
    }

还有一种情况就是校验集合。为了支持校验集合的方式,不能够直接使用List来接收,不然不会走校验框架。为了校验集合,需要按照下面方式。把接收的List做成一个类的成员变量,然后在List上添加@Valid注解。 请求的时候,需要配合使用@Validated注解。

    @PostMapping("/dic/list")
    public MultiResponse 
                         getDicListPost(@RequestBody @Validated DicList dicList) {
        return dictionaryService.getDicList(null);
    }
 
 
    @Data
    private static class DicList {
 
        @Valid
        private List dicListQry;
    }

第五节 SpringBoot统一全局响应

使用ResponseControllerAdvice注解,并且实现ResponseBodyAdvice接口

package com.zhoutianyu.learnspringboot.response;
 
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
 
@RestControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
 
    @Override
    public boolean supports(MethodParameter methodParameter, 
                            Class aClass) {
        return true;
    }
 
    @Override
    public Object beforeBodyWrite(Object data, MethodParameter methodParameter,
                                  MediaType mediaType, Class aClass,
                                  ServerHttpRequest serverHttpRequest, 
                                  ServerHttpResponse serverHttpResponse) {
 
        if (isResponseType(data)) {
            return data;
        }
 
        return new BaseResponse<>(StatusCodeEnum.SUCCESS, data);
    }
 
    private boolean isResponseType(Object data) {
        return data instanceof BaseResponse;
    }
}

第七节 SpringBoot自定义参数

application.yaml文件配置如下

#自定义参数
define:
  userinfo:
    username: zhoutianyu
    age: 24
    position: java engineer
  department:
    name: 研发部门
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
 
@Component
@Data
public class Department {
 
    @Value("${define.department.name}")
    private String name;
}
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
 
@ConfigurationProperties(prefix = "define.userinfo")
@Component
@Data
public class UserInfo {
 
    private String username;
 
    private int age;
 
    private String position;
}

第十二节 SprnigBoot使用定时任务

    
        org.springframework.boot
        spring-boot-starter
    
每隔30秒执行一次:*/30 * * * * ?    开发人员自测
每隔10分钟执行一次:0 */10 * * * ?   给测试小姐姐用
每月1号凌晨1点执行一次:0 0 1 1 * ?  每月推送一次月报
每天凌晨5点执行一次:0 0 5 * * ?     生产上使用
#自定义参数
define:
  quartz:
    cron: "*/6 * * * * ?"
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
 
@Component
@EnableScheduling
public class BaseQuartZ {
 
    @Scheduled(cron = "${define.quartz.cron}")
    public void schedule() {
        System.out.println(Thread.currentThread().hashCode());
    }
 
}

所有的定时任务都是同一个线程在跑。
构造一个线程池,然后使用@EnableAsync注解开启异步。在每个定时任务的方法上,增加@Async注解即可。

@Component
public class ThreadPoolConfig {
 
    @Bean(value = "threadPoolTaskExecutor")
    public Executor getExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //线程池维护线程的最少数量,即使没有任务需要执行,也会一直存活
        executor.setCorePoolSize(5);
        //线程池维护线程的最大数量
        executor.setMaxPoolSize(10);
        //允许的空闲时间,当线程空闲时间达到keepAliveTime时,线程会退出,直到线程数量=corePoolSize
        executor.setKeepAliveSeconds(60);
       //配置线程池中的线程的名称前缀
        executor.setThreadNamePrefix("demo.tyzhou-");
        //缓存队列(阻塞队列)当核心线程数达到最大时,新任务会放在队列中排队等待执行
        executor.setQueueCapacity(10);
        /**
         * 拒绝task的处理策略
         * CallerRunsPolicy使用此策略,如果添加到线程池失败,那么主线程会自己去执行该任务,不会等待线程池中的线程去执行
         * AbortPolicy丢掉这个任务并且抛出
         * DiscardPolicy线程池队列满了,会直接丢掉这个任务并且不会有任何异常
         * DiscardOldestPolicy队列满了,会将最早进入队列的任务删掉腾出空间,再尝试加入队列
         */
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        executor.initialize();
        return executor;
    }
}
@Component
@EnableScheduling
@EnableAsync
public class CronDemo {
 
    @Async
    @Scheduled(cron = "${define.quartz.cron}")
    public void schedule() {
        System.out.println(Thread.currentThread().hashCode());
    }
 
    @Async
    @Scheduled(cron = "${define.quartz.cron}")
    public void schedule2() {
        System.out.println(Thread.currentThread().hashCode());
    }
    
}

第十四节 SpringBoot上传文件

① 由于分布式系统共享同一个数据库服务器。那么就可以把文件服务器搭建在与数据库同一台机器上。下面的代码中,nginxPath变量就是文件服务器的用于存放文件的文件夹路径。适合私有云与公有云部署。

② 把上传的文件直接存放到数据库中,但是这种解决方案被研发经理批评,原因是在数据库迁移会相当麻烦,而且如果有大文件的上传与下载,会占用过多的数据库资源,阻塞整个系统。此方案强烈反对在实际工作中使用,虽然曾经用过。

③ 购买云文件服务器。例如OSS文件服务器系统,把所有文件上传到公共得文件服务器中,这样就能让多个节点共享资源。缺点也有,如果客户的服务器不能支持访问公网的话,那么此方案会行不通,需要提前与客户确定运行环境。

第十九节 SpringBoot项目打包部署

 
        
            
                org.springframework.boot
                spring-boot-maven-plugin
            
 
        
    

第二十节 SpringBoot项目适配MySQL与Oracle

import org.apache.ibatis.mapping.DatabaseIdProvider;
import org.apache.ibatis.mapping.VendorDatabaseIdProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
 
import java.util.Properties;
 
@Configuration
public class DateSourceConfg {
 
    /**
     * 自动识别使用的数据库类型
     * 在mapper.xml中databaseId的值就是跟这里对应,
     * 如果没有databaseId选择则说明该sql适用所有数据库
     */
    @Bean
    public DatabaseIdProvider getDatabaseIdProvider() {
        DatabaseIdProvider databaseIdProvider = new VendorDatabaseIdProvider();
        Properties properties = new Properties();
        properties.setProperty("Oracle", "oracle");
        properties.setProperty("MySQL", "mysql");
        databaseIdProvider.setProperties(properties);
        return databaseIdProvider;
    }
 
}
    

第二十四节 SpringBoot使用spring.factories

META-INF/spring.factories文件
如何让我们的starter里的@Configuration在使用者的项目里生效呢?
在SpringBoot的启动类中,@SpringBootApplication注解的代码里面有一句@EnableAutoConfiguration


image.png

重要!
速记ComponentScan扫描自己,EnableAutoConfiguration扫描spring.factories包

@ComponentScan注解的作用是扫描@SpringBootApplication所在的Application类(即spring-boot项目的入口类)所在的包(basepackage)下所有的@component注解(或拓展了@component的注解)标记的bean,并注册到spring容器中。

@EnableAutoConfiguration注解加载的是资源目录META-INF文件下的spring.factories的文件。包括导入到项目中的Jar包的META-INF文件夹下的spring.factories文件。spring.factories文件是一个properties文件。

@ConditionalOnClass(SystemInit.class),如果容器里又SystemInit才加载使用它的Bean

@ConditionalOnMissingBean表示,如果Spring容器里没有SystemInit对象,那么就会为容器创建一个SystemInit对象。

你可能感兴趣的:(跟着大宇学SpringBoot)