美文网首页
跟着大宇学SpringBoot

跟着大宇学SpringBoot

作者: 小大宇 | 来源:发表于2021-07-21 16:43 被阅读0次

第一节 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<DicInfoVO> getDicList(@Valid DicListQry dicListQry) {
        return null;
    }

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

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

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

    @PostMapping("/dic/list")
    public MultiResponse<DicInfoVO> 
                         getDicListPost(@RequestBody @Validated DicList dicList) {
        return dictionaryService.getDicList(null);
    }
 
 
    @Data
    private static class DicList {
 
        @Valid
        private List<DicListQry> 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使用定时任务

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>
每隔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项目打包部署

 <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
 
        </plugins>
    </build>

第二十节 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;
    }
 
}
    <select id="getUserById" databaseId="mysql"/>
    <select id="getUserById" databaseId="oracle"/>

第二十四节 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

    第一节 SpringBoot项目基础搭建 spring.profiles.active 可以用于项目启动加载哪个...

  • 跟着大宇学SpringCloud

    第一节:服务注册与服务发现 服务中心,配置文件中的两个false说明自己是【注册中心】 【服务提供者 Eurek...

  • 跟着大宇学MySQL

    表的基本操作 表结构变化之前要备份,因为数据是无法恢复的。不是每张表都是需要主键的!有外键关联的两张表必须使用相同...

  • SpringBoot 入门篇(一) Hello World

    一、SpringBoot简介 二、跟着官方文档学习SpringBoot   1、SpringBoot入门Demo ...

  • springboot的crud案例

    springboot的crud案例 在学习了一段springboot后,跟着网上的老师做了一遍springboot...

  • 感恩的心

    跟着父母学做人 跟着老师学知识 跟着家人学谦让 跟着孩子学成长 跟着老板学挣钱 跟着朋友学相处 跟着坏人学自爱 跟...

  • 【宇宙同频】

    。。。。。。 主观小宇宙客观大宇宙 人类小宇宙自然大宇宙 空间小宇宙时间大宇宙 局部小宇宙整体大宇宙 内小宇宙外大...

  • 跟着学

    课程学到今天,我越来越疑惑,新媒体真的适合我吗? 无论是满脸好奇地去听老白的课,还是满腔热血向砍柴兄弟与冯尘妹妹学...

  • springboot 2.X 解决访问静态资源的时候出现404的

    springboot版本:2.1.15.RELEASEjquery版本:3.5.1今天跟着老师学习springbo...

  • 大宇

    跟你不联系后每天晚上都会坚持夜跑,最初只是为了不让自己停下来想你,后来喜欢上了那种挥汗如雨的感觉,累到精疲力尽,然...

网友评论

      本文标题:跟着大宇学SpringBoot

      本文链接:https://www.haomeiwen.com/subject/pupjmltx.html