SpringBoot基础

今日内容

  • SpringBoot快速入门
  • SpringBoot自动配置原理
  • SpringBoot实践
    • 整合jdbc
    • 整合mvc
    • 整合mybatis

第一章 了解SpringBoot

在这一部分,我们主要了解以下3个问题:

  • 什么是SpringBoot springboot是一种快速使用spring框架的简便的方式
  • 为什么要学习SpringBoot
  • SpringBoot的特点

1.什么是SpringBoot

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

60410542187

我们可以看到下面的一段介绍:

Takes an opinionated view of building production-ready Spring applications. Spring Boot favors convention over configuration and is designed to get you up and running as quickly as possible.

翻译一下:

用一些固定的方式来构建生产级别的spring应用。Spring Boot 推崇约定大于配置的方式以便于你能够尽可能快速的启动并运行程序。

其实人们把Spring Boot 称为搭建程序的脚手架。其最主要作用就是帮我们快速的构建庞大的spring项目,并且尽可能的减少一切xml配置,做到开箱即用,迅速上手,让我们关注与业务而非配置。

2.为什么要学习SpringBoot

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

  • 复杂的配置

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

  • 一个是混乱的依赖管理

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

而SpringBoot让这一切成为过去!

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

我们可以使用SpringBoot创建java应用,并使用java –jar 启动它,就能得到一个生产级别的web工程。

3.SpringBoot的特点

Spring Boot 主要目标是:

  • 为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验 ,springboot是一种快速使用spring框架的简便的方式

  • 开箱即用(启动器starter-其实就是SpringBoot提供的一个jar包),但通过自己设置参数(.properties或yml),即可快速摆脱这种方式。

  • 提供了一些大型项目中常见的非功能性特性,如内嵌服务器、安全、指标,健康检测、外部化配置等

  • 绝对没有代码生成,也无需 XML 配置。

更多细节,大家可以到官网查看。

第二章 快速入门(重要)

接下来,我们就来利用SpringBoot搭建一个web工程,体会一下SpringBoot的魅力所在!

需求:浏览器输入一个地址,返回一句话

1.创建工程

我们先新建一个空的工程springboot_day01

2.添加依赖

看到这里很多同学会有疑惑,前面说传统开发的问题之一就是依赖管理混乱,怎么这里我们还需要管理依赖呢?难道SpringBoot不帮我们管理吗?

别着急,现在我们的项目与SpringBoot还没有什么关联。SpringBoot提供了一个名为spring-boot-starter-parent的工程,里面已经对各种常用依赖(并非全部)的版本进行了管理,我们的项目需要以这个项目为父工程,这样我们就不用操心依赖的版本问题了,需要什么依赖,直接引入坐标即可!

2.1.添加父工程坐标
<!--所有的springboot构建的项目,都需要继承如下父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>
2.2.添加web启动器

为了让SpringBoot帮我们完成各种自动配置,我们必须引入SpringBoot提供的自动配置依赖,我们称为启动器。因为我们是web项目,这里我们引入web启动器:

<!--添加依赖-->
<dependencies>
<!-- 不需要在单独指定jar包版本 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>

需要注意的是,我们并没有在这里指定版本信息。因为SpringBoot的父工程已经对版本进行了管理了。

这个时候,我们会发现项目中多出了大量的依赖:

1525486980765

这些都是SpringBoot根据spring-boot-starter-web这个依赖自动引入的,而且所有的版本都已经管理好,不会出现冲突。

2.3.完整pom
<?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>

<groupId>cn.itcast</groupId>
<artifactId>springboot_day01</artifactId>
<version>1.0-SNAPSHOT</version>

<!--所有的springboot构建的项目,都需要继承如下父工程 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
</parent>

<!--添加依赖-->
<dependencies>
<!-- 不需要在单独指定jar包版本 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>


</project>

3.启动类或引导类

Spring Boot项目通过main函数即可启动,我们需要创建一个启动类:启动类的名称可以任意

然后编写main函数:

package cn.itcast;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* @description: springBoot启动类,引导类
* @author: mryhl
* @date: Created in 2020/10/31 17:24
* @version: 1.1
* @SpringBootApplication 表明当前类是引导类
*/
@SpringBootApplication
public class ApplicationContext {

public static void main(String[] args) {
SpringApplication.run(ApplicationContext.class,args);

}
}

4.编写controller

接下来,我们就可以像以前那样开发SpringMVC的项目了!

我们编写一个controller:

alt

代码:

