抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

Hello world!

教程与文档

SpringBoot2核心技术与响应式编程 · 语雀 (yuque.com)

Spring与SpringBoot2

01、Spring与SpringBoot · 语雀 (yuque.com)

HelloWorld

  1. 导入依赖 pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <!-- 父项目配置 -->
    <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.3.3.RELEASE</version>
    </parent>

    <!-- web场景启动器 -->
    <dependencies>
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    </dependencies>
  2. 编写controller HelloController.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    // @Controller // 注明controller
    // @ResponseBody // 注明将java对象转为json格式的数据
    @RestController // 代替以上两者
    public class HelloController {
    // 映射请求的地址
    @RequestMapping("/hello")
    public String handle1() {
    return "Hello,SpringBoot2";
    }
    }
  3. 编写主程序类并测试 MainApplication.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    /**
    * 主程序类
    */
    // 表明这是一个SpringBoot应用
    @SpringBootApplication
    public class MainApplication {
    public static void main(String[] args) {
    // run声明主程序类,返回一个IoC容器
    SpringApplication.run(MainApplication.class, args);
    }
    }
  4. resources文件夹下application.properties,可根据文档自定义配置

    Common Application properties (spring.io)

  5. 创建可执行jar包,添加build依赖,然后点击maven中的lifecycle中的clean与package并执行 pom.xml

    1
    2
    3
    4
    5
    6
    7
    8
    9
    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.2.4.RELEASE</version>
    </plugin>
    </plugins>
    </build>
  6. 执行jar包,在target目录下执行以下命令

    java -jar 包名.jar

依赖管理与自动配置特性

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

底层注解

@Configuration、@Bean 配置对象

原Spring使用xml配置文件配置bean对象如下

bean.xml

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

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

<bean id="cat" class="com.myspringboot2.bean.Pet">
<property name="name" value="mimi"/>
</bean>

</beans>

编写配置MyConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 1、配置类里面使用@Bean添加对象,默认是单实例
* 2、配置类本身也是对象
* 3、proxyBeanMethods: 代理bean的方法。默认为true(full模式),使用代理对象调用方法,保证对象是单实例;否则(lite模式)非单实例
*/
@Configuration(proxyBeanMethods = true) //声明这是一个配置类(即替换掉配置文件
public class MyConfig {
// 无论外部对这个配置类中的方法调用多少次,获得的都是容器中的单实例对象
@Bean //向容器中添加组件,id为方法名(可以自定义),组件类型为返回类型,组件在容器中的实例为返回地值
public User user01() {
return new User("zhangsan", 18);
}
@Bean("pet01") //自定义id
public Pet cat() {
return new Pet("mimi");
}
}

测试类MainApplication.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 主程序类
*/
// 表明这是一个SpringBoot应用
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
// 获取IoC容器,run声明主程序类,返回一个IoC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 从容器中获取bean,默认是单实例
User user01 = run.getBean("user01", User.class);
Pet pet01 = run.getBean("pet01", Pet.class);
MyConfig myConfig = run.getBean(MyConfig.class);
}
}

Full模式与Lite模式

  • 配置类组件之间无依赖关系用Lite模式加速客器启动过程,减少判断
  • 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式

@ComponentScan 包扫描

1
2
3
4
// 一下三者相当于@SpringBootApplication
@ComponentScan("com.myspringboot2") //包扫描地址
@EnableAutoConfiguration
@SpringBootConfiguration

@Import 注入对象

1
@Import({User.class, DBHelper.class})   //向容器中添加对应类型的对象,默认对象名为对应类的全类名

@Conditional 条件装配

使用 MyConfig.java

1
2
3
4
5
6
7
8
@Configuration(proxyBeanMethods = false)  //声明这是一个配置类(即替换掉配置文件
public class MyConfig {
@ConditionalOnBean(name = "pet02") // 按条件执行向容器中注入对象,可放在类上(则按条件执行是否注入类中所有的对象)
@Bean //向容器中添加组件,id为方法名(可以自定义),组件类型为返回类型,组件在容器中的实例为返回地值
public User user01() {
return new User("zhangsan", 18);
}
}

测试 MainApplication.java

