SpringBoot(1) 概览

SpringBoot基础(1) 整体概览

概念与特性

  • 简化SSM开发过程
    • SSM需要配置 web.xml,配置 Spring,配置 MyBatis,整合等工作
    • Spring Boot采用大量默认配置以简化该过程
  • 特性:
    • 直接使用 java main 方法启动内嵌的 Tomcat 服务器运行 Spring Boot 程序,不需要部署 war 包文件
    • 提供约定的 starter POM 来简化 Maven 配置
    • 自动化配置
    • 提供程序的健康检查
    • 基本可以完全不使用 XML 配置文件,采用注解配置
  • 核心:
    • AutoConfigure 自动配置:针对很多Spring应用程序和常见的应用功能,Spring boot能自动提供相关配置
    • starter 起步依赖:告诉Spring boot需要什么功能,就能引入需要的依赖库
    • Actuator:监控插件,查看Spring boot程序的内部信息和各项运行指标
    • CLI 命令行界面:可选特性,针对Groovy脚本

案例

  • 创建一个 Module,选择 Spring Initializr,设置 GAV 坐标及 pom 配置信息,选择Spring Boot版本和依赖(会根据选择的依赖自动添加起步依赖并自动配置),项目结构如下

    image-20221030131142391
    • static:存放静态资源,如图片、CSS、JavaScript 等

    • templates:存放 Web 页面的模板文件

    • application.properties/application.yml:程序各种依赖模块的配置信息

    • .mvn|mvnw|mvnw.cmd:使用脚本操作执行 maven 相关命令

    • Application.java:SpringBoot 程序执行的入口——SpringBoot默认包扫描机制: 从启动类所在包开始,扫描当前包及其子级包下的所有文件,想自己制定包扫描路径就加@ComponentScan

    • pom.xml:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      <!--所有自己开发的 Spring Boot 都必须的继承-->
      <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.7.5</version>
      <relativePath/> <!-- lookup parent from repository -->
      </parent>
      <!--当前项目的 GAV 坐标-->
      <groupId>com</groupId>
      <artifactId>demo</artifactId>
      <version>0.0.1-SNAPSHOT</version>
      <name>demo</name>
      <description>Demo project for Spring Boot</description>
      <!--maven 属性配置,可以在其它地方通过${}方式进行引用-->
      <properties>
      <java.version>1.8</java.version>
      </properties>
      <dependencies>
      <!--SpringBoot 框架 web 项目起步依赖,通过该依赖自动关联其它依赖,不需要一个一个去添加-->
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
      <groupId>org.mybatis.spring.boot</groupId>
      <artifactId>mybatis-spring-boot-starter</artifactId>
      <version>2.2.2</version>
      </dependency>

      <dependency>
      <groupId>com.mysql</groupId>
      <artifactId>mysql-connector-j</artifactId>
      <scope>runtime</scope>
      </dependency>
      <!--SpringBoot 框架的测试起步依赖,例如:junit 测试-->
      <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-test</artifactId>
      <scope>test</scope>
      </dependency>
      </dependencies>

      <build>
      <plugins>
      <plugin>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
      </plugins>
      </build>
  • 新建一个controller(com.demo.Controller),运行main,访问url(因为还没有配置datasource,设置main中@SpringBootApplication(exclude= {DataSourceAutoConfiguration.class}))

    1
    2
    3
    4
    5
    6
    7
    8
    @Controller
    public class HelloController {
    @RequestMapping(value = "/springBoot/say")
    @ResponseBody
    public String say() {
    return "Hello,springBoot!";
    }
    }
    image-20221030135349723
    • 会启动一个内嵌的 tomcat,端 口号为 8080,上下文根为空:Tomcat started on port(s): 8080 (http) with context path ''
  • 案例分析

    • Spring Boot 的父级依赖 spring-boot-starter-parent 配置后,当前的项目就是 Spring Boot 项目

    • spring-boot-starter-parent提供相关的 Maven 默认依赖,常用的 jar 包依赖可以省去 version 配置,若要自定义某个依赖的版本,则在pom.xml中使用properties标记(例如,不使用maven默认导入的 <mysql.version>8.0.23</mysql.version>,自定义导入5.1.43版本)

      1
      2
      3
      <properties>
      <mysql.version>5.1.43</mysql.version>
      </properties>
    • @Controller 及 @ResponseBody 是 Spring MVC 的注解(该demo1为springboot集成springmvc的例子)

    • @SpringBootApplication 注解是 Spring Boot 项目的核心注解,主要作用是开启 Spring 自动配置