package cn.itcast.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController //相当于 @Controller+ @ResponseBody
public class HelloController {

//@RequestMapping(value = "/hello",method = RequestMethod.GET)
@GetMapping("/hello")
public String hello(){
System.out.println("访问到了HelloController中的hello方法");
return "欢迎来到神奇的springboot项目中";
}
}

5.启动测试

接下来,我们运行main函数,查看控制台,并且可以看到监听的端口信息:

alt

第三章 Java配置

在入门案例中,我们没有任何的配置,就可以实现一个SpringMVC的项目了,快速、高效!

但是有同学会有疑问,如果没有任何的xml,那么我们如果要配置一个Bean该怎么办?

1.回顾历史

事实上,在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,不过似乎在国内并未推广盛行。然后当SpringBoot来临,人们才慢慢认识到java配置的优雅。

有句古话说的好:拥抱变化,拥抱未来。所以我们也应该顺应时代潮流,做时尚的弄潮儿,一起来学习下java配置的玩法。

2.spring纯注解基本知识

先演示之前学习到的如何从properties配置文件中取值

然后再学习SpringBoot如何从properties配置文件中取值

java配置主要靠java类和一些注解,比较常用的注解有:

  • @Configuration:声明一个类作为配置类,代替xml文件
  • @Bean:声明在方法上,将方法的返回值加入Bean容器,代替<bean>标签
  • @Value:属性注入
  • @PropertySource:指定外部属性文件
  • ==@ComponentScan==:包扫描注解 相当于context:component-scan

需求:定义一个简单的User类,定义配置文件,User对象中的属性值从配置文件中获取

导入lombok相关jar包

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

User类如下:

在cn.itcast.pojo包下创建一个User类

package cn.itcast.pojo;

import lombok.Data;

/**
* @description:
* @author: mryhl
* @date: Created in 2020/10/31 17:34
* @version: 1.1
*/
@Data
public class User {
private String username;
private String password;
private Integer age;
}

3 @Value方式

第一步:在resources下创建一个user.properties文件,里面的内容如下:

user.username=zhangsan
user.password=123
user.age=19

第二步:在cn.itcast.config包下创建一个配置类,并使用@Configuration声明是一个配置类,在配置类中创建User对象

package cn.itcast.config;

import cn.itcast.pojo.User;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;

/**
* @description:
* @author: mryhl
* @date: Created in 2020/10/31 17:38
* @version: 1.1
* @Configurable 表示这个类是一个配置类
*/
@Configurable
@PropertySource("classpath:user.properties")
public class SpringConfig {
@Value("${user.username}")
private String username;
@Value("${user.password}")
private String password;
@Value("${user.age}")
private Integer age;
/**
* @author mryhl
* 将user对象交给spring的IOC容器
*/
@Bean
public User user(){
User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setAge(age);
return user;
}
}

第三步:测试

在HelloController中添加一个方法,验证User中是否有值

@Autowired
private User user;

@GetMapping("/user")
public User user(){
System.out.println("访问到了HelloController中user方法");
return user;
}

alt

4 Environment获取数据方式(了解)

spring中的Environment用来表示整个应用运行时的环境,可以使用Environment获取整个运行环境中的配置信息:方法是:environment.getProperty(配置文件中的key),返回的一律都是字符串,可以根据需要转换。

package cn.itcast.config;

import cn.itcast.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.core.env.Environment;

@Configuration //配置类
@PropertySource("classpath:user.properties")
public class SpringConfig {
@Autowired
private Environment environment;

@Bean //将user对象交给spring的IOC容器
public User user(){
String username = environment.getProperty("user.username");
String password = environment.getProperty("user.password");
Integer age = Integer.parseInt(environment.getProperty("user.age"));

User user = new User();
user.setUsername(username);
user.setPassword(password);
user.setAge(age);
return user;
}

}

5 @ConfigurationProperties方式

spring约定的、非常简洁的配置方式

首先约定,配置信息需要写在一个application.properties的文件中

第一步:在resources中创建一个application.properties文件,文件内容如下(和user.properties中的内容一样):

user.username=lisi1
user.password=123456
user.age=21

第二步:修改配置类如下:

package cn.itcast.config;

import cn.itcast.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

@Configuration //配置类

public class SpringConfig {

@Bean
@ConfigurationProperties(prefix = "user")
public User user(){
User user = new User();
return user;
}

}

第三步:测试仍然可以获取数据,很神奇!

alt