1
2
3
4
5
6
7
8
9
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
// 获取IoC容器,run声明主程序类,返回一个IoC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 由于user01配置的是由添加了ConditinalOnBean,而其中的条件pet02对象并不在容器当中,所以未注入user01
System.out.println(run.containsBean("user01"));
}
}

@ImportResource 导入xml配置文件

1
2
3
4
@ImportResource("classpath:beans.xml")  //兼容xml配置
@Configuration(proxyBeanMethods = false) //声明这是一个配置类(即替换掉配置文件
public class MyConfig {
}
1
2
3
4
5
6
7
8
9
@SpringBootApplication
public class MainApplication {
public static void main(String[] args) {
// 获取IoC容器,run声明主程序类,返回一个IoC容器
ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);
// 使用@ImportResource成功注入beans.xml中的对象
System.out.println(run.containsBean("user01"));
}
}

@ConfigurationProperties 配置绑定

编写属性, application.properties,注意使用全小写

1
2
mycar.brand=ABC
mycar.price=100000

第一种方法:需要在容器中的组件上使用, Car.java

1
2
3
4
5
6
7
@Component  //声明为组件,只有容器中的组件才能使用
@ConfigurationProperties(prefix = "mycar") //绑定配置文件中的属性,prefix指定对应前缀
public class Car {
String brand;
Integer price;
// ……
}

第二种方法:不使用@Component声明Car为组件,而是在配置类种开启指定对象的属性配置功能

1
2
3
4
5
@EnableConfigurationProperties(Car.class)  //开启指定对象的属性配置功能
@Configuration(proxyBeanMethods = false) //声明这是一个配置类(即替换掉配置文件
public class MyConfig {
// ……
}

测试, HelloController.java

1
2
3
4
5
6
7
8
9
@RestController
public class HelloController {
@Autowired
Car car;
@RequestMapping("/car")
public Car car() {
return car;
}
}

