zoukankan      html  css  js  c++  java
  • SpringBoot学习

    SpringBoot学习

    什么是SpringBoot他的优点是什么?

    SpringBoot简介

    Spring Boot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品:

    首页Spring Boot官方介绍简介可以看到下面的一段介绍

    Spring Boot的设计目的是让您尽可能快地启动和运行,而无需预先配置Spring。Spring Boot以一种固定的方式来构建可用于生产级别的应用程序。

    在这里插入图片描述

    一般把Spring Boot称为搭建程序的脚手架 或者说是便捷搭建 基于Spring的工程 脚手架。其最主要作用就是帮助开发人员快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让开发人员关注业务而非配置。

    为什么使用SpringBoot

    传统项目的缺点:

    java一直被人诟病的一点就是臃肿、麻烦。当我们还在辛苦的搭建项目时,可能Python程序员已经把功能写好了,究其原因注意是两点:

    1.复杂的配置

    项目各种配置其实是开发时的损耗, 因为在思考 Spring 特性配置和解决业务问题之间需要进行思维切换,所以写配置挤占了写应用程序逻辑的时间。

    2.一个是混乱的依赖管理

    项目的依赖管理也是件吃力不讨好的事情。决定项目里要用哪些库就已经够让人头痛的了,你还要知道这些库的哪个版本和其他库不会有冲突,这难题实在太棘手。并且,依赖管理也是一种损耗,添加依赖不是写应用程序代码。一旦选错了依赖的版本,随之而来的不兼容问题毫无疑问会是生产力杀手。

    3.而Spring Boot让这一切成为过去!

    Spring Boot 简化了基于Spring的应用开发,只需要“run”就能创建一个独立的、生产级别的Spring应用。Spring Boot为Spring平台及第三方库提供开箱即用的设置(提供默认设置,存放默认配置的包就是启动器starter),这样我们就可以简单的开始。多数Spring Boot应用只需要很少的Spring配置。我们可以使用Spring Boot创建java应用,并使用java –jar 启动它,就能得到一个生产级别的web工程。

    SpringBoot的主要特点

    1.创建独立的Spring应用,为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验
    2.直接嵌入应用服务器,如tomcat、jetty、undertow等;不需要去部署war包
    3.提供固定的启动器依赖去简化组件配置;实现开箱即用(启动器starter-其实就是Spring Boot提供的一个jar包),通过自己设置参数(.properties或.yml的配置文件),即可快速使用。
    4.自动地配置Spring和其它有需要的第三方依赖
    5.提供了一些大型项目中常见的非功能性特性,如内嵌服务器、安全、指标,健康检测、外部化配置等
    6.绝对没有代码生成,也无需 XML 配置

    SpringBoot快速入门

    目标:

    能够使用Spring Boot搭建项目

    分析:

    需求:可以在浏览器中访问http://localhost:8080/hello输出一串字符
    默认端口为8080

    实现步骤:

    1. 创建工程;
    2. 添加依赖(启动器依赖,spring-boot-starter-web);
    3. 创建启动类;
    4. 创建处理器Controller;
    5. 测试

    1. 创建工程;

    创建一个普通的maven工程

    在这里插入图片描述

    2. 添加依赖(启动器依赖,spring-boot-starter-web);

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
     <!--继承spring-boot的父类工程这样就可以使用父类工程中定义好的许多东西不需要自己实现-->
        <parent>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-parent</artifactId>
            <version>2.1.5.RELEASE</version>
        </parent>
        <groupId>org.example</groupId>
        <artifactId>SpringBoot</artifactId>
        <version>1.0-SNAPSHOT</version>
    
        <properties>
            <java.version>1.8</java.version>
        </properties>
    <dependencies>
        <!--导入spring-boot的启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
    </dependencies>
    </project>
    

    3. 创建启动类;

    springBott工程都有一个启动类,这是工程的入口类并在引导类上添加@SpringBootApplication注解,该注解包含扫描会扫描到当前包及其子包下的所有注解

    ![image.png](https://img-blog.csdnimg.cn/img_convert/33a057e9c5ab629f28bc39a440b71776.png#align=left&display=inline&height=217&margin=[object Object]&name=image.png&originHeight=338&originWidth=657&size=47474&status=done&style=none&width=422)

    package com.pjh;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    /*springBott工程都有一个启动类,这是工程的入口类
    * 并在引导类上添加@SpringBootApplication注解
    * 会扫描到当前包及其子包下的所有注解
    * */
    @SpringBootApplication
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class,args);
        }
    }
    
    

    4. 创建处理器Controller

    **
    @RestController包含以下注解
    在这里插入图片描述

    ** @GetMapping()包含以下注解**

    在这里插入图片描述

    package com.pjh.Controller;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    @RestController
    public class HelloController {
        @GetMapping("/hello")
        public String hello(){
            return "Hello Spring Boot" ;
        }
    }
    
    

    5. 测试

    在这里插入图片描述

    SpringBoot如何配置Bean

    Spring-boot可以在没有任何的xml的情况下配置Bean,比如我们要配置一个数据库连接池,以前会这么配置:

    <!-- 配置连接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"init-method="init" destroy-method="close">
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" 
    </bean>
    

    Spring配置历史

    事实上,在Spring3.0开始,Spring官方就已经开始推荐使用java配置来代替传统的xml配置了,我们不妨来回顾一下
    Spring的历史:

    Spring1.0时代

    在此时因为jdk1.5刚刚出来,注解开发并未盛行,因此一切Spring配置都是xml格式,想象一下所有的bean都用xml配置,细思极恐啊,心疼那个时候的程序员2秒

    Spring2.0时代

    Spring引入了注解开发,但是因为并不完善,因此并未完全替代xml,此时的程序员往往是把xml与注解进行结合,貌似我们之前都是这种方式。

    Spring3.0及以后

    3.0以后Spring的注解已经非常完善了,因此Spring推荐大家使用完全的java配置来代替以前的xml,不过似乎在国内并未推广盛行。然后当Spring Boot来临,人们才慢慢认识到java配置的优雅。有句古话说的好:拥抱变化,拥抱未来。所以我们也应该顺应时代潮流,做时尚的弄潮儿,一起来学习下java配置的玩法

    使用java代码配置一个数据库连接池

    java配置主要靠java类和一些注解,比较常用的注解有:
    @Configuration :声明一个类作为配置类,代替xml文件@Bean :声明在方法上,将方法的返回值加入Bean容器,代替 标签@Value :属性注入@PropertySource :指定外部属性文件,

    案例

    目标:可以使用@Value获取配置文件配置项并结合@Bean注册组件到Spring

    分析
    需求:使用Java代码配置数据库连接池,并可以在处理器中注入并使用
    步骤

    1. 添加依赖;
    2. 创建数据库;
    3. 创建数据库连接参数的配置文件jdbc.properties;
    4. 创建配置类;
    5. 改造处理器类注入数据源并使用

    添加依赖;

    <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
    

    创建数据库;
    在这里插入图片描述

    创建数据库连接参数的配置文件jdbc.properties;

    jdbc.Driver=com.mysql.jdbc.Driver
    jdbc.Username=root
    jdbc.Url=jdbc:mysql://localhost:3309/test
    jdbc.Password=1234
    

    **
    创建配置类;
    **

    package com.pjh.Config;
    
    import com.alibaba.druid.pool.DruidDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    import javax.sql.DataSource;
    /*说明这是一个配置类*/
    @Configuration
    /*读取配置文件*/
    @PropertySource("classpath:jdbc.properties")
    public class JdbcConfig {
        /*注入对应的参数*/
        @Value("${jdbc.Url}")
        String url;
        @Value("${jdbc.Driver}")
        String driverClass;
        @Value("${jdbc.Username}")
        String username;
        @Value("${jdbc.Password}")
        String password;
        @Bean
        public DataSource dataSource(){
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setUrl(url);
            druidDataSource.setDriverClassName(driverClass);
            druidDataSource.setUsername(username);
            druidDataSource.setPassword(password);
            return druidDataSource;
        }
    }
    
    

    **
    改造处理器类注入数据源并使用

    package com.pjh.Controller;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import sun.dc.pr.PRError;
    
    import javax.sql.DataSource;
    
    @RestController
    public class HelloController {
    
        @Autowired
        private DataSource dataSource;
        @GetMapping("/hello")
        public String hello(){
            System.out.println(dataSource);
            return "Hello Spring Boot" ;
        }
    }
    
    

    SpringBoot属性注入方式

    案例

    目标:能够使用@ConfigurationProperties实现Spring Boot配置文件配置项读取和应用

    分析:
    **
    需求:将配置文件中的配置项读取到一个对象中;

    实现:可以使用Spring Boot提供的注解@ConfigurationProperties,该注解可以将Spring Boot的配置文件(默认必须为application.properties或application.yml)中的配置项读取到一个对象中。
    **
    实现步骤:
    **
    **1. **创建配置项类JdbcProperties类,在该类名上面添加@ConfigurationProperties;

    **2. **将jdbc.properties修改名称为application.properties;

    3. 将JdbcProperties对象注入到JdbcConfig;

    **4. **测试

    1. 创建配置项类JdbcProperties类,在该类名上面添加@ConfigurationProperties;

    ConfigurationProperties 从application配置文件中读取配置项
    ** prefix 表示 配置项的前缀**
    ** 配置项类中的类变量名必须要与 前缀之后的配置项名称保持 松散绑定(相同)**

    package com.pjh.Config;
    
    @org.springframework.boot.context.properties.ConfigurationProperties(prefix = "jdbc")
    public class JdbcProperties {
        private String url;
        private String driverClassName;
        private String username;
        private String password;
    
        public String getUrl() {
            return url;
        }
    
        public void setUrl(String url) {
            this.url = url;
        }
    
        public String getDriverClassName() {
            return driverClassName;
        }
    
        public void setDriverClassName(String driverClassName) {
            this.driverClassName = driverClassName;
        }
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getPassword() {
            return password;
        }
    
        public void setPassword(String password) {
            this.password = password;
        }
    }
    
    

    **2. **将jdbc.properties修改名称为application.properties;

    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.username=root
    jdbc.url=jdbc:mysql://localhost:3309/test
    jdbc.password=1234
    

    3. 将JdbcProperties对象注入到JdbcConfig;

    通过 @EnableConfigurationProperties(JdbcProperties.class) 来声明要使用 JdbcProperties 这个类的对象
    然后要使用配置的话;可以通过以下方式注入JdbcProperties:

    注入方式1
    方法参数注入

    @Bean
        public DataSource dataSource(JdbcProperties jdbcProperties){
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setUrl(jdbcProperties.getUrl());      druidDataSource.setDriverClassName(jdbcProperties.getDriverClassName());
            druidDataSource.setUsername(jdbcProperties.getUsername());
            druidDataSource.setPassword(jdbcProperties.getPassword());
            return druidDataSource;
        }
    

    注入方式2

    @Autowired注入

    @Autowired
    private JdbcProperties prop;
    

    注入方式3

    构造函数注入

    private JdbcProperties prop;
    public JdbcConfig(Jdbcproperties prop){
    this.prop = prop;
    }
    

    **4. **测试

    在这里插入图片描述

    优雅的SpringBoot注入方式

    事实上,如果一段属性只有一个Bean需要使用,我们无需将其注入到一个类(JdbcProperties,将该类上的所有注解去掉)中。而是直接在需要的地方声明即可;再次修改 JdbcConfig 类为如下

    代码:

    @Configuration
    public class JdbcConfig {
    @Bean
    // 声明要注入的属性前缀,Spring Boot会自动把相关属性通过set方法注入到DataSource中
    @ConfigurationProperties(prefix = "jdbc")
    public DataSource dataSource() {
    return new DruidDataSource();
    }
    }
    

    我们直接把 @ConfigurationProperties(prefix = "jdbc") 声明在需要使用的 @Bean 的方法上,然后SpringBoot就会自动调用这个Bean(此处是DataSource)的set方法,然后完成注入。使用的前提是:该类必须有对应属性的set方法(即对应的名称与set方法的名称要一致)!

    注意事项:
    这种读取方式不需要创建对应的类,是直接读取配置文件中以"jdbc"为前缀的项,然后自动的匹配方法中要返回值的属性,把与jdbc中对应后缀的名称与类中对应的属性的名称一致的自动匹配,自动注入

    yml文件的配置

    什么是yml文件

    YML文件格式是YAML (YAML Aint Markup Language)编写的文件格式,YAML是一种直观的能够被电脑识别的的数据数据序列化格式,并且容易被人类阅读, 容易和脚本语言交互的,可以被支持YAML库的不同的编程语言程序导入,比如: C/C++, Ruby, Python, Java, Perl, C#, PHP等。YML文件是以数据为核心的,比传统的xml方式更加简洁。 YML文件的扩展名可以使用.yml或者.yaml

    在这里插入图片描述

    yml配置文件的特征:

    1. 树状层级结构展示配置项;
    2. 配置项之间如果有关系的话需要分行空两格;
    3. 配置项如果有值的话,那么需要在 :之后空一格再写配置项值;

    将application.properties配置文件修改为application.yml的话:

    propeties文件

    jdbc.driverClassName=com.mysql.jdbc.Driver
    jdbc.username=root
    jdbc.url=jdbc:mysql://localhost:3309/test
    jdbc.password=1234
    

    yml文件

    jdbc:
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/heima
      username: root
      password: root
    
    key:
      abc: cba
      def:
        - g
        - h
        - j
    

    yml配置文件的注意事项

    多个yml配置文件:

    在spring boot中是被允许的。这些配置文件的名称必须为application-***.yml,并且这些配置文件必须要在application.yml配置文件中激活之后才可以使用。
    **
    案例
    **
    比如有两个配置文件application-abc.yml,application-def.yml

    #激活配置文件;需要指定其它的配置文件名称
    spring:
      profiles:
        active: abc,def
    

    如果properties和yml配置文件同时存在在spring boot项目中:

    那么这两类配置文件都有效。在两个配置文件中如果存在同名的配置项的话会以properties文件的为主。

    yml配置不同的数据类型

    yml配置普通数据

    语法: key: value

    name: haohao
    

    配置对象数据||配置Map数据

    语法:
    key:
    key1: value1
    key2: value2
    ** 或者:**
    key: {key1: value1,key2: value2}

    示例代码

    person:
      name: haohao
      age: 31
      addr: beijing
    
    #或者
    
    person: {name: haohao,age: 31,addr: beijing}
    
    

    配置数组(List、Set)数据

    语法
    key:

    • value1
    • value2
      或者:
      key: [value1,value2]
    city:
      - beijing
      - tianjin
      - shanghai
      - chongqing
      
    #或者
    
    city: [beijing,tianjin,shanghai,chongqing]
    
    #集合中的元素是对象形式
    student:
      - name: zhangsan
        age: 18
        score: 100
      - name: lisi
        age: 28
        score: 88
      - name: wangwu
        age: 38
        score: 90
    

    注意:value1与之间的 - 之间存在一个空格
    例子:

    整合

    #普通数据配置
    name: 张三
    #对象的配置
    #person:
    #  name: 张三
    #  age: 18
    #  addr: 北京
    
    #行内对象配置
    #person: {name: 张三,age: 18,addr: 北京}
    
    #配置数据、集合(普通字符串)
    #city:
    #  - beijing
    #  - shanghai
    #  - tianjin
    
    #city: [beijin,tianjin,shanghai]
    
    #配置数据、集合(对象数据)
    #student:
    #  - name: 张三
    #    age: 18
    #    addr: beijin
    #  - name: 李四
    #    age: 19
    #    addr: tianjin
    
    #student: [{name: zhangsan,age: 19,addr: beijin},{name: lishi,age: 20,addr: beijin}]
    
    #map配置
    map:
      key1: value1
      key2: value2
    
    

    SpringBoot自动配置原理

    写在前面

    使用Spring Boot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?
    一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:

    在这里插入图片描述

    我们发现特别的地方有两个:
    注解:@SpringBootApplication
    run方法:SpringApplication.run()我们分别来研究这两个部分

    了解@SpringBootApplication

    点击进入,查看源码:

    在这里插入图片描述

    这里重点的注解有3个:
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan

    @SpringBootConfiguration

    在这里插入图片描述

    通过这段我们可以看出,在这个注解上面,又有一个 @Configuration 注解。通过上面的注释阅读我们知道:这个注解的作用就是声明当前类是一个配置类,然后Spring会自动扫描到添加了 @Configuration 的类,并且读取其中的配置信息。而 @SpringBootConfiguration 是来声明当前类是SpringBoot应用的配置类,项目中只能有一个。所以一般我们无需自己添加。

    @EnableAutoConfiguration

    关于这个注解,官网上有一段说明
    第二级的注解 @EnableAutoConfiguration ,告诉Spring Boot基于你所添加的依赖,去“猜测”你想要如何配置Spring。比如我们引入了 spring-boot-starter-web ,而这个启动器中帮我们添加了 tomcat 、 SpringMVC的依赖。此时自动配置就知道你是要开发一个web应用,所以就帮你完成了web及SpringMVC的默认配置了!

    总结:

    Spring Boot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。

    @ComponentScan

    我们跟进源码

    在这里插入图片描述

    并没有看到什么特殊的地方。我们查看注释:

    在这里插入图片描述

    大概的意思:
    配置组件扫描的指令。提供了类似与 context:component-scan 标签的作用
    通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
    而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中

    SpringBoot默认配置原理

    spring.factories

    在SpringApplication类构建的时候,有这样一段初始化代码:

    在这里插入图片描述

    跟进去:
    在这里插入图片描述

    这里发现会通过loadFactoryNames尝试加载一些FactoryName,然后利用createSpringFactoriesInstances将这些加载到的类名进行实例化。继续跟进loadFactoryNames方法:
    在这里插入图片描述

    发现此处会利用类加载器加载某个文件: FACTORIES_RESOURCE_LOCATION ,然后解析其内容。我们找到这个变量的声明:

    在这里插入图片描述

    可以发现,其地址是: META-INF/spring.factories ,我们知道,ClassLoader默认是从classpath下读取文件,因此,SpringBoot会在初始化的时候,加载所有classpath:META-INF/spring.factories文件,包括jar包当中的。而在Spring的一个依赖包:spring-boot-autoconfigure中,就有这样的文件:
    在这里插入图片描述

    **以后我们引入的任何第三方启动器,只要实现自动配置,也都会有类似 **

    默认配置类

    我们打开刚才的spring.factories文件:
    在这里插入图片描述

    可以发现以EnableAutoConfiguration接口为key的一系列配置,key所对应的值,就是所有的自动配置类,可以在当前的jar包中找到这些自动配置类:
    在这里插入图片描述

    非常多,几乎涵盖了现在主流的开源框架,例如:
    redis
    jms
    amqp
    jdbc
    jackson
    mongodb
    jpa
    solr
    elasticsearch
    ... 等等
    我们来看一个我们熟悉的,例如SpringMVC,查看mvc 的自动配置类:

    在这里插入图片描述
    **

    打开WebMvcAutoConfiguration:

    **

    在这里插入图片描述

    我们看到这个类上的4个注解:
    **@Configuration :声明这个类是一个配置类@ConditionalOnWebApplication(type = Type.SERVLET)ConditionalOn,翻译就是在某个条件下,此处就是满足项目的类是是Type.SERVLET类型,也就是一个普通web工程,显然我们就是@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })这里的条件是OnClass,也就是满足以下类存在:Servlet、DispatcherServlet、WebMvcConfigurer,其Servlet只要引入了tomcat依赖自然会有,后两个需要引入SpringMVC才会有。这里就是判断你是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效!@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)这个条件与上面不同,OnMissingBean,是说环境中没有指定的Bean这个才生效。其实这就是自定义配置的入口,也就是说,如果我们自己配置了一WebMVCConfigurationSupport的类,那么这个默认配置就会失效!
    接着,我们查看该类中定义了什么:
    **

    视图解析器:

    在这里插入图片描述

    处理器适配器(HandlerAdapter):
    在这里插入图片描述

    还有很多,这里就不一一截图了。

    默认配置属性

    另外,这些默认配置的属性来自哪里呢?

    在这里插入图片描述

    我们看到,这里通过@EnableAutoConfiguration注解引入了两个属性:WebMvcProperties和ResourceProperties。这不正是SpringBoot的属性注入玩法嘛。
    我们查看这两个属性类:

    在这里插入图片描述

    找到了内部资源视图解析器的prefix和suffix属性。ResourceProperties中主要定义了静态资源(.js,.html,.css等)的路径:**

    在这里插入图片描述

    **如果我们要覆盖这些默认属性,只需要在application.properties中定义与其前缀prefix和字段名一致的属性即可。 **

    总结

    SpringBoot为我们提供了默认配置,而默认配置生效的步骤:

    1.@EnableAutoConfiguration注解会去寻找 META-INF/spring.factories 文件,读取其中以EnableAutoConfiguration 为key的所有类的名称,这些类就是提前写好的自动配置类

    2.这些类都声明了 @Configuration 注解,并且通过 @Bean 注解提前配置了我们所需要的一切实例

    3.但是,这些配置不一定生效,因为有 @ConditionalOn 注解,满足一定条件才会生效。比如条件之一: 是一些相关的类要存在

    4.类要存在,我们只需要引入了相关依赖(启动器),依赖有了条件成立,自动配置生效。
    5.如果我们自己配置了相关Bean,那么会覆盖默认的自动配置的Bean

    6.我们还可以通过配置application.yml文件,来覆盖自动配置中的属性

    1)启动器

    所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。
    因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器

    2)全局配置

    另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义 application.properties 文件来
    进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。
    因此,玩SpringBoot的第二件事情,就是通过 application.properties 来覆盖默认属性值,形成自定义配置。我
    们需要知道SpringBoot的默认属性key,非常多,可以再idea中自动提示

    属性文件支持两种格式,application.properties和application.yml
    yml的语法实例:

    jdbc:
      driverClassName: com.mysql.jdbc.Driver
      url: jdbc:mysql://127.0.0.1:3306/springboot_test
      username: root
      password: root
    server:
      port: 80
    

    如果properties和yml文件都存在,如果有重叠属性,默认以Properties优先。遇到需要修改的组件的配置项流程为:

    在这里插入图片描述

    Lombok

    什么是Lombok

    Lombok是一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,通过使用对应的注解,可以在编译源码的时候生成对应的方法

    Lombok使用方法

    步骤1

    File->setting->Plugins ,然后搜索lombok
    在这里插入图片描述

    步骤二

    在pom.xml文件中导入相关的依赖

    <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>
    

    注解介绍

    @Getter and @Setter

    你可以用@Getter / @Setter注释任何字段(当然也可以注释到类上的),让lombok自动生成默认的getter / setter方法。
    默认生成的方法是public的,如果要修改方法修饰符可以设置AccessLevel的值,例如:@Getter(access = AccessLevel.PROTECTED)
    **

    在这里插入图片描述

    import lombok.AccessLevel;
    import lombok.Getter;
    import lombok.Setter;
    public class User {
        @Getter(AccessLevel.PROTECTED) @Setter private Integer id;
        @Getter @Setter private String name;
        @Getter @Setter private String phone;
    }
    

    @ToString

    生成toString()方法,默认情况下,它会按顺序(以逗号分隔)打印你的类名称以及每个字段。可以这样设置不包含哪些字段@ToString(exclude = "id") / @ToString(exclude = {"id","name"})
    如果继承的有父类的话,可以设置callSuper 让其调用父类的toString()方法,例如:@ToString(callSuper = true)

    import lombok.ToString;
    @ToString(exclude = {"id","name"})
    public class User {
      private Integer id;
      private String name;
      private String phone;
    }
    

    生成toString方法如下:

    public String toString(){
      return "User(phone=" + phone + ")";
    }
    

    @EqualsAndHashCode

    生成hashCode()和equals()方法,默认情况下,它将使用所有非静态,非transient字段。但可以通过在可选的exclude参数中来排除更多字段。或者,通过在parameter参数中命名它们来准确指定希望使用哪些字段。

    @EqualsAndHashCode(exclude={"id", "shape"})
    public class EqualsAndHashCodeExample {
      private transient int transientVar = 10;
      private String name;
      private double score;
      private Shape shape = new Square(5, 10);
      private String[] tags;
      private transient int id;
      
      public String getName() {
        return this.name;
      }
      
      @EqualsAndHashCode(callSuper=true)
      public static class Square extends Shape {
        private final int width, height;
        
        public Square(int width, int height) {
          this.width = width;
          this.height = height;
        }
      }
    }
    

    对比代码如下:

    import java.util.Arrays;
    public class EqualsAndHashCodeExample {
     private transient int transientVar = 10;
     private String name;
     private double score;
     private Shape shape = new Square(5, 10);
     private String[] tags;
     private transient int id;
     public String getName() {
       return this.name;
     }
     
     @Override public boolean equals(Object o) {
       if (o == this) return true;
       if (!(o instanceof EqualsAndHashCodeExample)) return false;
       EqualsAndHashCodeExample other = (EqualsAndHashCodeExample) o;
       if (!other.canEqual((Object)this)) return false;
       if (this.getName() == null ? other.getName() != null : !this.getName().equals(other.getName())) return false;
       if (Double.compare(this.score, other.score) != 0) return false;
       if (!Arrays.deepEquals(this.tags, other.tags)) return false;
       return true;
     }
     
     @Override public int hashCode() {
       final int PRIME = 59;
       int result = 1;
       final long temp1 = Double.doubleToLongBits(this.score);
       result = (result*PRIME) + (this.name == null ? 43 : this.name.hashCode());
       result = (result*PRIME) + (int)(temp1 ^ (temp1 >>> 32));
       result = (result*PRIME) + Arrays.deepHashCode(this.tags);
       return result;
     }
     
     protected boolean canEqual(Object other) {
       return other instanceof EqualsAndHashCodeExample;
     }
     
     public static class Square extends Shape {
       private final int width, height;
       
       public Square(int width, int height) {
         this.width = width;
         this.height = height;
       }
       
       @Override public boolean equals(Object o) {
         if (o == this) return true;
         if (!(o instanceof Square)) return false;
         Square other = (Square) o;
         if (!other.canEqual((Object)this)) return false;
         if (!super.equals(o)) return false;
         if (this.width != other.width) return false;
         if (this.height != other.height) return false;
         return true;
       }
       
       @Override public int hashCode() {
         final int PRIME = 59;
         int result = 1;
         result = (result*PRIME) + super.hashCode();
         result = (result*PRIME) + this.width;
         result = (result*PRIME) + this.height;
         return result;
       }
       
       protected boolean canEqual(Object other) {
         return other instanceof Square;
       }
     }
    }
    
    • @NoArgsConstructor, @RequiredArgsConstructor, @AllArgsConstructor

    @NoArgsConstructor生成一个无参构造方法。当类中有final字段没有被初始化时,编译器会报错,此时可用@NoArgsConstructor(force = true),然后就会为没有初始化的final字段设置默认值 0 / false / null。对于具有约束的字段(例如@NonNull字段),不会生成检查或分配,因此请注意,正确初始化这些字段之前,这些约束无效。

    import lombok.NoArgsConstructor;
    import lombok.NonNull;
    @NoArgsConstructor(force = true)
    public class User {
        @NonNull private Integer id;
        @NonNull private String name;
        private final String phone ;
    }
    

    @RequiredArgsConstructor会生成构造方法(可能带参数也可能不带参数),如果带参数,这参数只能是以final修饰的未经初始化的字段,或者是以@NonNull注解的未经初始化的字段
    @RequiredArgsConstructor(staticName = "of")会生成一个of()的静态方法,并把构造方法设置为私有的

    在这里插入图片描述

    在这里插入图片描述

    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;
    @RequiredArgsConstructor
    public class User {
      @NonNull private Integer id ;
      @NonNull private String name = "bbbb";
      private final String phone;
    }
    //另外一个
    import lombok.NonNull;
    import lombok.RequiredArgsConstructor;
    @RequiredArgsConstructor(staticName = "of")
    public class User {
      @NonNull private Integer id ;
      @NonNull private String name = "bbbb";
      private final String phone;
    }
    

    @AllArgsConstructor 生成一个全参数的构造方法

    在这里插入图片描述

    import lombok.AllArgsConstructor;
    import lombok.NonNull;
    @AllArgsConstructor
    public class User {
      @NonNull private Integer id ;
      @NonNull private String name = "bbbb";
      private final String phone;
    }
    

    @Data

    @Data 包含了 @ToString、@EqualsAndHashCode、@Getter / @Setter和@RequiredArgsConstructor的功能

    @Accessors

    @Accessors 主要用于控制生成的getter和setter
    主要参数介绍

    • fluent boolean值,默认为false。此字段主要为控制生成的getter和setter方法前面是否带get/set
    • chain boolean值,默认false。如果设置为true,setter返回的是此对象,方便链式调用方法
    • prefix 设置前缀 例如:@Accessors(prefix = "abc") private String abcAge 当生成get/set方法时,会把此前缀去掉

    在这里插入图片描述

    @Synchronized

    给方法加上同步锁

    import lombok.Synchronized;
    public class SynchronizedExample {
       private final Object readLock = new Object();
       
      @Synchronized
      public static void hello() {
        System.out.println("world");
      }
       
      @Synchronized
      public int answerToLife() {
        return 42;
     }
      @Synchronized("readLock")
      public void foo() {
        System.out.println("bar");
       }
    }
    
    //等效代码
    public class SynchronizedExample {
    private static final Object $LOCK = new Object[0];
    private final Object $lock = new Object[0];
    private final Object readLock = new Object();
     
    public static void hello() {
      synchronized($LOCK) {
        System.out.println("world");
      }
    }
     
    public int answerToLife() {
     synchronized($lock) {
        return 42;
      }
    }
    public void foo() {
      synchronized(readLock) {
        System.out.println("bar");
      }
    }
    }
    

    @Wither

    提供了给final字段赋值的一种方法

    //使用lombok注解的
    import lombok.AccessLevel;
    import lombok.NonNull;
    import lombok.experimental.Wither;
    public class WitherExample {
      @Wither private final int age;
      @Wither(AccessLevel.PROTECTED) @NonNull private final String name;
       
      public WitherExample(String name, int age) {
        if (name == null) throw new NullPointerException();
        this.name = name;
        this.age = age;
      }
    }
    
    //等效代码
    import lombok.NonNull;
    public class WitherExample {
    private final int age;
    private @NonNull final String name;
    public WitherExample(String name, int age) {
     if (name == null) throw new NullPointerException();
     this.name = name;
     this.age = age;
    }
    public WitherExample withAge(int age) {
     return this.age == age ? this : new WitherExample(age, name);
    }
    protected WitherExample withName(@NonNull String name) {
     if (name == null) throw new java.lang.NullPointerException("name");
     return this.name == name ? this : new WitherExample(age, name);
    }
    }
    

    @onX

    在注解里面添加注解的方式

    直接看代码

    public class SchoolDownloadLimit implements Serializable {
        private static final long serialVersionUID = -196412797757026250L;
        @Getter(onMethod = @_({@Id,@Column(name="id",nullable=false),@GeneratedValue(strategy= GenerationType.AUTO)}))
        @Setter
        private Integer id;
        @Getter(onMethod = @_(@Column(name="school_id")))
        @Setter
        private Integer schoolId;
        @Getter(onMethod = @_(@Column(name = "per_download_times")))
        @Setter
        private Integer perDownloadTimes;
        @Getter(onMethod = @_(@Column(name = "limit_time")))
        @Setter
        private Integer limitTime;
        @Getter(onMethod = @_(@Column(name = "download_to_limit_an_hour")))
        @Setter
        private Integer downloadToLimitInHour;
        @Getter(onMethod = @_(@Column(name = "available")))
        @Setter
        private Integer available = 1;
    }
    

    @Builder

    @Builder注释为你的类生成复杂的构建器API。
    lets you automatically produce the code required to have your class be instantiable with code such as:

    Person.builder().name("Adam Savage").city("San Francisco").job("Mythbusters").job("Unchained Reaction").build();
    

    直接看官方示例,对比一下就都明白了

    //使用lombok注解的
    import lombok.Builder;
    import lombok.Singular;
    import java.util.Set;
    @Builder
    public class BuilderExample {
     private String name;
     private int age;
     @Singular private Set<String> occupations;
    }
    
    //等效代码
    import java.util.Set;
    class BuilderExample {
      private String name;
      private int age;
      private Set<String> occupations;
      BuilderExample(String name, int age, Set<String> occupations) {
          this.name = name;
          this.age = age;
          this.occupations = occupations;
      }
      public static BuilderExampleBuilder builder() {
          return new BuilderExampleBuilder();
      }
      public static class BuilderExampleBuilder {
          private String name;
          private int age;
          private java.util.ArrayList<String> occupations;
          BuilderExampleBuilder() {
          }
          public BuilderExampleBuilder name(String name) {
              this.name = name;
              return this;
          }
          public BuilderExampleBuilder age(int age) {
              this.age = age;
              return this;
          }
          public BuilderExampleBuilder occupation(String occupation) {
              if (this.occupations == null) {
                  this.occupations = new java.util.ArrayList<String>();
              }
              this.occupations.add(occupation);
              return this;
          }
          public BuilderExampleBuilder occupations(Collection<? extends String> occupations) {
              if (this.occupations == null) {
                  this.occupations = new java.util.ArrayList<String>();
              }
              this.occupations.addAll(occupations);
              return this;
          }
          public BuilderExampleBuilder clearOccupations() {
              if (this.occupations != null) {
                  this.occupations.clear();
              }
              return this;
          }
          public BuilderExample build() {
              // complicated switch statement to produce a compact properly sized immutable set omitted.
              // go to https://projectlombok.org/features/Singular-snippet.html to see it.
              Set<String> occupations = ...;
              return new BuilderExample(name, age, occupations);
          }
          @java.lang.Override
          public String toString() {
              return "BuilderExample.BuilderExampleBuilder(name = " + this.name + ", age = " + this.age + ", occupations = " + this.occupations + ")";
          }
      }
    }
    

    @Delegate

    这个注解也是相当的牛逼,看下面的截图,它会该类生成一些列的方法,这些方法都来自与List接口

    在这里插入图片描述

    附带一个我使用的例子
    import lombok.Getter;
    import lombok.RequiredArgsConstructor;
    import lombok.Setter;
    import lombok.ToString;
    import lombok.experimental.Accessors;
    import javax.persistence.Column;
    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.GenerationType;
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.io.Serializable;
    import java.util.Date;
    @Entity
    @Table(name= Constants.TABLE_SCHOOL_DOWNLOAD_LIMIT)
    @RequiredArgsConstructor(staticName = "of")
    @Accessors(chain = true)
    @ToString
    public class SchoolDownloadLimit implements Serializable {
        private static final long serialVersionUID = -196412797757026250L;
        @Getter(onMethod = @_({@Id,@Column(name="id",nullable=false),@GeneratedValue(strategy= GenerationType.AUTO)}))
        @Setter
        private Integer id;
        @Getter(onMethod = @_(@Column(name="school_id")))
        @Setter
        private Integer schoolId;
        @Getter(onMethod = @_(@Column(name = "per_download_times")))
        @Setter
        private Integer perDownloadTimes;
        @Getter(onMethod = @_(@Column(name = "limit_time")))
        @Setter
        private Integer limitTime;
        @Getter(onMethod = @_(@Column(name = "download_to_limit_an_hour")))
        @Setter
        private Integer downloadToLimitInHour;
        @Getter(onMethod = @_(@Column(name = "available")))
        @Setter
        private Integer available = 1;
        @Getter(onMethod = @_(@Column(name = "create_time")))
        @Setter
        private Date createTime;
        @Getter(onMethod = @_(@Column(name = "update_time")))
        @Setter
        private Date updateTime;
    }
    

    就介绍这么多了,更多的注解请看官方文档

    整合SpringMVC

    虽然默认配置已经可以使用SpringMVC了,不过我们有时候需要进行自定义配置。
    可以在 application.yml 文件中配置日志级别控制:

    修改端口

    查看SpringBoot的全局属性可知,端口通过以下方式配置:

    logging:
    level:
    com.itheima: debug
    org.springframework: info
    

    修改 application.yml 配置文件,添加如下配置:

    #tomcat默认端口
    server:
      port: 80
    

    重启服务后测试:

    在这里插入图片描述

    访问静态资源

    现在,我们的项目是一个jar工程,那么就没有webapp,我们的静态资源该放哪里呢?
    回顾我们在上面看的源码,有一个叫做ResourceProperties的类(路径:org.springframework.boot.autoconfigure.web.ResourceProperties),里面就定义了静态资源的默认查找路径:
    默认的静态资源路径为:

    classpath:/META-INF/resources/
    classpath:/resources/
    classpath:/static/
    classpath:/public
    

    只要静态资源放在这些目录中任何一个,SpringMVC都会帮我们处理。
    **我们习惯会把静态资源放在 classpath:/static/ 目录下。我们创建目录 static **,
    在这里插入图片描述

    # 映射端口server:port: 80
    

    注意:如果访问图片时候没有显示;可以先将项目先clean再启动,或者创建 public、resources 文件夹,然后图片放置到public或resources中。

    添加拦截器

    拦截器介绍

    拦截器也是我们经常需要使用的,在SpringBoot中该如何配置呢?
    拦截器不是一个普通属性,而是一个类,所以就要用到java配置方式了。

    在SpringBoot官方文档中有这么一段说明:
    If you want to keep Spring Boot MVC features and you want to add additional MVC configuration(interceptors, formatters, view controllers, and other features), you can add your own @Configurationclass of type WebMvcConfigurer but without @EnableWebMvc . If you wish to provide custom instances of RequestMappingHandlerMapping , RequestMappingHandlerAdapter , orExceptionHandlerExceptionResolver , you can declare a WebMvcRegistrationsAdapter instance to provide such components. If you want to take complete control of Spring MVC, you can add your own @Configuration annotated with @EnableWebMvc .
    **
    翻译:如果你想要保持Spring Boot 的一些默认MVC特征,同时又想自定义一些MVC配置(包括:拦截器,格式化器,视图控制器、消息转换器 等等),你应该让一个类实现 WebMvcConfigurer ,并且添加 @Configuration 注解,但是千万不要加 @EnableWebMvc 注解。如果你想要自定义HandlerMappingHandlerAdapter 、ExceptionResolver 等组件,你可以创建一个 WebMvcRegistrationsAdapter 实例 来提供以上组件。如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加@Configuration 注解和 @EnableWebMvc 注解

    总结:通过实现 WebMvcConfigurer 并添加 @Configuration 注解来实现自定义部分SpringMvc配置。

    案例

    配置一个拦截器

    package com.pjh.Interceptor;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.web.servlet.HandlerInterceptor;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    @Slf4j
    public class MyInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
            log.debug("这是MyInterceptor的preHandle方法");
            return true;
        }
    
        @Override
        public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
            log.debug("这是MyInterceptor的postHandle方法");
        }
    
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            log.debug("这是MyInterceptor的afterCompletion方法");
        }
    }
    
    
    

    注册一个拦截器

    package com.pjh.Config;
    
    import com.pjh.Interceptor.MyInterceptor;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    @Configuration
    public class MvcConfig implements WebMvcConfigurer {
        /*将拦截器注册到ioc容器*/
        @Bean
        public MyInterceptor getInterceptor(){
            return new MyInterceptor();
        }
        /*重写该方法,往拦截器链添加自定义拦截器
        * @param registry 拦截器链
        * */
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
            /*向拦截器链添加拦截器并设置路径为所有*/
            registry.addInterceptor(getInterceptor()).addPathPatterns("/*");
        }
    }
    
    

    接下来访问http://localhost/hello 并查看日志:

    在这里插入图片描述

    整合JDBC和事务

    SpringBoot中是如何处理Jdbc和事务链接的

    spring中的jdbc连接和事务是配置中的重要一环,在SpringBoot中该如何处理呢?
    答案是不需要处理,我们只要找到SpringBoot提供的启动器即可,在 pom.xml 文件中添加如下依赖:

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

    当然,不要忘了数据库驱动,SpringBoot并不知道我们用的什么数据库,这里我们选择MySQL;同样的在 pom.xml文件中添加如下依赖:

    <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    

    至于事务,SpringBoot中通过注解来控制。就是我们熟知的 @Transactional 使用的时候设置在对应的类或方法上即可。

    案例

    目标:

    配置Spring Boot自带默认的hikari数据库连接池和使用@Transactional注解进行事务配置

    分析:

    1.添加事务相关的启动器依赖,mysql相关依赖
    2.编写业务类UserService使用事务注解@Transactional
    3.数据库连接池hikari配置
    只需要在application配置文件中指定数据库相关参数

    1.添加事务相关的启动器依赖,mysql相关依赖

    <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>
    

    2.编写业务类UserService使用事务注解@Transactional

    加了@Transactional注解的方法中的内容要不全部执行成功要不回滚

    package com.pjh.service;
    
    import com.pjh.pojo.User;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    @Service
    public class UserService {
        public User queryForId(){
            return new User();
        }
        @Transactional
        public void saveUser(){
            System.out.println("add new User!!");
        }
    }
    
    

    3.数据库连接池hikari配置

    **引入jdbc启动器的时候,SpringBoot已经自动帮我们引入了hikari连接池 **
    **

    在这里插入图片描述

    **HikariCP应该是目前速度最快的连接池了,我们看看它与c3p0的对比 **

    在这里插入图片描述

    只需要在application配置文件中指定数据库相关参数

    spring:
      datasource:
        driver-class-name: com.mysql.jdbc.Driver
        url: jdbc:mysql://localhost:3309/test
        password: 1234
        username: root
    

    直接在要使用的地方注入即可使用
    **

    package com.pjh.Controller;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    import javax.sql.DataSource;
    import java.sql.SQLException;
    @RestController
    public class HelloController {
        @Autowired
        private DataSource dataSource;
        @GetMapping("/hello")
        public String hello() throws SQLException {
            System.out.println(dataSource);
            System.out.println("这是处理器执行的方法");
            return "Hello Spring Boot" ;
        }
    }
    
    

    SpringBoot整合Mybatis

    SpringBoot启动器

    SpringBoot官方并没有提供Mybatis的启动器,不过Mybatis官网自己实现了。

    1.在项目的 pom.xml 文件中加入如下依赖:

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

    2. 配置 application.yml ,常用配置如下:

    mybatis:
      #指定实体包路径
      type-aliases-package: com.pjh.pojo
      # 映射文件路径
      #mapper-locations: classpath:mappers/*.xml
      #控制台输出执行sql
      configuration:
        log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    

    3. 配置Mapper扫描

    需要注意,这里没有配置mapper接口扫描包,因此我们需要给每一个Mapper接口添加 @Mapper 注解,才能被识别。

    package com.pjh.mapper;
    import org.apache.ibatis.annotations.Mapper;
    @Mapper
    public class UserMapper {
    }
    

    或者,我们也可以不加注解,而是在启动类上添加扫描包注解(推荐):

    package com.pjh;
    import org.mybatis.spring.annotation.MapperScan;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    /*springBott工程都有一个启动类,这是工程的入口类
    * 并在引导类上添加@SpringBootApplication注解
    * 会扫描到当前包及其子包下的所有注解
    * */
    @SpringBootApplication
    @MapperScan("com.pjh.mapper")
    public class Application {
        public static void main(String[] args) {
            SpringApplication.run(Application.class,args);
        }
    }
    
    

    以下代码示例中,我们将采用@MapperScan扫描方式进行。
    **

    通用mapper

    什么是通用mapper?

    通用mapper 可以极大的方便开发人员进行ORM,提供极其方便的单表增删改查。
    什么是通用mapper,一句话简单说,它就是个辅助mybatis极简单表开发的组件。它不是为了替代mybatis,而是让mybatis的开发更方便。
    可以按照自己的需要选择通用方法,还能很方便的开发自己的通用方法。

    为什么要用通用mapper?

    原生Mybatis的痛点

    1、mapper.xml文件里有大量的sql,当数据库表字段变动,配置文件就要修改
    2、需要自己实现sql分页,select * from table where . . . limit 1,3
    自己手写分页,除了传参page、pageSize,还需要返回条目总数count。
    3、数据库可移植性差:如果项目更换数据库,比如oracle-->mysql,mapper.xml中的sql要重新写,因为Oracle的PLSQL 和mysql 支持的函数是不同的。
    4、生成的代码量过大。
    5、批量操作,批量插入,批量更新,需要自写。

    使用通用mapper的步骤

    需要导入的jar包

     <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.1.5</version>
        </dependency>
    

    编写对应的实体类

    package com.pjh.pojo;
    
    import lombok.Data;
    import tk.mybatis.mapper.annotation.KeySql;
    
    import javax.persistence.Id;
    import javax.persistence.Table;
    import java.util.Date;
    
    /*代表生成getter setter方法*/
    @Data
    @Table(name = "tb_user")
    public class User {
        // id
        @Id
        //开启主键自动回填
        @KeySql(useGeneratedKeys = true)
        private Long id;
        // 用户名
        private String userName;
        // 密码
        private String password;
        // 姓名
        private String name;
        // 年龄
        private Integer age;
        // 性别,1男性,2女性
        private Integer sex;
        // 出生日期
        private Date birthday;
        // 创建时间
        private Date created;
        // 更新时间
        private Date updated;
        // 备注
        private String note;
    }
    
    

    编写通用mapper类

    package com.pjh.mapper;
    import com.pjh.pojo.User;
    import tk.mybatis.mapper.common.Mapper;
    public interface UserMapper extends Mapper<User> {
    }
    

    在启动类中添加扫描标签

    @MapperScan("mapper所在包的路径")
    

    在service类中使用对应的mapper接口

    @Autowired(required = false)
    private UserMapper userMapper;
    public User queryForId(int id){
       //使用id查询
        return userMapper.selectByPrimaryKey(id);
    }
    

    SpringBoot整合测试

    步骤1

    导入对应的jar包

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

    步骤二

    编写测试类

    package com.pjh.service;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    /*spring环境*/
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class UserServiceTest {
    
        @Test
        public void queryForId() {
        }
    
        @Test
        public void saveUser() {
        }
    }
    

    SpringBoot整合redis

    导入相关的jar包

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

    配置application.yml文件

    redis:
        #主机地址
        host: localhost
        #对应的端口号
        port: 6379
    

    编写测试类测试

    package com.pjh.redis;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.data.redis.core.RedisTemplate;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import java.util.List;
    import java.util.Set;
    
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class Redis {
        @Autowired
        private RedisTemplate redisTemplate;
    
        @Test
        public void test1(){
            /*各种数据类型的存取操作*/
            //string 字符串
            //redisTemplate.opsForValue().set("str", "heima");
            redisTemplate.boundValueOps("str").set("heima");
            System.out.println("str = " + redisTemplate.opsForValue().get("str"));
    
            //hash 散列
            redisTemplate.boundHashOps("h_key").put("name", "heima");
            redisTemplate.boundHashOps("h_key").put("age", 13);
            //获取所有域
            Set set = redisTemplate.boundHashOps("h_key").keys();
            System.out.println(" hash散列的所有域:" + set);
            //获取所有值
            List list = redisTemplate.boundHashOps("h_key").values();
            System.out.println(" hash散列的所有域的值:" + list);
    
            //list 列表
            redisTemplate.boundListOps("l_key").leftPush("c");
            redisTemplate.boundListOps("l_key").leftPush("b");
            redisTemplate.boundListOps("l_key").leftPush("a");
            //获取全部元素
            list = redisTemplate.boundListOps("l_key").range(0, -1);
            System.out.println(" list列表中的所有元素:" + list);
    
            // set 集合
            redisTemplate.boundSetOps("s_key").add("a", "b", "c");
            set = redisTemplate.boundSetOps("s_key").members();
            System.out.println(" set集合中的所有元素:" + set);
    
            // sorted set 有序集合
            redisTemplate.boundZSetOps("z_key").add("a", 30);
            redisTemplate.boundZSetOps("z_key").add("b", 20);
            redisTemplate.boundZSetOps("z_key").add("c", 10);
            set = redisTemplate.boundZSetOps("z_key").range(0, -1);
            System.out.println(" zset有序集合中的所有元素:" + set);
        }
    }
    
    

    测试结果

    在这里插入图片描述

    SpringBoot项目部署

    步骤1

    添加项目的pom.xml插件;在pom.xml要显式的加入插件spring-boot-maven-plugin,否则无法产生 jar 清单文件,导致打出来的 jar 无法使用命令运行;

    <build>
            <plugins>
                <!-- 打jar包时如果不配置该插件,打出来的jar包没有清单文件 -->
                <plugin>
                    <groupId>org.springframework.boot</groupId>
                    <artifactId>spring-boot-maven-plugin</artifactId>
                    <version>2.2.6.RELEASE</version>
                </plugin>
            </plugins>
        </build>
    

    步骤2

    使用maven的命令package打包;

    在这里插入图片描述

    步骤三

    之后在项目下的 target 目录中将有如下jar包:
    在这里插入图片描述

    在这里插入图片描述

    步骤四

    运行打出来的包;使用命令: java –jar 包全名 或者写一个 bat 文件,里面包含 java –jar 包全名;这样就可以双
    击启动应用。
    如执行上述打出来的jar的命令为:

    java -jar SpringBoot-1.0-SNAPSHOT.jar
    

    在这里插入图片描述

  • 相关阅读:
    Oracle 创建表并设置主键自增
    Oracle 基本知识回顾
    关于JAVAweb的一些东西
    JAVA获取运行环境的信息
    关于正则表达式的一些东西
    关于jQuery的一些东西
    关于JS的一些东西
    thymeleaf 的使用
    小程序flex容器
    Vue组件化
  • 原文地址:https://www.cnblogs.com/pjhaymy/p/14395018.html
Copyright © 2011-2022 走看看