分析:要想简单的获取值,条件是User类中的属性名称和配置文件中的key名称是要一致的!!

6 SpringBoot支持的配置文件说明

6.1 yaml&yml

​ 配置文件除了可以使用application.properties类型,还可以使用后缀名为:.yml或者.yaml的类型,也就是:application.yml或者application.yaml

1531284020457

yml和yaml基本格式是一样的:

user:
username: yhlbxws
password: 231412
age: 25

alt

yml 和yaml 比properties 强大的是可以在配置文件中定义一个数组或集合

如果项目中同时有application.properties 和application.yml时 优先加载的是application.properties

举例如下:

第一步:在User类中添加3个属性,

package cn.itcast.pojo;

import lombok.Data;

import java.util.List;

@Data
public class User {
private String username;
private String password;
private Integer age;

private List<String> list;
private String[] array;
private List<User> userList;
}

第二步:在application.yml或application.yaml中添加如下配置

user:
username: wangwu
password: 654321
age: 18
list:
- 迪丽热巴
- 古力娜扎
- 巴尔扎哈
array:
- 迪丽热巴1
- 古力娜扎1
- 巴尔扎哈1
userList[0]:
username: 迪丽热巴2
password: 123
age: 18
userList[1]:
username: 古力娜扎2
password: 123456
age: 20

第三步:测试

alt

我们在研究SpringBoot原理的方向:SpringBoot是如何加载对象

第四章 自动配置原理

使用SpringBoot之后,一个整合了SpringMVC的WEB工程开发,变的无比简单,那些繁杂的配置都消失不见了,这是如何做到的?

一切魔力的开始,都是从我们的main函数来的,所以我们再次来看下启动类:

1525488044650

我们发现特别的地方有两个:

  • 注解:@SpringBootApplication
  • run方法:SpringApplication.run()

我们分别来研究这两个部分。

1.了解@SpringBootApplication

点击进入,查看源码:

1525488226710

这里重点的注解有3个:

  • @SpringBootConfiguration
  • @EnableAutoConfiguration
  • @ComponentScan
@Target(ElementType.TYPE) 注解在什么位置生效  ElementType.TYPE代表在类上
@Retention(RetentionPolicy.RUNTIME) 什么时候生效 运行时生效
@Documented 是否能生成api文档
@Inherited 是否能被继承
1.1.@SpringBootConfiguration

我们继续点击查看源码:

1525488518514

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

1.2.@EnableAutoConfiguration

关于这个注解,官网上有一段说明:

The second class-level annotation is @EnableAutoConfiguration. This annotation
tells Spring Boot to “guess” how you want to configure Spring, based on the jar
dependencies that you have added. Since spring-boot-starter-web added Tomcat
and Spring MVC, the auto-configuration assumes that you are developing a web
application and sets up Spring accordingly.

简单翻译以下:

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

总结,SpringBoot内部对大量的第三方库或Spring内部库进行了默认配置,这些配置是否生效,取决于我们是否引入了对应库所需的依赖,如果有那么默认配置就会生效。

所以,我们使用SpringBoot构建一个项目,只需要引入所需框架的依赖,配置就可以交给SpringBoot处理了。除非你不希望使用SpringBoot的默认配置,它也提供了自定义配置的入口。

1.3.@ComponentScan

我们跟进源码:

1525498265579

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

1525498351385

大概的意思:

配置组件扫描的指令。提供了类似与<context:component-scan>标签的作用

通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包

而我们的@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。

2.默认配置原理

2.1.spring.factories

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

1533684134317

跟进去:

1533684245960

这里发现会通过loadFactoryNames尝试加载一些FactoryName,然后利用createSpringFactoriesInstances将这些加载到的类名进行实例化。

继续跟进loadFactoryNames方法:

1533684398745

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

1533684452698

可以发现,其地址是:META-INF/spring.factories,我们知道,ClassLoader默认是从classpath下读取文件,因此,SpringBoot会在初始化的时候,加载所有classpath:META-INF/spring.factories文件,包括jar包当中的。

而在Spring的一个依赖包:spring-boot-autoconfigure中,就有这样的文件:

1533684761902

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

2.1默认配置类

我们打开刚才的spring.factories文件:

1533684789998

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

1525499397690

还有:

1525499426598

非常多,几乎涵盖了现在主流的开源框架,例如:

  • redis
  • jms
  • amqp
  • jdbc
  • jackson
  • mongodb
  • jpa
  • solr
  • elasticsearch

… 等等