自动配置原理(源码分析

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

@SpringBootApplication

声明当前是一个配置类

@ComponentScan

指定扫描路径

@EnableAutoConfiguration

@AutoConfigurationPackage

利用Registrar将当前包下的所有组件全部导入进容器

@Import

导入默认组件

便捷使用

Lombok

简化JavaBean编写等

  1. 引入依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    </dependency>
  2. 编写JavaBean

    1
    2
    3
    4
    5
    6
    7
    @NoArgsConstructor  //自动编写无参构造器
    @AllArgsConstructor //自动编写全参构造器
    @Data //自动编写set/get/toString方法
    public class Car {
    String brand;
    Integer price;
    }
  3. 编写controller的日志打印

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    @Slf4j	//引入日志接口
    @RestController
    public class HelloController {
    // 映射请求的地址
    @RequestMapping("/hello")
    public String handle1() {
    log.info("hello"); //日志打印信息
    return "Hello,SpringBoot2";
    }
    }

Dev-tools、JRebel

自动重启、热更新

  1. 引入依赖

    1
    2
    3
    4
    5
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-devtools</artifactId>
    <optional>true</optional>
    </dependency>
  2. 使用 Ctrl+F9 更新

Spring Initializr

快速创建springboot应用,创建应用时选择即可

配置文件

properties

yaml

基本语法

  • key: value #注意空格
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用tab,只允许空格
  • 缩进空格数无影响,同层级的元素需要左对齐
  • #编写注释
  • “”双引号内\n等不转义,仍然是回车的本意显示为回车,’’单引号内转义,\n显示为字符串

数据类型

  • 字面量

    1
    key: value
  • 对象

    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

示例

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

configuration-processor

配置处理器

  1. 添加依赖

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
    </dependency>

    <build>
    <plugins>
    <plugin>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-maven-plugin</artifactId>
    <version>2.2.4.RELEASE</version>
    <!-- 打包的时候不带这个包 -->
    <configuration>
    <excludes>
    <exclude>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    </exclude>
    </excludes>
    </configuration>
    </plugin>
    </plugins>
    </build>

web开发

简单功能

静态资源访问

  • 静态资源目录

    • 存放路径:类路径(resources资源根目录)下的/static or /public or /resources or /META-INF/resources
    • 访问路径:项目根路径/静态资源名
  • 原理: 静态映射/**。
    请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面

  • 改变默认的静态资源访问路径和存放路径,在配置文件application.yaml中编写

    1
    2
    3
    4
    5
    spring:
    mvc:
    static-path-pattern: /res/** #res为自定义前缀,即访问地址须在项目根路径/res/静态资源名
    resources:
    static-locations: [classpath:/自定义文件夹名/]

欢迎页

命名为index.html放在静态资源目录下即可。

自定义Favicon

命名为favicon.ico 放在静态资源目录下即可。

源码分析

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

请求处理

@xxxMapping 请求映射

Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)

  • 以前:**/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
  • 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
  1. 编写controller类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    @RestController
    public class HelloController {
    @GetMapping("/user")
    // 即@RequestMapping(value = "/user",method = RequestMethod.GET)
    public String getUser() {
    return "getUser GET";
    }
    @PostMapping("/user")
    // 即@RequestMapping(value = "/user",method = RequestMethod.POST)
    public String saveUser() {
    return "saveUser POST";
    }
    @PutMapping("/user")
    // 即@RequestMapping(value = "/user",method = RequestMethod.PUT)
    public String modifiedUser() {
    return "modifiedUser PUT";
    }
    @DeleteMapping("/user")
    // 即@RequestMapping(value = "/user",method = RequestMethod.DELETE)
    public String deleteUser() {
    return "deleteUser DELETE";
    }
    }
  2. 编写页面

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    <form action="/user" method="get">
    <input type="submit" value="get提交">
    </form>
    <form action="/user" method="post">
    <input type="submit" value="post提交">
    </form>
    <!-- form表单中method只能写get/post -->
    <!-- 使用隐藏域传递_method方法参数的值 -->
    <form action="/user" method="post">
    <input type="hidden" name="_method" value="PUT">
    <input type="submit" value="PUT提交">
    </form>
    <form action="/user" method="post">
    <input type="hidden" name="_method" value="DELETE">
    <input type="submit" value="DELETE提交">
    </form>
  3. 在配置文件中开启hiddenmethod-filter(默认为false),如果前端不是使用表单发送请求则不需要开启filter

    1
    2
    3
    4
    5
    spring:
    mvc:
    hiddenmethod:
    filter:
    enabled: true

自定义HiddenMethodFilter

编写配置类,自定义filter

1
2
3
4
5
6
7
8
@Configuration(proxyBeanMethods = false)
public class MyWebConfig {
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
HiddenHttpMethodFilter filter = new HiddenHttpMethodFilter();
filter.setMethodParam("_m"); //修改方法参数名为_m
return filter;
}
}

请求映射原理

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

参数注解