核心配置文件

  • 核心配置文件用于配置 Spring Boot 程序,名字必须以 application 开头

配置格式

.properties 文件

  • 默认采用该文件

  • 修改tomcat端口号和上下文文件根:

    1
    2
    3
    4
    #设置内嵌 Tomcat 端口号
    server.port=9090
    #配置项目上下文根
    server.servlet.context-path=/demo1-context-path

.yml 文件

  • 一种 yaml 格式的配置文件,采用一定的空格、换行等格式排版进行配置

    1
    2
    3
    4
    server:
    port: 9090
    servlet:
    context-path: /test
  • 基本语法:

    • key: value(值与冒号配置项必须要有一个空格)
    • 缩进表示层级关系(不用tab,只用空格,同级元素左对齐即可)
    • 字符串无需加引号,如果加,单双引号含义一致
  • 字面量(data、boolean、string、number、null):k: v

  • 对象:键值对的集合,如map、hash、object

    1
    2
    3
    4
    5
    6
    行内写法:  k: {k1:v1,k2:v2,k3:v3}
    #或
    k:
    k1: v1
    k2: v2
    k3: v3
  • 数组:

    1
    2
    3
    4
    5
    6
    行内写法:  k: [v1,v2,v3]
    #或者
    k:
    - v1
    - v2
    - v3
  • 例如:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Data
    public class Person {

    private String userName;
    private Boolean boss;
    private Date birth;
    private Integer age;
    private Pet pet;
    private String[] interests;
    private List<String> animal;
    private Map<String, Object> score;
    private Set<Double> salarys;
    private Map<String, List<Pet>> allPets;
    }

    @Data
    public class Pet {
    private String name;
    private Double weight;
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    # yaml表示以上对象
    person:
    userName: zhangsan
    boss: false
    birth: 2019/12/12 20:12:33
    age: 18
    pet:
    name: tomcat
    weight: 23.4
    interests: [篮球,游泳]
    animal:
    - jerry
    - mario
    score:
    english:
    first: 30
    second: 40
    third: 50
    math: [131,140,148]
    chinese: {first: 128,second: 136}
    salarys: [3999,4999.98,5999.99]
    allPets:
    sick:
    - {name: tom}
    - {name: jerry,weight: 47}
    health: [{name: mario,weight: 47}]
  • 两种格式配置文件同时存在,则使用 .properties 配置文件

多环境配置

  • 项目会经历很多的阶段(开发->测试->上线),每个阶段的配置也会不同

  • 为每个环境创建一个配置文件,命名必须为 application-环境标识.properties|yml,例如:

    1
    2
    3
    application-dev.properties # 开发环境核心配置文件
    application-product.properties # 生产环境核心配置文件
    application-test.properties # 测试环境核心配置文件
  • 激活:

    • 需要在总配置文件application.properties中激活环境

      1
      2
      3
      4
      5
      6
      #激活开发环境
      #spring.profiles.active=dev
      #激活测试环境
      #spring.profiles.active=test
      #激活生产环境
      spring.profiles.active=product
    • 需要在总配置文件application.yml中激活环境

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      #激活开发环境
      #spring:
      # profiles:
      # active: dev
      #激活测试环境
      #spring:
      # profiles:
      # active: test
      #激活生产环境
      spring:
      profiles:
      active: product

自定义配置

  • 除了内置的配置项以外,还可以采用如下注解去读取配置的属性值

@Value

  • 通过@Value注入单个属性、数组或者列表

  • 不通过配置文件注入

    • 注入普通字符串

      1
      2
      @Value("normal")
      private String normal;
    • 注入系统变量

      1
      2
      @Value("#{systemProperties['os.name']}")
      private String systemPropertiesName; // 注入操作系统属性
    • 注入表达式结果(在#{ } 里面写 SpEL 表达式)

      1
      2
      @Value("#{ T(java.lang.Math).random() * 100.0 }")
      private double randomNumber; //注入表达式结果
    • 注入url资源

      1
      2
      @Value("http://www.baidu.com")
      private Resource testUrl; // 注入URL资源
  • 通过配置文件注入

    • 配置文件中添加:

      1
      2
      school.name=abc
      web=http://www.baidu.com
    • 注入:

      1
      2
      3
      4
      @Value("${school.name}")
      private String schoolName;
      @Value("${websit}")
      private String websit;
    • 可设置注入属性的默认值(当配置文件中没有此key时,此默认值生效):@Value("${name:zch}")

    • 如果是读取map:

      1
      2
      3
      4
      5
      @Value("#{${a.b}}")
      private Map<String, Integer> checkSql;

      a.b.[a]=0
      a.b.[b]=1
  • 如果是自定义的my.properties文件,需要在某个类中通过@PropertySource引入该配置文件,而application.properties中的属性会自动被加载

@ConfigurationProperties

  • 将整个文件映射成一个对象,用于自定义配置项比较多的情况

  • @ConfigurationProperties需要和@Configuration配合使用,通常在一个POJO里配置

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Data  // 将@ToString、@EqualsAndHashCode、@Getter/@Setter和@RequiredArgsConstructor的功能捆绑在一起,需要安装Lombok插件
    @Configuration
    @PropertySource({"classpath:remote.properties"})
    @ConfigurationProperties(prefix = "mail")
    public class ConfigProperties {

    private String hostName;
    private int port;
    private String from;
    }
    • 此时,会读取所有以mail开头的属性,并和bean中的字段匹配

      1
      2
      3
      4
      #Simple properties
      mail.hostname=host@mail.com
      mail.port=9000
      mail.from=mailer@mail.com
    • 属性名字匹配支持很多格式,如下所示所有的格式都可以和hostName进行匹配

      1
      2
      3
      4
      5
      mail.hostName
      mail.hostname
      mail.host_name
      mail.host-name
      mail.HOST_NAME
    • 进一步的,使用这个config:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @RestController
      public class ConfigurationController {
      @Resource
      private RemoteConfig remoteConfig;
      @GetMapping
      public void getInfo() {
      System.out.println("地址:" + remoteConfig.getAddress());
      System.out.println("端口:" + remoteConfig.getPort());
      }
      }

常用的注解

  • @SpringBootApplication:可以把@SpringBootApplication看作是**@Configuration、@EnableAutoConfiguration、@ComponentScan**注解的集合

  • @ComponentScan:扫描被@Component(@Service,@Controller)注解的bean,注解默认会扫描该类所在的包下所有的类

  • @Configuration:允许在Spring上下文中注册额外的bean或导入其他配置类

  • @EnableAutoConfiguration:启用SpringBoot的自动配置机制

  • Bean相关:

    • @Autowired:自动导入对象到类中,自动装配,其作用是为了消除代码里的getter/setter与bean属性中的property
    • @Component,@Repository等:要想把类标识成可用于@Autowired注解自动装配的bean的类,使用这些注解实现
      • @Component :通用的注解,如果一个 Bean 不知道属于哪个层,可以使用@Component 注解标注
      • @Repository :对应持久层即 Dao 层,主要用于数据库相关操作
      • @Service : 对应服务层
      • @Controller : 对应 Spring MVC 控制层
    • @RestController:前后端分离时一般不用@Controller注解,而是使用@RestController注解。@RestController注解是@Controller和@ResponseBody的合集,表示这是个控制器 bean,将函数的返回值直接填入 HTTP 响应体中
    • @Scope:用在类上,声明Spring Bean的作用域
    • @Configuration:一般用来声明配置类,可以使用@Component注解替代
  • 处理常用的app请求

    • Get请求-@GetMapping:@GetMapping(“users”) 等价于@RequestMapping(value=”/users”,method=RequestMethod.GET)
    • Post请求-@PostMapping:@PostMapping(“users”) 等价于@RequestMapping(value=”/users”,method=RequestMethod.POST)
    • Put请求-@PutMapping:@PutMapping(“/users/{userId}”) 等价于@RequestMapping(value=”/users/{userId}”,method=RequestMethod.PUT)
    • Delete请求-@DeleteMapping:@DeleteMapping(“/users/{userId}”)等价于@RequestMapping(value=”/users/{userId}”,method=RequestMethod.DELETE)
    • Patch请求-@PatchMapping
  • 前后端传值:

    • @PathVariable和@RequestParam:@PathVariable用于获取路径参数,@RequestParam用于获取查询参数
    • @RequestBody:用于读取 Request 请求(可能是 POST,PUT,DELETE,GET 请求)的 body 部分,并且Content-Type 为 application/json 格式的数据,接收到数据之后会自动将数据绑定到 Java 对象上——一个请求方法只可以有一个@RequestBody,但是可以有多个@RequestParam@PathVariable
  • 读取配置信息

    • @value
    • @ConfigurationProperties
  • 参数校验

    • 验证参数:

      • @NotEmpty 被注释的字符串的不能为 null 也不能为空
      • @NotBlank 被注释的字符串非 null,并且必须包含一个非空白字符
      • @Null 被注释的元素必须为 null
      • @NotNull 被注释的元素必须不为 null
      • @AssertTrue 被注释的元素必须为 true
      • @AssertFalse 被注释的元素必须为 false
      • @Pattern(regex=,flag=)被注释的元素必须符合指定的正则表达式
      • @Email 被注释的元素必须是 Email 格式。
      • @Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
      • @Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
      • @DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
      • @DecimalMax(value) 被注释的元素必须是一个数字,其值必须小于等于指定的最大值
      • @Size(max=, min=)被注释的元素的大小必须在指定的范围内
      • @Digits (integer, fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
      • @Past被注释的元素必须是一个过去的日期
      • @Future 被注释的元素必须是一个将来的日期
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      @Data
      @AllArgsConstructor
      @NoArgsConstructor
      public class Person {
      @NotNull(message = "classId 不能为空")
      private String classId;

      @Size(max = 33)
      @NotNull(message = "name 不能为空")
      private String name;

      @Pattern(regexp = "((^Man$|^Woman$|^UGM$))", message = "sex 值不在可选范围")
      @NotNull(message = "sex 不能为空")
      private String sex;

      @Email(message = "email 格式不正确")
      @NotNull(message = "email 不能为空")
      private String email;
      }

      @RestController
      @RequestMapping("/api")
      public class PersonController {
      @PostMapping("/person")
      public ResponseEntity getPerson(@RequestBody @Valid Person person) {
      return ResponseEntity.ok().body(person);
      }
      }
    • 验证请求体:**@Valid**:在需要验证的参数上加上@Valid注解,如果验证失败,将抛出MethodArgumentNotValidException

    • 验证请求参数:在类上加上 Validated 注解

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      @RestController
      @RequestMapping("/api")
      @Validated
      public class PersonController {
      @GetMapping("/person/{id}")
      public ResponseEntity getPersonByID(
      @Valid
      @PathVariable("id")
      @Max(value = 5,message = "超过 id 的范围了")
      Integer id
      ) {
      return ResponseEntity.ok().body(id);
      }
      }
  • @Transactional:要开启事务的方法上使用@Transactional注解

  • JPA相关

    • @Entity:声明一个类对应一个数据库实体

    • @Table:设置表名

    • @Column :声明字段

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      @Entity
      @Table(name = "role")
      public class Role {
      @Id
      @GeneratedValue(strategy = GenerationType.IDENTITY)
      private Long id;
      private String name;
      private String description;
      省略getter/setter......
      }

      @Column(name = "user_name", nullable = false, length=32)
      private String userName;
    • @Transient :声明不需要与数据库映射的字段,在保存的时候不需要保存进数据库

  • 注入组件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    #############################Configuration使用示例######################################################
    /**
    * 1、配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
    * 2、配置类本身也是组件
    * 3、proxyBeanMethods:代理bean的方法
    * Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
    * Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
    * 组件依赖必须使用Full模式默认。其他默认是否Lite模式
    *
    *
    *
    */
    @Configuration(proxyBeanMethods = false) //告诉SpringBoot这是一个配置类 == 配置文件
    public class MyConfig {

    /**
    * Full:外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
    * @return
    */
    @Bean //给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
    public User user01(){
    User zhangsan = new User("zhangsan", 18);
    //user组件依赖了Pet组件
    zhangsan.setPet(tomcatPet());
    return zhangsan;
    }

    @Bean("tom")
    public Pet tomcatPet(){
    return new Pet("tomcat");
    }
    }


    ################################@Configuration测试代码如下########################################
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan("com.boot")
    public class MainApplication {

    public static void main(String[] args) {
    //1、返回我们IOC容器
    ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);

    //2、查看容器里面的组件
    String[] names = run.getBeanDefinitionNames();
    for (String name : names) {
    System.out.println(name);
    }

    //3、从容器中获取组件

    Pet tom01 = run.getBean("tom", Pet.class);

    Pet tom02 = run.getBean("tom", Pet.class);

    System.out.println("组件:"+(tom01 == tom02));


    //4、com.boot.config.MyConfig
    MyConfig bean = run.getBean(MyConfig.class);
    System.out.println(bean);

    //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
    //保持组件单实例
    User user = bean.user01();
    User user1 = bean.user01();
    System.out.println(user == user1);


    User user01 = run.getBean("user01", User.class);
    Pet tom = run.getBean("tom", Pet.class);

    System.out.println("用户的宠物:"+(user01.getPet() == tom));
    }
    }
  • 配置文件引入(xml)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    ======================beans.xml=========================
    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="haha" class="com.boot.bean.User">
    <property name="name" value="zhangsan"></property>
    <property name="age" value="18"></property>
    </bean>

    <bean id="hehe" class="com.boot.bean.Pet">
    <property name="name" value="tomcat"></property>
    </bean>
    </beans>
    1
    2
    3
    4
    5
    6
    7
    8
    @ImportResource("classpath:beans.xml")
    public class MyConfig {}

    ======================测试=================
    boolean haha = run.containsBean("haha");
    boolean hehe = run.containsBean("hehe");
    System.out.println("haha:"+haha);//true
    System.out.println("hehe:"+hehe);//true

Web开发

集成MyBatis

  • 例如,通过 SpringBoot +MyBatis 实现对emp表的查询操作

    • 配置properties文件:

      • datasource:

        1
        2
        3
        4
        spring.datasource.driver-class-name=com.mysql.jdbc.Driver
        spring.datasource.url=jdbc:mysql://localhost:3306/testMyBatis?characterEncoding=utf8
        spring.datasource.username=root
        spring.datasource.password=123456
      • mybatis:

        1
        2
        mybatis.mapper-locations=classpath:mappers/*.xml
        mybatis.configuration.map-underscore-to-camel-case=true
    • 创建实体类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      package com.demo.Pojo;

      import java.io.Serializable;

      public class Emp implements Serializable {
      private Integer id;
      private String name;
      private String job;
      private Double salary;

      // getter、setter、toString
      }
    • 创建mapper接口

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      package com.demo.Mapper;

      import java.util.List;

      import com.demo.Pojo.Emp;
      import org.apache.ibatis.annotations.Mapper;

      @Mapper
      public interface EmpMapper {
      // 查询所有的用户信息
      List<Emp> findAll();
      }
      • mapper 接口较多时,可以在 Spring Boot 主启动类上使用 @MapperScan 注解扫描指定包下的 mapper 接口(属性为basePackages),而非在每个 mapper 接口上都标注 @Mapper
    • 创建映射文件

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      <?xml version="1.0" encoding="UTF-8"?>
      <!DOCTYPE mapper
      PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
      "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

      <mapper namespace="com.demo.Mapper.EmpMapper">
      <cache flushInterval="60"/>
      <select id="findAll" resultType="com.demo.Pojo.Emp">
      select * from Emp
      </select>
      </mapper>
    • 测试:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      package com.demo;

      import com.demo.Mapper.EmpMapper;
      import org.junit.jupiter.api.Test;
      import org.mybatis.spring.annotation.MapperScan;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.boot.test.context.SpringBootTest;

      @SpringBootTest
      @MapperScan("com.demo.Mapper") // 扫描mapper接口类在的包
      class DemoApplicationTests {

      @Autowired
      private EmpMapper empMapper;

      @Test
      void testMapper() {
      System.out.println(empMapper.findAll());
      }
      }
  • 注解方式:针对实际业务中使用最多的“增删改查”操作,提供注解@Select、@Insert、@Update、@Delete——接口中的任何一个方法只能使用一种配置方式,但不同方法之间,这两种方式则可以混合使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    @Mapper
    public interface UserMapper {
    @Select("select * from user where user_name = #{userName,jdbcType=VARCHAR} and password = #{password,jdbcType=VARCHAR}")
    List<User> getByUserNameAndPassword(User user);

    @Delete("delete from user where id = #{id,jdbcType=INTEGER}")
    int deleteByPrimaryKey(Integer id);

    @Insert("insert into user ( user_id, user_name, password, email)" +
    "values ( #{userId,jdbcType=VARCHAR}, #{userName,jdbcType=VARCHAR}, #{password,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR})")
    int insert(User record);

    @Update(" update user" +
    " set user_id = #{userId,jdbcType=VARCHAR},\n" +
    " user_name = #{userName,jdbcType=VARCHAR},\n" +
    " password = #{password,jdbcType=VARCHAR},\n" +
    " email = #{email,jdbcType=VARCHAR}\n" +
    " where id = #{id,jdbcType=INTEGER}")
    int updateByPrimaryKey(User record);
    }

事务支持

  • 底层依然采用 Spring 本身提供的事务管理
  • 入口类(主启动类)中用注解 @EnableTransactionManagement 开启事务支持
  • 在访问数据库的 Service 方法上添加注解 @Transactional

SpringMVC

  • Spring Boot 下的 Spring MVC 和之前的 Spring MVC 使用是完全一样的
  • 主要的注解包括: @Controller、@RestController(不能跳转页面, 只能返回字符串或者 json 数据)、@RequestMapping、@GetMapping、@PostMapping、@PutMapping、@DeleteMapping

Spring Boot 实现 RESTful

  • REST:如果一个架构符合 REST 原则,称它为 RESTFul 架构

    • http://localhost:8080/boot/order?id=1021&status=1
    • RESTFul风格:http://localhost:8080/boot/order/1021/1
  • 通过几个注解来实现:

    • @PathVariable:获取url数据,是实现 RESTFul 最主要的一个注解

    • 四个Mapping注解

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      @RestController
      /**/
      @PostMapping(value = "/springBoot/student/{name}/{age}")
      public Object addStudent(@PathVariable("name") String name,
      @PathVariable("age") Integer age) {
      Map<String,Object> retMap = new HashMap<String, Object>();
      retMap.put("name",name);
      retMap.put("age",age);
      return retMap;
      }
  • 如果发生请求冲突,则可以改路径,或者改请求方式

  • RESTFul 原则

    • 请求路径不要出现动词
      • /boot/order/1021/1(推荐),/boot/queryOrder/1021/1(不推荐)
    • 分页、排序等操作,不需要使用斜杠传参数
    • 客户端使用GET、POST、PUT、DELETE4个表示操作方式的动词对服务端资源进行操作
    • 资源的表现形式是XML或者HTML

集成 Redis

  • 完善集成MyBatis的例子。根据Id查询Emp,先从redis中找,如果没有再找mysql,放到redis中

  • 添加redis起步依赖(Jedis是Redis官方推荐的面向Java操作Redis的客户端开发Jar包;RedisTemplate是Spring对Jedis API的高度封装)

    • Jedis:Redis的Java连接开发工具,本质是定义一个tcp连接,然后使用socket技术进行通信。每次操作新创建一个Jedis对象,执行完毕后关闭连接释放对象,对应的就是一次tcp连接,多线程环境下非线程安全,除非使用连接池
    • jedisPool:
      • 创建时初始化一些连接资源存储到连接池中,使用Jedis连接资源时不需要创建,而是从连接池中获取一个资源进行Redis的操作,使用完毕后,不需要销毁该Jedis连接资源,而是将该资源归还给连接池,供其他请求使用,避免了频繁创建socket连接
      • 可以把JedisPool理解成项目中的数据库连接池,例如:阿里巴巴的druid
    • spring-data-redis(RedisTemplate)
      • 默认提供了两个使用Redis的类:StringRedisTemplate和RedisTemplate
        • RedisTemplate支持Redis没有的缓存对象的操作
        • StringRedisTemplate用来存储字符串
    • SpringBoot 2.0已经使用Lettuce代替Jedis
  • 核心配置文件:

    1
    2
    3
    4
    #配置 redis 连接信息
    spring.redis.host=192.168.92.134
    spring.redis.port=6379
    spring.redis.password=123456
  • 相关的Service:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    @Service
    public class RedisService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private EmpMapper empMapper;

    public List<Emp> queryAllEmp() {
    //设置 redisTemplate 对象 key 的序列化方式
    redisTemplate.setKeySerializer(new StringRedisSerializer());

    List<Emp> res = (List<Emp>) redisTemplate.opsForValue().get("allEmp");
    //判断是否为空
    if (null == res) {
    //去数据库查询,并存放到 redis 缓存中
    res = empMapper.findAll();

    System.out.println("update redis");

    redisTemplate.opsForValue().set("allEmp", res,15,
    TimeUnit.SECONDS);
    }
    return res;
    }
    }
    • 这里,Autowired注解在IDEA中会报错,但依然能够运行,建议改为Resource注解
  • Pojo类实现序列化接口

拦截器

  • 以一个登录拦截器为例

  • 实现一个拦截器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class UserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler) throws Exception {
    System.out.println("--------编写拦截规则-------");
    //编写拦截规则
    //true:通过
    //false:不通过
    //从 session 中获取结果
    Integer code = (Integer) request.getSession().getAttribute("code");
    if (null == code) {
    response.sendRedirect(request.getContextPath() + "/user/error");
    return false;
    }
    return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response,
    Object handler, ModelAndView modelAndView) throws Exception {
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response,
    Object handler, Exception ex) throws Exception {
    }
    }
  • 定义配置类

    • 创建一个 config 包,创建一个配置类 InterceptorConfig 并实现接口 WebMvcConfigurer,覆盖接口方法 addInterceptors

    • 标注@Configuration注解,以被扫描到

    • 以上操作相当于MVC的注册拦截器,而@Configuration相当于一个applicationContext-mvc.xml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      @Configuration //用于定义配置类,可替换 xml 文件;定义一个拦截器,相当于之前的 mvc 里的配置
      public class InterceptorConfig implements WebMvcConfigurer {
      @Override
      public void addInterceptors(InterceptorRegistry registry) {
      //定义需要拦截的路径
      String[] addPathPatterns = {
      "/user/**",
      };
      //定义不需要拦截的路径
      String[] excludePathPatterns = {
      "/user/error",
      "/user/verifyRealName"
      };
      registry.addInterceptor(new UserInterceptor()) //添加要注册的拦截器对象
      .addPathPatterns(addPathPatterns) //添加需要拦截的路径
      .excludePathPatterns(excludePathPatterns); //添加不需要拦截的路径
      }
      }

    字符编码过滤器

    • 方法一:使用Spring提供的字符编码过滤器

    • 方法二:

      • 配置文件:

        1
        2
        3
        4
        5
        #编码格式
        spring.http.encoding.force=true
        spring.http.encoding.charset=UTF-8
        spring.http.encoding.enabled=true
        server.tomcat.uri-encoding=UTF-8