我们来看一个我们熟悉的,例如SpringMVC,查看mvc 的自动配置类:

1525499859426

打开WebMvcAutoConfiguration:

1525500000816

我们看到这个类上的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的类,那么这个默认配置就会失效!

接着,我们查看该类中定义了什么:

视图解析器:

1525500405278

处理器适配器(HandlerAdapter):

1525500452517

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

2.2.默认配置属性

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

1525500697391

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

我们查看这两个属性类:

1525500810914

找到了内部资源视图解析器的prefix和suffix属性。

ResourceProperties中主要定义了静态资源(.js,.html,.css等)的路径:

1525500921773

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

3.总结

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

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

  • 这些类都声明了@Configuration注解,并且通过@Bean注解提前配置了我们所需要的一切实例。完成自动配置

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

  • 类要存在,我们只需要引入了相关依赖(启动器),依赖有了条件成立,自动配置生效。

  • 如果我们自己配置了相关Bean,那么会覆盖默认的自动配置的Bean

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

1)启动器

所以,我们如果不想配置,只需要引入依赖即可,而依赖版本我们也不用操心,因为只要引入了SpringBoot提供的stater(启动器),就会自动管理依赖及版本了。

因此,玩SpringBoot的第一件事情,就是找启动器,SpringBoot提供了大量的默认启动器

2)全局配置

另外,SpringBoot的默认配置,都会读取默认属性,而这些属性可以通过自定义application.properties文件来进行覆盖。这样虽然使用的还是默认配置,但是配置中的值改成了我们自定义的。

因此,玩SpringBoot的第二件事情,就是通过application.properties来覆盖默认属性值,形成自定义配置。我们需要知道SpringBoot的默认属性key,非常多,可以再idea中自动提示

第五章 SpringBoot实践

接下来,我们来看看如何用SpringBoot来玩转以前的S spring S springmvc M mybatis,我们会在数据库引入一张用户表tb_user和实体类User

image-20201031193244009

就在刚才的springboot-demo工程中做开发就可以!

user实体类:放入到cn.itcast.pojo包下

package cn.itcast.pojo;

import lombok.Data;
import java.util.Date;

@Data //注意要记得添加lombok的依赖
public class User{
// id
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;

}

1.整合SpringMVC

虽然默认配置已经可以使用SpringMVC了,不过我们有时候需要进行自定义配置。

1.0.日志控制

导入相关jar包

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

日志级别控制:

## 日志级别控制
logging:
level:
cn.itcast: debug ## 日志级别 从高到低 debug info warn error
org.springframework.boot: info

测试:

package cn.itcast.controller;

import cn.itcast.pojo.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @description: 测试的Controller
* @author: mryhl
* @date: Created in 2020/10/31 17:27
* @version: 1.1
* @RestController 相当于 @Controller+ @ResponseBody
*/
@RestController
@Slf4j
public class HelloController {
@GetMapping("/hello")
public String hello(){
//System.out.println("HelloController中的hello方法执行了");
log.debug("HelloController中的hello方法执行了");
return "HelloController中的hello方法执行了";
}
@Autowired
private User user;
@GetMapping("/user")
public User user(){
//System.out.println("访问到了HelloController中user方法");
log.info("访问到了HelloController中user方法");
return user;
}
}

alt

其中:

  • logging.level:是固定写法,说明下面是日志级别配置,日志相关其它配置也可以使用。
  • cn.itcast和org.springframework是指定包名,后面的配置仅对这个包有效。
  • debug:日志的级别 常用的级别有4个 debug info warn error
1.1.修改端口

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

server:
port: 80

重启服务后测试:

60412725797
1.2.访问静态资源

现在,我们的项目是一个jar工程,那么就没有webapp,我们的静态资源该放哪里呢?

回顾我们上面看的源码,有一个叫做ResourceProperties的类,里面就定义了静态资源的默认查找路径:

1525500921773

默认的静态资源路径为:

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

只要静态资源放在这些目录中任何一个,SpringMVC都会帮我们处理。

我们习惯会把静态资源放在classpath:/static/目录下。我们创建目录,并且添加一些静态资源:

alt

重启项目后测试:

alt
1.3.添加拦截器

拦截器也是我们经常需要使用的,在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 @Configuration class of type WebMvcConfigurer but without @EnableWebMvc. If you wish to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, 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注解。如果你想要自定义HandlerMappingHandlerAdapterExceptionResolver等组件,你可以创建一个WebMvcRegistrationsAdapter实例 来提供以上组件。