@PathVariable、@RequestHeader、@RequestParam、@CookieValue、@RequestBody
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
@RestController
public class ParamTestController {

// 测试url: http://localhost:8080/test1/1/lisi?age=10&inters=%E5%90%83%E9%A5%AD&inters=%E7%9D%A1%E8%A7%89
@GetMapping("/test1/{id}/{username}")
public Map<String, Object> test1(@PathVariable("id") Integer id,
@PathVariable("username") String name,
@PathVariable Map<String, String> variables,
@RequestHeader("User-Agent") String userAgent,
@RequestHeader Map<String, String> headers,
@RequestParam("age") Integer age,
@RequestParam("inters") List<String> inters,
@RequestParam Map<String,String> params1,
@RequestParam MultiValueMap<String, String> params2,
@CookieValue("_xsrf") String _xsrf,
@CookieValue("_xsrf") Cookie cookie) {
/**
* @PathVariable("") 获得指定路径变量名的值
* @PathVariable 获得所有路径变量名以及值,存放到Map<String, String>中
* 注意后者键值对对应的是地址栏中的username参数名,而前者是形参名name
*
* @RequestHeader("") 获得请求头中指定key的值
* @RequestHeader 获得请求头中所有的key及其值
*
* @RequestParam("") 获得指定请求参数名的值
* @RequestParam 获得所有请求参数名以及值,存放到Map<String, String>中
* 注意后者存放在map中,kv只有一对,可使用MultiValueMap获取到一对多的键值对。
*/
Map<String, Object> map = new HashMap<>();
// 以下是测试
map.put("id", id);
map.put("name", name);
map.put("pv", variables);
map.put("userAgent", userAgent);
map.put("rh", headers);
map.put("age",age);
map.put("inters",inters);
map.put("params1",params1);
map.put("params2",params2);
map.put("_xsrf",_xsrf);
System.out.println(cookie.getName()+"===>"+cookie.getValue());
return map;
}

@PostMapping("/test2")
public Map<String, Object> test2(@RequestBody String content){
/**
* @RequestBody 获得请求体中所有的key及对应值
*/
Map<String, Object> map = new HashMap<>();
// 以下是测试
map.put("content", content);
return map;
}
}
@RequestAttribute 获取域对象参数值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@Controller //注意RestController写return "forward:/success"只会解析成字符串
public class RequestController {
@GetMapping("/goto")
public String gotoPage(HttpServletRequest req) {
req.setAttribute("msg", "信息");
req.setAttribute("code", "信息123123");
return "forward:/success"; //转发到/success请求
}

@ResponseBody
@GetMapping("/success")
public Map<String, Object> success(@RequestAttribute("msg") String msg,
@RequestAttribute("code") String code) {
/**
* @RequestAttribute 获得request域对象中的指定值
*/
Map<String, Object> map = new HashMap<>();
map.put("msg", msg);
map.put("code", code);
return map;
}

}
@MatrixVariable 获取矩阵变量
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
//1、矩阵变量语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
//2、SpringBoot默认是禁用了矩阵变量的功能
// 手动开启:原理。对于路径的处理。UrlPathHelper进行解析。
// removeSemicolonContent(移除分号内容)支持矩阵变量的
//3、矩阵变量必须有url路径变量才能被解析
@GetMapping("/cars/{path}")
public Map carsSell(@MatrixVariable("low") Integer low,
@MatrixVariable("brand") List<String> brand,
@PathVariable("path") String path){
Map<String,Object> map = new HashMap<>();

map.put("low",low);
map.put("brand",brand);
map.put("path",path);
return map;
}

// /boss/1;age=20/2;age=10
@GetMapping("/boss/{bossId}/{empId}")
public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge,
@MatrixVariable(value = "age",pathVar = "empId") Integer empAge){
Map<String,Object> map = new HashMap<>();

map.put("bossAge",bossAge);
map.put("empAge",empAge);
return map;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Configuration(proxyBeanMethods = false)
public class MyWebConfig {
public HiddenHttpMethodFilter hiddenHttpMethodFilter() {
HiddenHttpMethodFilter filter = new HiddenHttpMethodFilter();
filter.setMethodParam("_m"); //修改_method
return filter;
}

@Bean
// 自定义其中的功能,此处演示启用矩阵变量功能
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
UrlPathHelper urlPathHelper = new UrlPathHelper();
// 设置不删除分号内容
urlPathHelper.setRemoveSemicolonContent(false);
configurer.setUrlPathHelper(urlPathHelper);
}
};
}
}

ServletAPI

WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId

参数注解源码分析

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

直接看困了,以后再看吧。

自定义参数绑定

  1. 编写两个bean

    1
    2
    3
    4
    5
    6
    7
    8
    @Data
    public class User {
    String username;
    String password;
    Integer age;
    Date birthday;
    Pet pet;
    }
    1
    2
    3
    4
    5
    @Data
    public class Pet {
    String name;
    Integer age;
    }
  2. 编写表单

    1
    2
    3
    4
    5
    6
    7
    8
    <form action="/saveuser" method="post">
    姓名:<input type="text" name="username">
    年龄:<input type="number" name="age">
    生日:<input type="date" name="birthday">
    宠物名字:<input type="text" name="pet.name">
    宠物年龄:<input type="number" name="pet.age">
    <input type="submit" value="POST提交">
    </form>
  3. 编写controller测试

    1
    2
    3
    4
    @PostMapping("/saveuser")
    public User saveuser(User user) {
    return user;
    }

自定义转换器

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
@Configuration(proxyBeanMethods = false)
public class MyWebConfig {
@Bean
// 自定义其中的功能
public WebMvcConfigurer webMvcConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new Converter<String, Date>() {
@Override
public Date convert(String s) {
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd");
Date date = null;
try {
date = sf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
}
return date;
}
});
}
};
}
}

数据响应与内容协商

