# 快速开发

很方便的开发框架,只需要很少的配置,提供一站式 starter 依赖项,简化 maven 配置,内置 tomcat,没有 xml 配置要求,大幅度提高开发效率。

这么爽的开发框架,几乎是傻瓜式上手即用,所以会用点框架是拿不上台面的。我们更应该注重基础,以及算法,不要过多沉迷于框架。

# 新建项目

几乎不用选择什么,新建项目选择 Spring Initializr 如果是 web 项目,勾选上 spring web 就差不多了(小辣椒也可以选,毕竟真的很方便):

进去之后就会看到启动类,该类有 @SpringBootApplication 注解, springboot 项目启动时,会通过启动类去 "扫描" 其他的类,所以我们写的 service 类,controller 类不能放在启动类的父目录,只能放在同级目录或同级目录的子目录里面

现在你可以什么都不写,直接 run,也不会报错(没有配置文件默认就是 8080 端口)。

# 整合 web 框架

配置文件:可以是 .properties 文件,也可以是 .yml 文件,区别只是两个文件内容书写格式不同,前者通过 . 引用,后者通过缩进。

# mybatis

导入依赖:

<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
</dependency>

resource 目录配置文件指定数据源(我这里用的就是.yaml 文件):

spring:
  datasource:
    url: jdbc:mysql://localhost:3306
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

starter 会自动扫描项目中 @Mapper 注解的接口,注册为 Bean,不需要任何配置:

@Mapper
public interface MainMapper {
    @Select("select * from users where username = #{username}")
    UserData findUserByName(String username);
}

SpringBoot 会自动为 Mybatis 配置数据源,默认使用的就是 HikariCP 数据源。

# Thymeleaf

导入依赖:

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

然后直接用就可以了

@RequestMapping("/index")
public String index(){
    return "index";
}

html 文件放在 template 目录下,css,js 文件放在 static 目录下,甚至你可能还特意分了一下 css 目录之类的,所以我们愮在配置文件中指定一下静态资源的访问前缀:

spring:
	mvc:
  	static-path-pattern: /static/**

# 日志

先了解两个概念:

  • 日志实现:之前学习的 JUL 其实就是日志实现,实现了具体细节和操作。

  • 日志门面:如 Slf4j,把不同日志系统实现进行具体的抽象化,只提供统一的日志使用接口,使用时直接调用接口即可。但是最终日志实现的格式,输出方式等需要绑定具体日志系统来实现。

Springboot 为了统一日志框架,做了以下的事情:

  1. 将其他依赖以前的日志框架剔除。
  2. 导入对应日志框架的 Slf4j 中间包。
  3. 导入自己官方指定的日志实现。

可以选择 Logback 日志框架:

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

# Redis

你需要有一些 redis 的预备知识

# Java 与 Redis 交互

需要用到 Jedis 框架,实现 Java 与 Redis 数据库的交互

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>4.0.0</version>
</dependency>

最基本的操作(前提是启动 redis 服务器)

public static void main(String[] args) {
    // 创建 Jedis 对象
    Jedis jedis = new Jedis("localhost", 6379);
  	
  	// 使用之后关闭连接
  	jedis.close();
}

之后就是通过 Jedis 调用命令的同名方法来执行 redis 命令:

try(Jedis jedis = new Jedis("192.168.10.3", 6379)){
    jedis.set("test", "lbwnb");   // 等同于 set test lbwnb 命令
    System.out.println(jedis.get("test"));  // 等同于 get test 命令
}

# SpringBoot 整合 Redis

对应依赖,该依赖底层没有使用 Jedis ,而是 Lettuce

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

starter 提供的默认配置会去连接本地的 Redis 服务器,并使用 0 号数据,也可以手动修改:

spring:
  redis:
  	#Redis 服务器地址
    host: 192.168.10.3
    #端口
    port: 6379
    #使用几号数据库
    database: 0

starter 已经提供了两个默认的模板类: RedisTemplateSteingRedisTemplate ,我们可以直接注入这两个类使用:

@SpringBootTest
class SpringBootTestApplicationTests {
    @Resource
    StringRedisTemplate template;
    @Test
    void contextLoads() {
        ValueOperations<String, String> operations = template.opsForValue();
        operations.set("c", "xxxxx");   // 设置值
        System.out.println(operations.get("c"));   // 获取值
      	
        template.delete("c");    // 删除键
        System.out.println(template.hasKey("c"));   // 判断是否包含键
    }
}

所有的值的操作都被封装到了 ValueOperations 对象中,而普通的键操作直接通过模板对象就可以使用了,大致使用方式其实和 Jedis 一致。

事务管理:Spring 没有专门的 Redis 事务管理,可以借助 JDBC 的:

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

然后在配置文件中配置一下 datasource

spring:
  datasource:
    url: jdbc:mysql://localhost:3306:study
    username: root
    password: 123456

就可以写 service 了:

@Service
public class RedisService {
    @Resource
    StringRedisTemplate template;
    // 构造,注入后调用该方法
    @PostConstruct
    public void init(){
        template.setEnableTransactionSupport(true);   // 需要开启事务
    }
    @Transactional    // 需要添加此注解
    public void test(){
        template.multi();
        template.opsForValue().set("d", "xxxxx");
        template.exec();
    }
    
    // 也可以将对象存进去,1. 使用序列化 2. 使用 json,需要导入 Jaskson 依赖
    // 使用 json,还需要设置一下
    // template.setValueSerializer(new Jaskson2JsonRedisSerializer<>(Object.class))
    @Test
    void contextLoad2() {
        // 注意 Student 需要实现序列化接口才能存入 Redis
        template.opsForValue().set("student", new Student());
        System.out.println(template.opsForValue().get("student"));
    }
}

# Redis 用作缓存

在项目中,将 Redis 作为 Mybatis 的二级缓存,Mybatis 自带的二级缓存的缺点在于是 Mapper 级别的,对于多台服务器连接,各自二级缓存是隔离的,之前讲 Mybatis 的时候也提到过。

我们需要手动实现 Mybatis 提供的 Cache 接口,直接给代码了:

// 实现 Mybatis 的 Cache 接口
public class RedisMybatisCache implements Cache {
    private final String id;
    private static RedisTemplate<Object, Object> template;
   	// 注意构造方法必须带一个 String 类型的参数接收 id
    public RedisMybatisCache(String id){
        this.id = id;
    }
  	// 初始化时通过配置类将 RedisTemplate 给过来
    public static void setTemplate(RedisTemplate<Object, Object> template) {
        RedisMybatisCache.template = template;
    }
    @Override
    public String getId() {
        return id;
    }
    @Override
    public void putObject(Object o, Object o1) {
      	// 这里直接向 Redis 数据库中丢数据即可,o 就是 Key,o1 就是 Value,60 秒为过期时间
        template.opsForValue().set(o, o1, 60, TimeUnit.SECONDS);
    }
    @Override
    public Object getObject(Object o) {
      	// 这里根据 Key 直接从 Redis 数据库中获取值即可
        return template.opsForValue().get(o);
    }
    @Override
    public Object removeObject(Object o) {
      	// 根据 Key 删除
        return template.delete(o);
    }
    @Override
    public void clear() {
      	// 由于 template 中没封装清除操作,只能通过 connection 来执行
				template.execute((RedisCallback<Void>) connection -> {
          	// 通过 connection 对象执行清空操作
            connection.flushDb();
            return null;
        });
    }
    @Override
    public int getSize() {
      	// 这里也是使用 connection 对象来获取当前的 Key 数量
        return template.execute(RedisServerCommands::dbSize).intValue();
    }
}

缓存类编写完成后,我们接着来编写配置类(Spring):

@Configuration
public class MainConfiguration {
    @Resource
    RedisTemplate<Object, Object> template;
    @PostConstruct
    public void init(){
      	// 把 RedisTemplate 给到 RedisMybatisCache
        RedisMybatisCache.setTemplate(template);
    }
}

在 Mapper 直接使用即可:

// 只需要修改缓存实现类 implementation 为我们的 RedisMybatisCache 即可
@CacheNamespace(implementation = RedisMybatisCache.class)
@Mapper
public interface MainMapper {
	
    // 会将查询结果放到 redis 里面
    @Select("select name from student where sid = 1")
    String getSid();
}

# 多环境配置

写好多个环境的配置文件,进行自由切换。

SpringBoot 只会读取 application.properties 或者 application.yml 文件,所以要实现自由切换,需要在配置文件中指定:

spring:
  profiles:
    active: dev

这样就会读取 application-dev.yml 配置文件。

# 参考

https://www.yuque.com/qingkongxiaguang/spring/xzo445