如果你想要完全自定义SpringMVC,不保留SpringBoot提供的一切特征,你可以自己定义类并且添加@Configuration注解和@EnableWebMvc注解

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

首先我们定义一个拦截器:

package cn.itcast.interceptors;

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;

/**
* @description:
* @author: mryhl
* @date: Created in 2020/10/31 19:44
* @version: 1.1
* 记录日志
*/
@Slf4j
public class UserInterceptor implements HandlerInterceptor {

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.debug("UserInterceptor中的preHandle执行了");
// 拦截器放行
return true;
}

@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.debug("UserInterceptor中的postHandle执行了");
}

@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.debug("UserInterceptor中的afterCompletion执行了");
}
}

然后,我们定义配置类,注册拦截器:

package cn.itcast.config;

import cn.itcast.interceptors.UserInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

/**
* @description:
* @author: mryhl
* @date: Created in 2020/10/31 19:47
* @version: 1.1
*/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
/**
* @author mryhl
* 将自定义拦截器添加到springMvc拦截器栈
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new UserInterceptor()).addPathPatterns("/**");
}
}

结构如下:

alt

接下来运行并查看日志:

你会发现日志中什么都没有,因为我们记录的log级别是debug,默认是显示info以上,我们需要进行配置。

SpringBoot通过logging.level.*=debug来配置日志级别,*填写包名

## 设置cn.itcast包的日志级别为debug
logging:
level:
cn.itcast: debug

再次运行查看:

alt

2.整合jdbc和事务

spring中的jdbc连接和事务是配置中的重要一环,在SpringBoot中该如何处理呢?

答案是不需要处理,我们只要找到SpringBoot提供的启动器即可:

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

当然,不要忘了数据库驱动,SpringBoot并不知道我们用的什么数据库,这里我们选择MySQL:

<!--指定操作的数据库-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>

至于事务,SpringBoot中通过注解来控制。就是我们熟知的@Transactional

package cn.itcast.service.impl;

import cn.itcast.pojo.User;
import cn.itcast.service.UserService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

/**
* @description:
* @author: mryhl
* @date: Created in 2020/10/31 20:53
* @version:
*/
@Service
@Transactional
public class UserServiceImpl implements UserService {
@Override
public List<User> findAll() {
return null;
}

@Override
public User findById(Integer id) {
return null;
}

@Override
public void save(User user) {

}

@Override
public void Update(User user) {

}

@Override
public void deleteById(Integer id) {

}
}

3.整合连接池

其实,在刚才引入jdbc启动器的时候,SpringBoot已经自动帮我们引入了一个连接池:

1525514424562

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

1525516441005

因此,我们只需要指定连接池参数即可:

spring:
datasource:
driver-class-name: com.mysql.jdbc.Driver
url: jdbc:mysql:///springboot_db
username: root
password: root

4.整合mybatis

4.1.mybatis

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

<!--mybatis整合springboot-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>

配置,一些文件位置相关的,mybatis知道,需要我们来指定:

mybatis:
## mybatis 别名扫描
type-aliases-package: cn.itcast.pojo
## mapper.xml文件位置,如果没有映射文件,请注释掉
mapper-locations: classpath:mappers/**.xml

需求:查询所有用户信息

Controller代码

@Autowired
private UserService userService;

@GetMapping("/findAll")
public List<User> findAll(){
List<User> list = userService.findAll();
return list;
}

service代码

@Autowired
private UserDao userDao;

@Override
public List<User> findAll() {
List<User> list = userDao.findAll();
return list;
}

Mapper代码

package cn.itcast.dao;

import cn.itcast.pojo.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;
//@Mapper
public interface UserDao {
//查询所有
List<User> findAll();

}

mapper映射文件

文件所在位置如图:

alt
<?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="cn.itcast.dao.UserDao">

<select id="findAll" resultType="User">
select * from tb_user
</select>

</mapper>

另外,Mapper接口的位置在application.yml中并不能配置,Mapper接口的扫描有两种实现方式:

方式一

我们需要给每一个Mapper接口添加@Mapper注解,由Spring来扫描这些注解,完成Mapper的动态代理。

package cn.itcast.dao;

import cn.itcast.pojo.User;
import org.apache.ibatis.annotations.Mapper;

import java.util.List;
@Mapper
public interface UserDao {
//查询所有
List<User> findAll();

}

方式二

在启动类上添加扫描包注解(推荐):

package cn.itcast;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
* 引导类(启动类):springboot项目运行的入口
* @SpringBootApplication 表明当前类是引导类
*/
@SpringBootApplication
@MapperScan("cn.itcast.dao") //扫描dao包结构,为dao创建代理对象
public class ApplicationContext {

public static void main(String[] args) {
SpringApplication.run(ApplicationContext.class,args);
}
}