响应JSON数据

  1. 引入jackson.jar,已包含在starter-web场景启动器中
  2. 使用注解@ResponseBody

响应原理

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

内容协商

根据客户端接收能力不同,返回不同媒体类型的数据。

  1. 以xml为示例,引入依赖

    1
    2
    3
    4
    <dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
    </dependency>
  2. 请求头里accept字段,设置了接收数据以xml格式为优先

  3. 开启基于请求参数的内容协商原理,同时url中添加请求参数format=xxx即可

    1
    2
    3
    4
    spring:
    mvc:
    contentnegotiation:
    favor-parameter: true

内容协商原理

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

自定义MessageConvertor

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

视图解析与模板引擎

thymeleaf

java模板引擎

  1. 基本语法

  2. 引入依赖

1
2
3
4
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  1. 编写模板
1
2
3
4
5
6
7
8
9
10
11
12
13
14
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1 th:text="${msg}">默认的值</h1>
<h2>
<a href="www.google.com" th:href="${link}">跳转百度</a>
<a href="www.google.com" th:href="@{link}">跳转百度</a>
</h2>
</body>
</html>
  1. 编写controller
1
2
3
4
5
6
7
8
9
10
11
@Controller
public class ViewTestController {
@GetMapping("/testsuccess")
public String test(Model model) {
// model中的数据会被放在请求域中
model.addAttribute("msg", "msgTest");
model.addAttribute("link", "https://www.baidu.com");
// 跳转页面写页面的前名
return "success";
}
}

拦截器

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

  1. 编写Interceptor
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
/**
* 登陆检查
*/
@Slf4j
public class LoginInterceptor implements HandlerInterceptor {
/**
* 目标方法执行之前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
log.info("Run LoginInterceptor.preHandle");
HttpSession session = request.getSession();
Object loginUser = session.getAttribute("loginUser");
if (loginUser != null) {
return true;
} else {
session.setAttribute("msg", "当前尚未登录");
response.sendRedirect("/");
return false;
}
}
/**
* 目标方法执行之后
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
log.info("Run LoginInterceptor.postHandle",modelAndView);
}
/**
* 页面渲染以后
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
log.info("Run LoginInterceptor.afterCompletion",ex);
}
}
  1. 编写WebConfig类,添加interceptor
1
2
3
4
5
6
7
8
9
10
@Configuration
public class AdminWebConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
// 添加拦截器,并且设置拦截地址与不拦截地址
// /**拦截目录下所有资源,静态资源也会被拦截
registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**").excludePathPatterns("/","/login","/css/**","/js/**","/font/**","/images/**");
// 设置exlucde不拦截,或者在配置文件中编写static-path-pattern=/static/**,注意此时需要修改标签中的href
}
}

文件上传

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

  1. 编写controller
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
/**
* 文件上传测试
*/
@Slf4j
@Controller
public class FormTestController {
@GetMapping("/form_layouts")
public String formLayouts() {
return "form/form_layouts";
}

/**
* MultipartFile自动封装上传过来的文件
*/
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("name") String name,
@RequestPart("headImg") MultipartFile headImg,
@RequestPart("photos") MultipartFile[] photos) throws IOException {
// 获取的信息
log.info("上传的信息:email={},name={},headImg={},photos={}", email, name, headImg.getSize(), photos.length);
if (!headImg.isEmpty()) {
// 获取原文件名、保存到服务器
headImg.transferTo(new File("C:\\Users\\卢荟\\Desktop\\test1\\"+headImg.getOriginalFilename()));
}
if (photos.length > 0) {
for (MultipartFile photo : photos) {
if (!photo.isEmpty()) {
photo.transferTo(new File("C:\\Users\\卢荟\\Desktop\\test2\\"+photo.getOriginalFilename()));
}
}
}
return "index";
}
}
  1. 编写配置文件
1
2
3
#修改上传文件的最大大小
spring.servlet.multipart.max-file-size=10MB
spring.servlet.multipart.max-request-size=100MB

异常处理

  • 默认情况下,Spring Boot提供/error处理所有错误的映射
  • 对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。
  • 对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据

自定义错误页

在将400.html、500.html等页面放在resources > templates >error下即可

自定义异常处理