这种方式的好处是,不用给每一个Mapper都添加注解。

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

alt

开启自动驼峰标识

测试发现userName为空,原因是因为属性名和列名没有对应上

mybatis:
type-aliases-package: cn.itcast.pojo ## 扫描实体类包结构
mapper-locations: classpath:mappers/*.xml ## mybatis映射文件目录位置
configuration:
map-underscore-to-camel-case: true ## 开启驼峰命名 例如:user_name映射到userName
4.2.通用mapper(课后相关了解)

https://mapperhelper.github.io/docs/2.use/

注意:先把mybatis相关的配置文件删除、把引导类上mapperScan注解删除、把mybatis的启动器删除

通用Mapper的作者也为自己的插件编写了启动器,我们直接引入即可:

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

注意:一旦引入了通用Mapper的启动器,会覆盖Mybatis官方启动器的功能,因此需要移除对官方Mybatis启动器的依赖。

无需任何配置就可以使用了。如果有特殊需要,可以到通用mapper官网查看: https://mapperhelper.github.io/docs/

另外,我们需要把启动类上的@MapperScan注解修改为通用mapper中自带的:

alt

接下来就是通用mapper的使用步骤了:

1)继承Mapper接口

package cn.itcast.dao;

import cn.itcast.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import tk.mybatis.mapper.common.BaseMapper;

import java.util.List;
//@Mapper
public interface UserDao extends BaseMapper<User> {
//查询所有
//List<User> findAll();

}

2)在实体类上加JPA注解:

package cn.itcast.pojo;

import lombok.Data;

import javax.persistence.Id;
import javax.persistence.Table;
import java.util.Date;
import java.util.List;

@Data
@Table(name = "tb_user")//指定数据库表名与实体类映射关系
public class User {
/*private String username;
private String password;
private Integer age;

private List<String> list;
private String[] array;
private List<User> userList;*/

// id
@Id //当前属性是主键
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;

}

alt

此时,对UserService的代码进行简单改造:

package cn.itcast.service.impl;

import cn.itcast.dao.UserDao;
import cn.itcast.pojo.User;
import cn.itcast.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

@Service
@Transactional //基于注解实现事务管理
public class UserServiceImpl implements UserService {
@Autowired
private UserDao userDao;

@Override
public List<User> findAll() {
//List<User> list = userDao.findAll();
List<User> list = userDao.selectAll();
return list;
}

@Override
public User findById(Integer id) {
User user = userDao.selectByPrimaryKey(id);
return user;
}

@Override
public void save(User user) {
System.out.println("save方法执行了");
}

@Override
public void Update(User user) {
System.out.println("update方法执行了");
}

@Override
public void deleteById(Integer id) {
System.out.println("delete方法执行了");
}
}

5.启动测试

将controller进行简单改造:

package cn.itcast.controller;

import cn.itcast.pojo.User;
import cn.itcast.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController //相当于 @Controller+ @ResponseBody
@Slf4j
public class HelloController {

//@RequestMapping(value = "/hello",method = RequestMethod.GET)
@GetMapping("/hello")
public String hello(){
//基于lombok提供的日志对象记录日志
log.debug("HelloController中的hello方法执行了");
//System.out.println("访问到了HelloController中的hello方法");
return "欢迎来到神奇的springboot项目中";
}

@Autowired
private User user;

@GetMapping("/user")
public User user(){
log.info("HelloController中user方法");
// System.out.println("访问到了HelloController中user方法");
return user;
}

@Autowired
private UserService userService;

@GetMapping("/findAll")
public List<User> findAll(){
List<User> list = userService.findAll();
return list;
}

@GetMapping("/findById")
public User findById(Integer id){
User user = userService.findById(id);
return user;
}
}

我们启动项目,查看:

alt

友情提示:如果你非要用MyBatis的通用mapper,并且出了这个异常tk.mybatis.mapper.provider.base.BaseSelectProvider,看看MapperScan的包是不是tk的

//import org.mybatis.spring.annotation.MapperScan;
import tk.mybatis.spring.annotation.MapperScan;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mr.YHL

谢谢您的肯定

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值