@ControllerAdvice+@ExceptionHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
/**
* 处理整个web controller的异常
*/
@Slf4j
@ControllerAdvice //注明这是一个增强的controller
public class GlobalExceptionHandler {
/**
* 处理数学异常、空指针异常
* @param e
* @return
*/
@ExceptionHandler({ArithmeticException.class, NullPointerException.class}) // 表明用于处理指定异常
public String handleArithException(Exception e) {
log.error("异常是:{}", e);
return "error/404"; // 指定返回视图的地址
}
}
@ResponseStatus+自定义Exception
1
2
3
4
5
6
7
8
9
@ResponseStatus(value = HttpStatus.FORBIDDEN,reason = "用户数量太多")     //注明异常返回状态码和原因
public class UserTooManyException extends RuntimeException {
public UserTooManyException() {

}
public UserTooManyException(String msg) {
super(msg);
}
}
自定义HandlerExceptionResolver
1
2
3
4
5
6
7
8
9
10
11
12
@Component
public class CustomerHandlerExceptionResolver implements HandlerExceptionResolver {
@Override
public ModelAndView resolveException(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) {
try {
httpServletResponse.sendError(511, "自定义错误");
} catch (IOException ex) {
ex.printStackTrace();
}
return new ModelAndView();
}
}

原生组件注入

ServletAPI

@ServletComponentScan

主应用类中使用@ServletComponentScan配置扫描路径

1
2
3
4
5
6
7
@ServletComponentScan(basePackages = "com.spb_adminex.servlet")		//配置servlet、filter、listener扫描地址
@SpringBootApplication
public class SpbAdminexApplication {
public static void main(String[] args) {
SpringApplication.run(SpbAdminexApplication.class, args);
}
}
@WebServlet
1
2
3
4
5
6
7
@WebServlet(urlPatterns = "/my")
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().write("MyServlet running");
}
}
@WebFilter
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Slf4j
@WebFilter(urlPatterns = {"/css/*","/images/*"})
public class MyFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
log.info("MyFilter初始化");
}
@Override
public void destroy() {
log.info("MyFilter销毁");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
log.info("MyFilter running");
filterChain.doFilter(servletRequest, servletResponse);
}
}
@WebListener
1
2
3
4
5
6
7
8
9
10
11
12
@Slf4j
@WebListener
public class MyListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
log.info("MyListener监听到项目初始化完成");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
log.info("MyListener监听到项目销毁");
}
}

RegisterBean

编写一个配置类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Configuration
public class MyRegisterConfig {
@Bean
public ServletRegistrationBean myServlet() {
return new ServletRegistrationBean(new MyServlet(), "/my");
}
@Bean
public FilterRegistrationBean myFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(new MyFilter());
filterRegistrationBean.setUrlPatterns(Arrays.asList("/my","/css/*"));
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean myListener() {
return new ServletListenerRegistrationBean(new MyListener());
}
}

数据访问

SQL

使用默认数据源、jdbcTemplate

  1. 导入starter场景和数据库驱动
1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
  1. 编写配置文件application.yaml
1
2
3
4
5
6
spring:
datasource:
url: jdbc:mysql://localhost:3306/online_bookstore
username: root
password: 123456789
driver-class-name: com.mysql.cj.jdbc.Driver
  1. 使用jdbcTemplate测试
1
2
3
4
5
6
7
8
9
10
11
@Slf4j
@SpringBootTest
class SpbAdminexApplicationTests {
@Autowired
JdbcTemplate jdbcTemplate;
@Test
void contextLoads() {
Long count = jdbcTemplate.queryForObject("select count(*) from admin", Long.class);
log.info("当前表的记录数为" + count);
}
}

使用Druid数据源

  1. 引入数据源
1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.6</version>
</dependency>
  1. 编写数据源配置类
1
2
3
4
5
6
7
8
9
10
@Configuration
public class MyDataSourceConfig {
// 引入自己的数据源之后,自动配置的默认DataSource失效
@ConfigurationProperties("spring.datasource") //将组件与配置文件中的属性绑定
@Bean
public DataSource dataSource() {
DruidDataSource druidDataSource = new DruidDataSource();
return druidDataSource;
}
}
  1. 测试
1
2
3
4
5
6
7
8
9
10
@Slf4j
@SpringBootTest
class SpbAdminexApplicationTests {
@Autowired
DataSource dataSource;
@Test
void contextLoads() {
log.info("当前数据源类型为{}", dataSource.getClass());
}
}
  1. 其他👉雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

使用xml配置文件整合MyBatis

  1. 导入依赖
1
2
3
4
5
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
  1. 编写application.yaml配置文件
1
2
3
mybatis:
config-location: classpath:mybatis/mybatis-config.xml #全局配置文件位置
mapper-locations: classpath:mybatis/mapper/*.xml #sql映射文件位置
  1. 编写mybatis-config.xml全局配置文件/或者编写application配置文件(此时不能同时配置全局配置文件位置)
1
2
3
4
5
6
7
8
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 开启下划线转驼峰命名法 -->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
</configuration>
1
2
3
4
mybatis:
mapper-locations: classpath:mybatis/mapper/*.xml #sql映射文件位置
configuration:
map-underscore-to-camel-case: true #开启下划线转驼峰命名法
  1. 编写beanMapper接口
1
2
3
4
5
@Mapper //注明这是一个mapper接口
public interface AdminMapper {
public Admin getAdmin(Integer id);
public Boolean insertAdmin(Admin admin);
}
  1. 编写beanMapper.xml配置文件
1
2
3
4
5
6
7
8
9
10
11
12
<?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.spb_adminex.mapper.AdminMapper">

<select id="getAdmin" resultType="com.spb_adminex.bean.Admin" >
select * from admin where id=#{id}
</select>
<insert id="insertAdmin" useGeneratedKeys="true" keyProperty="id">
insert into admin(`account`,`password`) values(#{account},#{password})
</insert>

</mapper>
  1. 编写service层
1
2
3
4
5
6
7
8
9
10
11
12
@Service
public class AdminService {
@Autowired
AdminMapper adminMapper;

public Admin getAdminById(Integer id) {
return adminMapper.getAdmin(id);
}
public Boolean insertAdmin(Admin admin) {
return adminMapper.insertAdmin(admin);
}
}
  1. 编写controller层
1
2
3
4
5
6
7
8
9
10
11
@Controller
public class AdminController {
@Autowired
AdminService adminService;

@ResponseBody
@GetMapping("/getAdmin")
public Admin getAdminById(@RequestParam("id") Integer id) {
return adminService.getAdminById(id);
}
}

使用注解整合MyBatis

  1. 其余文件,且不需要beanMapper.xml
  2. 编写beanMapper接口
1
2
3
4
5
@Mapper //注明这是一个mapper接口
public interface AdminMapper {
@Select("select * from admin where id=#{id}") //注解替换beanMapper.xml文件
public Admin getAdmin(Integer id);
}

整合MyBatis-Plus

快速开始 | MyBatis-Plus (baomidou.com)

获取数据
  1. 导入依赖
1
2
3
4
5
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
  1. 为启动类添加@MapperScan,注明扫描Mapper文件的地址
1
2
3
4
5
6
7
8
9
@SpringBootApplication
@MapperScan("com.baomidou.mybatisplus.samples.quickstart.mapper")
public class Application {

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

}
  1. 编写全局配置文件
1
2
3
4
5
6
spring:
datasource:
url: jdbc:mysql://localhost:3306/spb_adminex
username: root
password: 123456789
driver-class-name: com.mysql.cj.jdbc.Driver
  1. 编写Bean类
1
2
3
4
5
6
7
8
9
10
11
12
13
@NoArgsConstructor
@AllArgsConstructor
@Data
@TableName("user") //可以指定表名,不知道则默认为类名
public class User {
private Long id;
private String name;
private String age;
private String email;

@TableField(exist = false) //注明当前字段在表中不存在
private String test;
}
  1. 编写BeanMapper接口
1
2
public interface UserMapper extends BaseMapper<User> {
}
  1. 编写BeanService接口
1
2
3
public interface UserService extends IService<User> {

}
  1. 编写BeanServiceImpl实现类
1
2
3
4
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper,User> implements UserService {

}
  1. 编写controller
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Controller
public class TableController {
@Autowired
UserService userService = new UserServiceImpl();
@GetMapping("/dynamic_table")
public String dynamicTable(Model model) {
List<User> userList = userService.list();
model.addAttribute("userList", userList);
return "table/dynamic_table";
}
@GetMapping("/responsive_table")
public String responsiveTable() {
return "table/responsive_table";
}
@GetMapping("/editable_table")
public String editableTable() {
return "table/editable_table";
}
}
分页操作
  1. 编写MybatisPlugConfig
1
2
3
4
5
6
7
8
9
10
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
// 创建MybatisPlusInterceptor
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
  1. 编写controller
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
@Controller
public class TableController {
@Autowired
UserService userService = new UserServiceImpl();

// 进入dynamic_table并展示分页数据
@GetMapping("/dynamic_table")
public String dynamicTable(@RequestParam(value = "pn",defaultValue = "1")Integer pn, Model model) {
// 获得分页结果对象,并设置分页
Page<User> page = userService.page(new Page<User>(pn, 2));
model.addAttribute("page", page);
// page.getRecords获得所有记录,page.current获得当前页数,page.pages获得总页数,page.getTotal获得总条数……
return "table/dynamic_table";
}

@GetMapping("/user/delete/{id}")
// 删除用户功能
public String deleteUser(@PathVariable("id") Long id,
@RequestParam(value = "pn",defaultValue = "1") Integer pn,
RedirectAttributes ra) {
userService.removeById(id);
ra.addAttribute("pn", pn);
return "redirect:/dynamic_table";
}
}
  1. 编写html页面,thymeleaf语法详见雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili
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
<table>
<thead>
<tr>
<th>id</th>
<th>用户名</th>
<th>年龄</th>
<th>邮箱</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr class="gradeX" th:each="user,status:${page.getRecords()}">
<td th:text="${status.count}">xxx</td>
<td th:text="${user.name}">xxx</td>
<td th:text="${user.age}">xxx</td>
<td th:text="${user.email}">xxx</td>
<td>
<a th:href="@{/user/delete/{id}(id=${user.id},pn=${page.current})}" class="btn btn-primary">删除</a>
</td>
</tr>
</tbody>
</table>
<div class="row-fluid">
<div>
<div class="dataTables_info">当前第[[${page.current}]]页 总计[[${page.pages}]]页 总[[${page.getTotal}]]条记录
</div>
</div>
<div>
<div class="dataTables_paginate paging_bootstrap pagination">
<ul>
<li class="prev disabled"><a href="#">← Previous</a></li>
<li th:class="${num == page.current?'active':''}" th:each="num:${#numbers.sequence(1,page.pages)}">
<a th:href="@{/dynamic_table(pn=${num})}">[[${num}]]</a>
</li>
<li class="next disabled"><a href="#">Next → </a></li>
</ul>
</div>
</div>
</div>

NoSQL(Redis)

不尝试了没钱

单元测试

@SpringBootTest

1
2
3
4
5
6
@SpringBootTest
class MyTest {
@Test
public void test() {
}
}

常用注解

  • **@Test :**表示方法是测试方法。但是与JUnit4的@Test不同,他的职责非常单一不能声明任何属性,拓展的测试将会由Jupiter提供额外测试
  • **@ParameterizedTest :**表示方法是参数化测试,下方会有详细介绍
  • **@RepeatedTest :**表示方法可重复执行,下方会有详细介绍
  • **@DisplayName :**为测试类或者测试方法设置展示名称
  • **@BeforeEach :**表示在每个单元测试之前执行
  • **@AfterEach :**表示在每个单元测试之后执行
  • **@BeforeAll :**表示在所有单元测试之前执行
  • **@AfterAll :**表示在所有单元测试之后执行
  • **@Tag :**表示单元测试类别,类似于JUnit4中的@Categories
  • **@Disabled :**表示测试类或测试方法不执行,类似于JUnit4中的@Ignore
  • **@Timeout :**表示测试方法运行如果超过了指定时间将会返回错误
  • **@ExtendWith :**为测试类或测试方法提供扩展类引用

断言机制

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

……

指标监控

雷丰阳2021版SpringBoot2零基础入门springboot全套完整版(spring boot2)_哔哩哔哩_bilibili

高级特性

后会有期

源码和其他部分到时候(也不知道啥时候)会再去看的,but not today

评论




🧡💛💚💙💜🖤🤍