Spring Boot学习笔记
Spring Boot学习笔记
视频出处:动力节点springboot视频教程
为什么要使用Spring Boot?
- 使用Spring和SpringMVC时需要用到大量的xml配置文件,配置各种对象,把使用的对象放入到Spring容器中才能使用对象,十分繁琐。同时,用Spring整合其他框架时,需要了解其他框架的配置规则。
- Spring Boot就好比是不需要配置文件的Spring和SpringMVC,已经提前把常用的框架和第三方库配置好了,直接使用即可。开发起来效率更高,更为方便。
第1章 XML和JavaConfig
Spring使用XML作为容器配置文件,在3.0之后加入了JavaConfig,使得可以用java类作为配置文件使用。
这一点就是Spring Boot移除SSM中大量配置文件所用到的重要技术。
1.1 JavaConfig
1.1.1 介绍
JavaConfig:使用java类作为xml配置文件的代替,是配置Spring容器的纯java方法。在这个java类中可以创建java对象,把对象注入Spring容器中。
优点:
- 避免繁琐的xml配置。
- 可以使用面向对象的方式,一个配置类可以继承另一个配置类,可以重写方法。
1.1.2 XML配置容器
①创建maven工程,添加依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<!-- 编译插件 -->
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<!-- 插件的版本 -->
<version>3.5.1</version>
<!-- 编译级别 -->
<configuration>
<source>1.8</source>
<target>1.8</target>
<!-- 编码格式 -->
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
</build>
②创建数据类
package com.tsccg.pojo;
public class Student {
private String name;
private Integer age;
private String sex;
//get和set...
//toString
}
③resources 目录下创建 Spring 的配置文件 :beans.xml
声明一个Student对象:
<bean id="student" class="com.tsccg.pojo.Student">
<property name="name" value="张三"/>
<property name="age" value="20"/>
<property name="sex" value="男"/>
</bean>
单元测试:
/**
* 使用xml方式创建对象
*/
@Test
public void beanTest01() {
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
Student student = (Student) app.getBean("student");
System.out.println("xml方式创建对象:"+student);
}
结果:
xml方式创建对象:Student{name='张三', age=20, sex='男'}
1.1.3 JavaConfig配置容器
需要使用两个注解:
@Configuration
:放在类上,声明当前类为配置类。@Bean
:放在方法上,将方法返回的对象注入到容器中。
创建配置类:
package com.tsccg.javaconfig;
import com.tsccg.pojo.Student;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;
/**
* @Author: TSCCG
* @Date: 2021/12/13 18:12
*/
@Configuration//声明此类为配置类,在这个类中有很多方法, 方法的返回值是对象。
public class SpringConfig {
/**
* 创建Student对象并返回
* 通过@Bean注解将对象注入容器,对象默认id为方法名
*/
@Bean
public Student createStudent() {
Student student = new Student();
student.setName("李四");
student.setAge(22);
student.setSex("女");
return student;
}
/**
* 自定义Bean对象id
*/
@Bean(name = "liSiStudent")
public Student createStudent2() {
Student student = new Student();
student.setName("李四");
student.setAge(22);
student.setSex("女");
return student;
}
}
单元测试:
/**
* 使用javaConfig创建Student对象
*/
@Test
public void beanTest02() {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
Student student = (Student) app.getBean("createStudent");
System.out.println("javaConfig方式创建对象:"+student);
}
/**
* 自定义bean对象id
*/
@Test
public void beanTest03() {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
Student student = (Student) app.getBean("liSiStudent");
System.out.println("自定义id:"+student);
}
结果:
javaConfig方式创建对象:Student{name='李四', age=22, sex='女'}
自定义id:Student{name='李四', age=22, sex='女'}
1.2 @ImporResource
@ImporResource是在配置类里导入其他的xml配置文件,等同于xml配置的
<import resource="classpath:xxx.xml"/>
用法:
①在beans.xml文件中声明一个Student对象
<bean id="wangWuStudent" class="com.tsccg.pojo.Student">
<property name="name" value="王五"/>
<property name="age" value="18"/>
<property name="sex" value="女"/>
</bean>
②在配置类上添加@ImporResource
注解,导入beans.xml文件
@Configuration
@ImportResource(value="classpath:beans.xml")//导入beans.xml配置文件,指定从类路径下导入
public class SpringConfig {
...
}
③单元测试
/**
* 配置类导入xml配置文件
*/
@Test
public void beanTest04() {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
Student student = (Student) app.getBean("wangWuStudent");
System.out.println("JavaConfig导入xml配置文件:"+student);
}
结果:
JavaConfig导入xml配置文件:Student{name='王五', age=18, sex='女'}
④导入多个配置文件
@Configuration
@ImportResource(value={"classpath:beans.xml","classpath:applicationContext.xml"})
public class SpringConfig {
...
}
1.3 @PropertySource
@PropertySource用于在配置类里读取properties属性配置文件,等同于xml配置里的:
<context:property-placeholder location="classpath:xxx.properties"/>
用法:
①在resources目录下创建属性配置文件config.properties
dog.name=小哈
dog.type=哈士奇
dog.age=1
②创建数据类
使用@Component注解创建对象并放入容器,使用@Value注解读取配置文件中的数据并注入对象属性
package com.tsccg.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @Author: TSCCG
* @Date: 2021/12/13 19:59
*/
@Component("myDog")//创建对象并注入容器中
public class Dog {
@Value("${dog.name}")//读取属性配置文件中的数据,注入到对象属性中
private String name;
@Value("${dog.type}")
private String type;
@Value("${dog.age}")
private Integer age;
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", type='" + type + '\'' +
", age=" + age +
'}';
}
}
③修改配置类
1)使用@PropertySource注解读取属性配置文件
2)使用@ComponentScan注解扫描数据类,等同于<context:component-scan base-package="com.tsccg.pojo"/>
@Configuration//声明此类为配置类。
@PropertySource(value="classpath:config.properties")//读取属性配置文件
@ComponentScan(basePackages = "com.tsccg.pojo")//组件扫描器
public class SpringConfig {
...
}
④单元测试
/**
* @PropertySource 读取属性配置文件
*/
@Test
public void beanTest05() {
ApplicationContext app = new AnnotationConfigApplicationContext(SpringConfig.class);
Dog myDog = (Dog) app.getBean("myDog");
System.out.println("外部属性配置文件注入:"+myDog);
}
结果:
外部属性配置文件注入:Dog{name='小哈', type='哈士奇', age=1}
第2章 Spring Boot入门
2.1 介绍
Spring Boot是Spring家族的一个成员,可以简化Spring和SpringMVC的使用。核心还是IOC容器。
特性:
- Create stand-alone Spring applications
- Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)
- Provide opinionated 'starter' dependencies to simplify your build configuration
- Automatically configure Spring and 3rd party libraries whenever possible
- Provide production-ready features such as metrics, health checks, and externalized configuration
- Absolutely no code generation and no requirement for XML configuration
翻译:
- 可以独立创建一个Spring应用程序
- 内嵌有Tomcat、Jetty或Undertow(无需部署WAR文件),可以单独启动一个web应用。
- 提供了starter初始依赖以简化项目的构建配置。如在ssm项目中,整合MyBatis框架需要在Spring配置文件中配置MyBatis的对象:DataSource数据源、SqlSessionFactory、Dao代理对象。而在Spring Boot项目中,在pom.xml中加入一个
mybatis-spring-boot-starter
依赖即可。 - 尽可能地自动配置Spring以及第三方库。就是把Spring和第三方库中的对象都创建好,放到容器中,开发人员可以直接使用。(如SpringMVC的中央调度器,MyBatis框架的对象)
- 提供了生产准备功能,如统计(运行时长等)、健康检查(监控项目是否正常运转)和外部化配置(类如属性配置文件)
- 绝对不会生成代码,无需xml配置文件
2.2 创建Spring Boot项目
2.2.1 方式1:使用Spring Boot提供的初始化器
国内地址:https://start.springboot.io/
步骤:
①新建项目
②初始化设置
③添加依赖
④设置项目路径并创建
⑤项目结构
启动类:Application.java
package com.tsccg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
测试类:ApplicationTests.java
package com.tsccg;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Test
void contextLoads() {
}
}
⑥项目依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--继承spring-boot-starter-parent,位于仓库中-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--当前项目的坐标-->
<groupId>com.tsccg</groupId>
<artifactId>02-springboot-demo-first</artifactId>
<version>0.0.1-SNAPSHOT</version>
<!--项目描述,可删去-->
<name>02-springboot-demo-first</name>
<description>Demo project for Spring Boot</description>
<!--jdk版本-->
<properties>
<java.version>1.8</java.version>
</properties>
<!--依赖,版本为继承的spring-boot-starter-parent指定版本-->
<dependencies>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
</project>
web起步依赖相关jar:
⑦也可以通过浏览器打开初始化器页面
下载自动生成的项目文件,导入本地即可。
2.2.2 方式2:使用Maven向导
使用Maven向导的方式就是直接创建一个maven项目,按Spring Boot项目结构添加所需文件和配置。
使用Maven创建的好处是可以不用联网。
步骤:
①创建一个空的Maven项目
②修改pom.xml文件
1)添加spring-boot-starter-parent坐标
2)添加web启动依赖及其他配置
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--添加父坐标-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tsccg</groupId>
<artifactId>03-springboot-demo-second</artifactId>
<version>1.0-SNAPSHOT</version>
<!--添加其他所需配置-->
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<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>
</project>
③修改项目结构
1)创建启动类Application.java
,加入@SpringBootApplication 注解
package com.tsccg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2)在resources目录下创建static
、templates
文件夹,springboot核心配置文件application.properties
3)创建测试类ApplicationTests.java
,加入@SpringBootTest注解
package com.tsccg;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class ApplicationTests {
@Test
void contextLoads() {
}
}
2.3 基于Spring Boot的web例子
在Spring Boot项目中,使用SpringMVC时,不需要提前在配置文件中进行配置,直接使用就行。
步骤:
①基于前面创建的Spring Boot项目,我们直接写一个Controller类:HelloController
②启动Application类的main方法
可以发现内嵌的Tomcat已启动,默认为8080端口。
③在浏览器访问 http://localhost:8080/hello
2.4 @SpringBootApplication注解分析
启动类Application上的@SpringBootApplication注解是Spring Boot项目的重要注解。
其为一个复合注解,内部主要包含@SpringBootConfiguration、@EnableAutoConfiguration、@ComponentScan三个注解:
- @SpringBootConfiguration:内部包含@Configuration注解,作用是声明当前类为配置类,可当作配置文件。
- @EnableAutoConfiguration:开启自动配置,把一些java对象配置好,注入Spring容器中。
- @ComponentScan:组件扫描器,找到注解,根据注解的功能创建对象,给属性赋值等等。组件扫描器默认扫描的是 @ComponentScan 注解所在的类,类所在的包和子包。
2.5 Spring Boot核心配置文件
Spring Boot 的核心配置文件用于配置 Spring Boot 程序。
名字必须以 application
开始,后缀有两种格式:
-
.properties
:student.name=张三 student.age=21
-
.yml
/.yaml
:#属性与上级属性之间留两个空格,值与前面的冒号之间必须留一个空格 student: name: 张三 age: 21
2.5.1 .properties
文件(默认)
基于前面2.3的web例子进行修改。
①修改application.properties属性配置文件,设置Tomcat启动时开放的端口号以及上下文路径
application.properties:
#设置端口号
server.port=8082
#设置上下文路径
server.servlet.context-path=/boot
②启动应用:
③在浏览器访问 http://localhost:8082/boot/hello
2.5.2 .yml
文件(推荐)
同基于前面2.3的web例子进行修改。
①对原有的application.properties文件进行删除或修改文件名称
若两种格式的文件同时存在,则优先用application.properties
②在resource目录下创建一个application.yml文件,在其中设置端口号和上下文路径
#设置端口号与上下文路径
#属性与上级属性之间留两个空格,值与前面的冒号之间留一个空格
server:
port: 8083
servlet:
context-path: /boot2
③启动应用
若配置未生效则用maven执行clean-->install操作。
④在浏览器访问 http://localhost:8083/boot2/hello
2.5.3 多环境配置
在实际开发的过程中,我们的项目会经历很多的阶段(开发->测试->上线),每个阶段的配置也会不同。例如:端口、上下文路径、数据库等。
为了方便在不同的环境之间切换,SpringBoot 提供了多环境配置,具体操作如下:
基于2.3的web项目进行修改。
①分别为开发、测试、生产环境创建一个配置文件
命名必须以application-自定义环境标识.properties|yml
为准
②在application.yml中指定使用哪个环境的配置,如下:
启动应用,在浏览器访问 http://localhost:9081/dev/hello
③修改application.yml,指定为测试环境
重启应用,在浏览器中访问 http://localhost:9082/test/hello
2.5.4 自定义配置项
SpringBoot 的核心配置文件中,除了使用内置的配置项之外,我们还可以添加自定义配置项,然后采用@Value或@ConfigurationProperties读取配置项的属性。
2.5.4.1@Value
用法:@Value("${key}") , key 来自 application.properties(yml)
例子:基于2.3web案例进行修改
①在application.properties核心配置文件中加入内置配置项和自定义配置项
#内置配置项
server.port=8081
server.servlet.context-path=/read
#自定义配置项
student.name=张三
student.age=18
wite=www.xxx.com
②修改HelloController
1)添加私有属性并用@Value注解读取application.properties文件的数据进行注入
2)添加处理器方法将属性响应到浏览器
@RestController
public class HelloController {
@Value("${server.port}")
private String port;
@Value("${student.name}")
private String name;
@Value("${student.age}")
private Integer age;
@Value("${wite}")
private String wite;
@RequestMapping("/data")
public String readData() {
return name + "由于年龄未到" + age + ",所以不能从" + port + "端口访问" + wite;
}
}
③启动应用,在浏览器访问 http://localhost:8081/read/data
2.5.4.2@ConfigurationProperties
@ConfigurationProperties:可以把配置文件中的数据映射为java对象,适用于自定义配置项较多的情况。用在类上或配置类方法上。
属性:prefix,用于匹配配置文件中某些配置项开头的内容,如:指定prefix为student,那么就会匹配student.name、student.age等以student开头的配置项。
prefix可以不指定,如果不指定,那么会去配置文件中寻找与该类的属性名一致的配置项,prefix的作用是区分同名配置。
案例演示:(基于上一个例子)
①创建一个java类Student
1)使用@Component注解创建对象并注入容器
2)使用@ConfigurationProperties注解从配置文件中读取配置数据为该类注入属性
package com.tsccg.pojo;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Component
@ConfigurationProperties(prefix = "student")
public class Student {
private String name;
private Integer age;
//get set
//toString
}
使用ConfigurationProperties 注解,IDEA 会出现一个警告,但是不影响程序的执行。在pom中加入如下依赖后,重启项目即可消除。
<!--处理使用@ConfigurationProperties 注解出现警告问题-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
②创建StudentController类
@RestController
public class StudentController {
@Resource//自动注入
private Student student;
@RequestMapping("/student")
public String readStudent() {
return student.toString();
}
}
③开启应用,在浏览器访问http://localhost:8081/read/student
2.6 在Spring Boot项目中使用JSP
Spring Boot默认不支持JSP,而是使用模板技术代替jsp。
若要使用jsp需要进行以下配置:
①添加依赖
<!--引入Spring Boot内嵌的Tomcat对JSP的解析包不加解析不了jsp页面-->
<!--如果只是使用JSP页面可以只添加该依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
<!--如果要使用servlet必须添加该以下两个依赖-->
<!--servlet依赖的jar包-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<!--jsp依赖jar包-->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.1</version>
</dependency>
<!--如果使用 JSTL 必须添加该依赖-->
<!--jstl 标签依赖的 jar 包 start-->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
②指定jsp文件编译后的存放目录
SpringBoot 要求 jsp 文件必须编译到指定的 META-INF/resources 目录下才能访问,否则访问不到。
在pom.xml的build标签配置如下信息
<resources>
<resource>
<!--源文件位置-->
<directory>src/main/webapp</directory>
<!--指定编译到 META-INF/resource,该目录不能随便写-->
<targetPath>META-INF/resources</targetPath>
<!--指定要把哪些文件编译进去,**表示 webapp 目录及子
目录,*.*表示所有文件-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
<!--把src/main/resources下面的所有文件,都包含到classes目录-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
③在src/main/目录下创建存放jsp文件的目录:webapp ,并在项目中指定为Web Resource Directory,创建一个jsp文件index.jsp
④在index.jsp中获取请求作用域的数据
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
</head>
<body>
${data}
</body>
</html>
⑤在application.properties配置文件中配置SpringMVC中的视图解析器
server.port=9090
#视图前缀
spring.mvc.view.prefix=/
#视图后缀
spring.mvc.view.suffix=.jsp
⑥创建JspController,返回视图
package com.tsccg.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class JspController {
@RequestMapping("/doSome")
public String doSome(Model model) {
//向请求作用域中放入数据
model.addAttribute("data","Spring Boot整合Jsp");
return "index";
}
}
⑦开启应用,访问 http://localhost:9090/doSome
2.7 Spring Boot中使用容器对象(ApplicationContext)
我们点进启动类中SpringApplication的run方法,发现run方法中返回了一个ConfigurationApplicationContext类型对象,继续点开ConfigurationApplicationContext,发现是一个接口,继承了ApplicationContext。
ApplicationContext为Spring的容器对象,通过该对象可以直接获取容器中的Bean对象。
当我们在不想启动整个项目的前提下测试部分代码时,可以通过main方法中的SpringApplication.run()语句获取返回的Spring容器对象,获取业务bean进行调用。
演示:
①创建业务接口 HelloService
package com.tsccg.service;
public interface HelloService {
void sayHello(String name);
}
②创建业务接口实现类 HelloServiceImpl
package com.tsccg.service.impl;
import com.tsccg.service.HelloService;
import org.springframework.stereotype.Service;
@Service(value = "helloService")
public class HelloServiceImpl implements HelloService {
@Override
public void sayHello(String name) {
System.out.println("Hello " + name);
}
}
③在启动类main方法中,获取容器对象,取出业务bean对象调用其方法
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//获取容器对象
ConfigurableApplicationContext app = SpringApplication.run(Application.class, args);
//获取业务bean对象
HelloService helloService = (HelloService) app.getBean("helloService");
//调用方法
helloService.sayHello("张三");
}
}
④启动应用
2.8 CommandLineRunner接口
开发中可能会有这样的情景:需要在容器启动后执行一些内容,比如读取配置文件,数据库连接之类的。SpringBoot 给我们提供了两个接口来帮助我们实现这种需求,使用任意一个都可以
- CommandLineRunner
- ApplicationRunner
它们的执行时机为容器启动完成的时候,这两个接口中都有一个 run 抽象方法,我们只需要实现这个方法即可。这两个接口的不同之处在于 :
- ApplicationRunner接口中的run方法参数为 ApplicationArguments
- CommandLineRunner接口中run方法的参数为 String 数组
@FunctionalInterface
public interface CommandLineRunner {
void run(String... args) throws Exception;
}
@FunctionalInterface
public interface ApplicationRunner {
void run(ApplicationArguments args) throws Exception;
}
演示使用:
以2.7中的例子为基础,进行修改。
①修改启动类
使启动类实现CommandLineRunner接口,实现其run方法
@SpringBootApplication
public class Application implements CommandLineRunner {
@Resource
private HelloService helloService;
public static void main(String[] args) {
System.out.println("准备创建容器对象");
SpringApplication.run(Application.class, args);
System.out.println("创建容器对象后");
}
@Override
public void run(String... args) throws Exception {
System.out.println("容器对象创建好后,执行的方法");
String result = helloService.sayHello("李四");
System.out.println("调用容器对象中的方法:" + result);
}
}
②开启应用
第3章 Spring Boot与web组件
三个内容:
- 拦截器 HandlerInterceptor
- Servlet
- 过滤器 Filter
3.1 拦截器
拦截器是SpringMVC中的一种对象,能够拦截对Controller的请求,实现对请求的预先处理。
3.1.1 回顾SpringMVC中使用拦截器
①自定义拦截器,实现HandlerInterceptor接口
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
②在SpringMVC配置文件中注册拦截器类
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="拦截的url" />
<bean class="拦截器类全限定名称"/>
</mvc:interceptor>
</mvc:interceptors>
3.1.2 在Spring Boot中使用拦截器
在Spring Boot中使用拦截器与SpringMVC中使用的步骤大体一致,都是先自定义拦截器,然后将其注册到项目中。
只不过在Spring Boot中要把拦截器注册到@Configuration修饰的配置类中。
具体步骤:
①自定义拦截器
创建java类实现 HandlerInterceptor 接口,实现preHandle方法
package com.tsccg.handlerInterceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("执行了自定义拦截器的preHandle方法");
return true;
}
}
②注册拦截器
- 创建java类实现WebMvcConfigurer接口,实现其addInterceptors方法,用@Configuration注解修饰该类
- 将自定义的拦截器对象注册到项目中,设置拦截和放行的url
package com.tsccg.config;
import com.tsccg.handlerInterceptor.MyLoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 相当于SpringMVC配置文件
*/
@Configuration
public class MyAppConfig implements WebMvcConfigurer {
/**
* 注册拦截器
* @param registry 登记系统中可以使用的拦截器对象
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
//拦截的url
String path = "/user/**";
//放行的url
String excludePath = "/user/login";
registry.addInterceptor(new MyLoginInterceptor())
.addPathPatterns(path).excludePathPatterns(excludePath);
}
}
③创建测试用的Controller
@RestController
public class UserController {
@RequestMapping("/user/account")
public String account() {
return "10000";
}
@RequestMapping("/user/login")
public String login() {
return "登录界面";
}
}
④启动应用
1)通过浏览器访问受拦截的url: http://localhost:8080/user/account
可见,在发送请求后,后台执行了自定义的拦截器方法
2)通过浏览器访问放行的url: http://localhost:8080/user/login
可见,在发送请求后,后台没有执行拦截器方法
3.2 Servlet
ServletRegistrationBean用来注册Servlet对象
使用步骤:
①创建Servlet
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.print("使用Servlet对象");
out.flush();
out.close();
}
}
②注册Servlet
@Configuration
public class MyAppConfig{
/**
* 注册Servlet
* @return
*/
@Bean
public ServletRegistrationBean servletRegistrationBean() {
//ServletRegistrationBean reg = new ServletRegistrationBean(new MyServlet(),"/myServlet");
ServletRegistrationBean reg = new ServletRegistrationBean();
//注册Servlet对象
reg.setServlet(new MyServlet());
//设置请求路径
reg.addUrlMappings("/myServlet");
return reg;
}
}
③启动应用,在浏览器中访问 http://localhost:8080/myServlet
3.3 过滤器
FilterRegistrationBean 用来注册 Filter 对象
使用步骤:
①自定义过滤器,实现javax.servlet.Filter接口
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("执行了自定义过滤器,方法:doFilter");
chain.doFilter(request,response);
}
}
②注册过滤器
@Configuration
public class MyAppConfig{
/**
* 注册过滤器对象
* @return
*/
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean bean = new FilterRegistrationBean();
//注册自定义过滤器对象
bean.setFilter(new MyFilter());
//设置过滤的url
bean.addUrlPatterns("/user/*");
return bean;
}
}
③创建Controller
@RestController
public class MyController {
@RequestMapping("/user/account")
public String userAccount() {
return "过滤器使用测试";
}
@RequestMapping("/member/account")
public String memberAccount() {
return "过滤器使用测试2";
}
}
④启动应用
1)访问过滤器指定范围内的地址: http://localhost:8080/user/account
2)访问过滤器指定范围外的地址: http://localhost:8080/member/account
3.4 字符集过滤器
3.4.1回顾SpringMVC使用字符集过滤器
CharacterEncodingFilter是框架提供的字符集过滤器,解决post方式请求中文字符乱码的问题。
在通过SpringMVC框架使用该过滤器时,需要在web.xml中注册该过滤器,配置其属性:
<!--注册字符集过滤器-->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>forceResponseEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3.4.2在Spring Boot中使用字符集过滤器
使用的方式有两种:
1.在配置类中注册
2.在Spring Boot核心配置文件中设置
1.在配置类中注册
步骤:
①创建Servlet,在不设置utf-8的情况下响应中文字符
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html");//不设置utf-8字符集
PrintWriter out = resp.getWriter();
out.print("====中文测试数据====");//响应中文字符
out.flush();
out.close();
}
}
②注册Servlet
@Configuration
public class MyAppConfig{
/**
* 注册Servlet
* @return
*/
@Bean
public ServletRegistrationBean servletRegistrationBean() {
ServletRegistrationBean bean =
new ServletRegistrationBean(new MyServlet(),"/user/inf");
return bean;
}
}
③开启应用,在浏览器访问 http://localhost:8080/user/inf
可见,响应的中文字符发生乱码。
④在配置类中注册字符集过滤器
@Configuration
public class MyAppConfig{
/**
* 注册Servlet
* @return
*/
@Bean
public ServletRegistrationBean servletRegistrationBean() {
ServletRegistrationBean bean =
new ServletRegistrationBean(new MyServlet(),"/user/inf");
return bean;
}
/**
* 注册过滤器
* @return
*/
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean bean = new FilterRegistrationBean();
//创建框架提供的字符集过滤器类
CharacterEncodingFilter filter = new CharacterEncodingFilter();
filter.setEncoding("utf-8");//设置encoding属性为utf-8
filter.setForceEncoding(true);//设置请求对象和响应对象的字符编码集与encoding属性一致
bean.setFilter(filter);//注册字符集过滤器
bean.addUrlPatterns("/user/*");//设置过滤的url
return bean;
}
}
⑤在application.properties中添加如下配置
server.servlet.encoding.enabled=false
⑥重启应用,重新访问
2.在核心配置文件中设置
Spring Boot 项目默认启用了 CharacterEncodingFilter, 直接在application.properties中设置他的属性就可以:
#设置 spring boot 中 CharacterEncodingFitler 的属性值
server.servlet.encoding.enabled=true
server.servlet.encoding.charset=utf-8
#强制 request, response 使用 charset 他的值 utf-8
server.servlet.encoding.force=true
重启应用,重新访问:
第4章 ORM操作数据库
对象关系映射(Object Relational Mapping,简称ORM),是一种程序设计技术,用于实现面向对象程序语言里不同类型系统的数据之间的转换。
MyBatis就是ORM的一种,下面将展示在Spring Boot项目中使用MyBatis操作MySQL数据库。
建表:
步骤分析:
- 创建Spring Boot项目,勾选Web、MyBatis、MySQL Driver起步依赖
- 在application.properties中配置数据库连接信息
- 创建实体类Student
- 创建Controller,接收浏览器请求,访问Service
- 创建Service接口及其实现类,调用Dao接口方法
- 创建Dao接口,添加查询方法
- 在Dao接口同级目录下创建对应Mapper文件,指定namespace,写sql语句
- 在pom.xml中指定把src/main/java目录中的xml文件包含到classpath中
其中,创建Dao代理对象的方式有两种:
- 在每个Dao接口上添加@Mapper
- 在启动类上添加@MapperScan(basePackages = {"com.tsccg.dao","com.tsccg.dao2"})
4.1 第一种方式:@Mapper
①创建Spring Boot项目,勾选Web、MyBatis、MySQL Driver起步依赖
②在application.properties中配置数据库连接信息
#项目端口号
server.port=9090
#数据库连接信息
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db_mybatis?useUnicode=true&characterEncoding=UTF-8&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456
③创建Student实体类
package com.tsccg.pojo;
public class Student {
private Integer id;
private String name;
private String email;
private Integer age;
//get set
//toString
}
④创建Controller
package com.tsccg.controller;
@RestController
public class StudentController {
@Resource
private StudentService studentService;
@RequestMapping("/find")
public String findStudent(Integer id) {
Student student = studentService.findById(id);
return student.toString();
}
}
⑤创建Service
StudentService接口:
package com.tsccg.service;
import com.tsccg.pojo.Student;
public interface StudentService {
Student findById(Integer id);
}
接口实现类:
package com.tsccg.service.impl;
import javax.annotation.Resource;
@Service
public class StudentServiceImpl implements StudentService {
@Resource
private StudentDao studentDao;
@Override
public Student findById(Integer id) {
return studentDao.findById(id);
}
}
⑥创建Dao
StudentDao接口:
package com.tsccg.dao;
import com.tsccg.pojo.Student;
import org.apache.ibatis.annotations.Mapper;
@Mapper//告诉MyBatis这是dao接口,创建此接口的代理对象。
public interface StudentDao {
Student findById(Integer id);
}
在同级目录下创建StudentDao.xml
<?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.tsccg.dao.StudentDao">
<!--根据id查询学生信息-->
<select id="findById" parameterType="int" resultType="com.tsccg.pojo.Student">
select id,name,email,age from t_student where id = #{id}
</select>
</mapper>
⑦由于是在src/main/java目录下创建的mapper映射文件,故需要在pom.xml中指定把src/main/java目录中的xml文件包含到classpath中
在build标签内添加如下语句:
<resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</resource>
</resources>
⑧开启应用,在浏览器访问 http://localhost:9090/find?id=1001
4.2 第二种方式:@MapperScan
第一种方式需要在每一个Dao接口上都加@Mapper,当Dao接口较多时不方便。
而这种方式只需要在启动类上添加@MapperScan(basePackages = "com.tsccg.dao")即可。
@SpringBootApplication
@MapperScan(basePackages = "com.tsccg.dao")
//@MapperScan(basePackages = {"com.tsccg.dao","com.tsccg.dao2"})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4.3 将Mapper文件与java代码分开管理
我们在项目中更偏向于将mapper文件与java代码分开管理,就是将mapper文件都放在src/main/resources目录下,将java代码都放在src/main/java目录下。
有两种分离方式:
- 第一种:在resources目录下创建com.tsccg.dao目录,使得编译后将mapper文件和Dao.class文件放在一起
- 第二种:在resources目录下创建自定义子目录,在核心配置文件中指定从类路径下的该目录找mapper文件
4.3.1第一种分离方式
在resources目录下创建com.tsccg.dao目录,将mapper文件都放进去。
这种分离方式可以在项目编译后,将mapper文件与StudentDao.class文件放在一起,如下:
步骤:
①在resources目录下创建com.tsccg.dao目录,将mapper文件移动至该目录下。
注意,在resources目录下创建com.tsccg.dao目录时,必须用/
表示分层,如下:
不然会将com.tsccg.dao当作一个目录名,编译后不会将mapper文件与StudentDao.class放在一起。
②在pom.xml中注释掉原先设置的resources标签,不然会编译报错
③重启应用,通过浏览器重新访问
4.3.2第二种分离方式
第二种方式可以告诉程序从什么位置找到mapper文件,无需让mapper文件与编译后的StudentDao.class位于同级目录。
步骤:
①在resources目录下创建自定义的子目录,如mapper,然后将mapper文件放入。
②在application.properties核心配置文件中指定mapper文件所在位置
#指定mapper文件的位置
mybatis.mapper-locations=classpath:mapper/*.xml
#指定使用mybatis的日志
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
③同样需要在pom.xml中注释掉原先设置的resources标签,不然会编译报错
④重启应用,重新访问地址
4.4事务
在Spring Boot中使用事务很简单,底层用的还是Spring提供的事务管理。
使用步骤:
- 在入口类上添加
@EnableTransactionManagement
注解开启事务支持(默认开启,但最好添上) - 在访问数据库的Service接口实现类上添加
@Transactional
注解即可
实例演示:
以4.1中的例子为基础进行修改。
①分别在入口类上和Service接口实现类上添加事务注解
②在Controller里添加删除方法
使用try...catch语句监控Service中是否抛出异常,响应相应信息。
@RestController
public class StudentController {
@Resource
private StudentService studentService;
@RequestMapping("/delete")
public String deleteStudentById(Integer id) {
try {
//通过id删除学生信息
studentService.deleteById(id);
return "删除成功";
} catch (Exception e) {
e.printStackTrace();
return "删除失败";
}
}
}
③在Service接口中添加删除方法并在实现类中实现
StudentService:
public interface StudentService {
//通过id删除学生信息
void deleteById(Integer id);
}
StudentServiceImpl:
@Service
@Transactional//开启事务
public class StudentServiceImpl implements StudentService {
@Resource
private StudentDao studentDao;
@Override
public void deleteById(Integer id) {
studentDao.deleteById(id);//调用Dao删除数据
int a = 10 / 0;//抛出运行时异常
}
}
④在Dao接口中定义删除方法并在Mapper文件中添加对应sql语句
StudentDao:
public interface StudentDao {
void deleteById(Integer id);
}
StudentDao.xml:
<?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.tsccg.dao.StudentDao">
<delete id="deleteById" parameterType="int">
delete from t_student where id = #{id}
</delete>
</mapper>
⑤测试
开启应用,通过浏览器访问 http://localhost:9090/delete?id=1006
第5章 RESTful 接口架构风格
5.1 RESTful简介
REST(Representational State Transfer),表现层资源状态转移。
REST是一种互联网软件架构设计的风格,并不是标准,可用也可不用。它只是提出了一组客户端与服务器交互时的架构理念和设计原则,基于这种理念和原则设计的接口可以更简洁,更有层次。说白了,就是一种统一的url命名格式,将CRUD操作的url命名规范化,统一化。
表现层资源状态转移 概念说明:
- 表现层:就是视图层,显示资源的,通过视图页面、jsp等显示操作资源的结果。
- 资源:服务器端的动静态资源文件,数据库表中的数据等都是资源。每个资源都是服务器上一个可命名的抽象概念,是以名词为核心来组织的,如用user表示用户在服务端数据库的信息。一个资源可由一个或多个url来标识,url既是资源的名称,也是Web上的地址。在浏览器等客户端上,可以通过资源的url与其进行交互。
- 资源状态:就是对于资源的表述,当我们通过浏览器访问一个视频、一段文字或一张图片时,对应资源的表述格式是不一样。
- 资源状态转移:资源状态转移说的是资源在客户端和服务端之间转移(请求资源-响应资源)的表述。通过转移和操作资源的表述来实现操作资源的目的。
5.2 RESTful的实现
我们过去访问一个资源所用的url五花八门,如访问一个用户信息:
http://localhost:8080/findUserById?id=1001 GET //查询一个用户信息
http://localhost:8080/addUser POST //添加用户信息
http://localhost:8080/updateUser POST //更新用户信息
http://localhost:8080/deleteUserById?id=1001 GET //删除一个用户信息
以上这些url所操作的都是同一个资源,在url内就写明了对该资源的操作。
而REST是面向资源的,资源是通过url进行暴露的。REST中,url的设计只需要把资源通过合理的方式暴露出来即可,对资源的操作与url无关,操作是通过HTTP动词来体现的。
HTTP协议中,GET、POST、DELETE、PUT都是表示操作方式的动词。
它们分别对应四种基本操作:
- GET:获取资源
- POST:新建资源
- DELETE:删除资源
- PUT:更新资源
REST风格提倡url地址使用统一的风格设计,用名词表示资源,以及访问资源的信息,在url中,使用/
分隔对资源的访问信息。
修改上面的url为REST风格:
http://localhost:8080/user/1001 GET //查询一个用户信息
http://localhost:8080/user POST //添加用户信息
http://localhost:8080/user/1001 DELETE //删除一个用户信息
http://localhost:8080/user PUT //更新用户信息
现在问题有两个问题:
- 浏览器只支持GET和POST方式的请求,如何发送DELETE和PUT请求呢?
- 如何获取拼接到url中的请求参数值呢?
5.3 发送DELETE和PUT请求
在SpringMVC中 有一个过滤器,支持将POST请求转换为DELETE、PUT请求。
过滤器:org.springframework.web.filter.HiddenHttpMethodFilter
核心方法:
从过滤器方法中得出,我们可以在页面上用表单方式发送POST请求,在携带的请求参数中添加一个名为_method
的参数,值为DELETE
或PUT
。
如下:
<form action="/user" method="POST">
id:<input type="text" name="id"><br/>
姓名:<input type="text" name="name"><br/>
<!--请求方式参数,用户不需要看到,故设置为隐藏-->
<input type="hidden" name="_method" value="PUT"><br/>
<input type="submit" value="更新">
</form>
然后在项目中注册该过滤器即可将POST请求转换为PUT请求。
在application.properties中注册HiddenHttpMethodFilter过滤器:
spring.mvc.hiddenmethod.filter.enabled=true
此外,我们也可以通过ajax发送DELETE或PUT请求,但只有部分浏览器支持。
5.4 RESTful中的注解
在Spring Boot中开发RESTful主要由如下几个注解实现
① @PathVariable:获取拼接到url中的参数数据,是实现RESTful最主要的一个注解
② @GetMapping:接收和处理GET方式的请求,等同于 @RequestMapping(method=RequestMethod.GET)
③ @PostMapping:接收和处理POST方式的请求,等同于 @RequestMapping(method=RequestMethod.POST)
④ @DeleteMapping:接收和处理DELETE方式的请求,等同于 @RequestMapping(method=RequestMethod.DELETE)
⑤ @PutMapping:接收和处理PUT方式的请求,等同于 @RequestMapping(method=RequestMethod.PUT)
5.4 注解使用练习
以4.4中的例子为基础进行修改。
①在application.properties中注册HiddenHttpMethodFilter过滤器:
#设置端口号
server.port=9090
#注册HiddenHttpMethodFilter过滤器
spring.mvc.hiddenmethod.filter.enabled=true
②编写前端页面
在resources/static目录下新建index.html,发送crud四种请求
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<div id="app">
<h3>查询</h3>
<a href="/student/1001">查询</a>
<hr>
<h3>删除</h3>
<form action="/student/1007" method="POST">
<input type="hidden" name="_method" value="DELETE"><br>
<input type="submit" value="删除"><br/>
</form>
<hr>
<h3>添加</h3>
<form action="/student" method="POST">
id:<input type="text" name="id"><br/>
姓名:<input type="text" name="name"><br/>
<input type="submit" value="添加"><br/>
</form>
<hr>
<h3>更新</h3>
<form action="/student" method="POST">
id:<input type="text" name="id"><br/>
姓名:<input type="text" name="name"><br/>
<input type="hidden" name="_method" value="PUT"><br/>
<input type="submit" value="更新"><br/>
</form>
</div>
</body>
</html>
③编写Controller
package com.tsccg.controller;
@RestController
public class StudentController {
/**
* 根据id获取学生信息
* @PathVariable
* 1.作用:获取url中的数据
* 2.位置:处理器形参前
* 3.value:路径变量值 {studentId}
*/
@GetMapping("/student/{studentId}")//处理GET请求
public String findStudent(@PathVariable(value="studentId") Integer id) {
return "执行查询操作,id="+id;
}
/**
* 添加学生
*/
@PostMapping("/student")//处理POST请求
public String addStudent(@RequestParam Map<String,String> student) {
return "执行添加操作,student="+student;
}
/**
* 根据id删除学生信息
*/
@DeleteMapping("/student/{studentId}")//处理DELETE请求
public String deleteStudent(@PathVariable("studentId") Integer id) {
return "执行删除操作,id="+id;
}
/**
* 更新学生信息
*/
@PutMapping("/student")//处理PUT请求
public String updateStudent(@RequestParam Map<String,String> student) {
return "执行更新操作,student="+student;
}
}
④测试
开启应用,从浏览器访问 http://localhost:9090/index.html
5.5 REST注意URL+请求方式必须唯一
在REST中,必须保证URL+请求方式是唯一的,若出现如下情况,会报错。
@GetMapping("/student/{studentId}")
public String findStudentById(@PathVariable(value="studentId") Integer id) {
return "根据id查询学生信息";
}
@GetMapping("/student/{studentName}")
public String findStudentByName(@PathVariable(value="studentName") String name) {
return "根据姓名查询学生信息";
}
第6章 Spring Boot集成Redis
6.1 Redis简介
Redis是一个NoSQL数据库,常用作缓存使用。通过Redis客户端可以使用多种语言在程序中访问Redis数据。其中,java语言使用的客户端库有:Jedis、Lettuce、Redisson等。
那么在Spring Boot中,使用的Redis客户端库是什么呢?
创建一个Spring Boot项目,勾选Web和Redis起步依赖:
查看项目导入的Redis相关依赖:
可以看出,在Spring Boot中,默认使用的Redis客户端库为lettuce
6.2 演示添加和获取操作
①创建Spring Boot项目,勾选web和redis起步依赖
其中,Spring Boot会根据redis的起步依赖在容器中创建两个对象:
- RedisTemplate
- SpringRedisTemplate
<!--Spring Boot会在容器中创建两个对象:RedisTemplate、SpringRedisTemplate-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
在程序中使用RedisTemplate类的方法 操作redis数据, 实际就是调用的lettuce 客户端中的方法
②在核心配置文件application.properties中配置连接redis信息
#配置端口号
server.port=9090
#配置redis
spring.redis.host=localhost
spring.redis.port=6379
#spring.redis.password=123
③创建Controller
注入RedisTemplate对象,通过该对象的以ops
开头的几个方法获取操作redis中各种类型数据的对象
如:
- opsForValue()---->ValueOperations---->String类型数据
- opsForHash()---->HashOperations---->Hash类型数据
然后就可以通过获取的对象执行set/get方法,管理redis中的数据了。
package com.tsccg.controller;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
public class RedisController {
//注入RedisTemplate对象
@Resource
private RedisTemplate redisTemplate;
//向redis中添加String类型数据
@PostMapping("/student/{name}")
public String setKey(@PathVariable String name) {
//获取管理redis中String类型的对象
ValueOperations valueOperations = redisTemplate.opsForValue();
//执行添加操作
valueOperations.set("name",name);
return "添加了学生:"+name;
}
//从redis中获取添加的数据
@GetMapping("/student")
public String getValue() {
//获取管理redis中String类型的对象
ValueOperations valueOperations = redisTemplate.opsForValue();
//执行获取操作
return (String)valueOperations.get("name");
}
}
④测试
1)开启windows版redis服务
2)开启项目服务,通过postman客户端软件,以POST方式发送: http://localhost:9090/student/小明
3)再以GET方式发送请求:http://localhost:9090/student
4)通过Redis Desktop Manager桌面工具查看刚刚插入的数据
发现在redis中添加的数据为序列化的数据。
⑤修改Controller,注入StringRedisTemplate对象
package com.tsccg.controller;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@RestController
public class RedisController {
//修改注入StringRedisTemplate对象
@Resource
private StringRedisTemplate stringRedisTemplate;
//修改添加的数据为age
@PostMapping("/student/{age}")
public String setKey(@PathVariable String age) {
//通过StringRedisTemplate对象获取操作Stirng类型数据的对象
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
valueOperations.set("age",age);
return "添加了年龄:"+age;
}
//修改获取的数据为age
@GetMapping("/student")
public String getValue() {
ValueOperations valueOperations = stringRedisTemplate.opsForValue();
return (String)valueOperations.get("age");
}
}
⑥重新测试
重启应用,重新发送添加请求:
再次查看redis库中存入的数据:
发现这次在redis中存入的数据是正常的。
6.3 对比RedisTemplate和StringRedisTemplate
RedisTemplate:把key和value经过序列化存到redis中,key和value是序列化的内容,不能直接识别。默认使用的是jdk的序列化方式,可以修改为其它的系列化方式。
StringRedisTemplate:把key和value作为String处理,使用的是String的序列化,可读性好。
序列化与反序列化:
- 序列化:把对象转换为可传输的字节序列过程就叫序列化
- 反序列化:把字节序列还原为对象的过程就叫反序列化。
为什么要进行序列化?
我们在实际项目开发中,使用的redis都是放在linux上的,而为了让数据对象可以从其它地方跨平台存放到linux系统上去,就必须将对象序列化。
序列化最终的目的就是为了让对象可以跨平台存储,可以通过网络传输。而我们进行跨平台存储和网络传输的方式就是IO,IO支持的数据格式就是字节数组。我们必须在把对象转换为字节数组前就指定一种规则(序列化),那么我们从IO流读取数据的时候再以这种规则把对象还原。(反序列化)
序列化的常见方式:
序列化只是一种拆装组装对象的规则,这种规则也多种多样。比如现在常用的序列化方式有:JDK(不支持跨语言)、JSON、XML、Hessian、Kryo(不支持跨语言)、Thrift、Protofbuff 等。
-
jdk的序列化: 把java对象转为byte[], 二进制数据
-
json序列化:json序列化能将对象转换为 JSON 格式或从 JSON 格式转换为对象。例如把一个Student对象转换为JSON字符串{"name":"李四", "age":29} ),反序列化(将JSON字符串 {"name":"李四", "age":29} 转换为Student对象)
6.4 设置key和value的序列化方式
Redis数据序列化方式有:
其中,默认的序列化方式为jdk的序列化,将key和value转换为二进制字节数组。
6.4.1 设置为String序列化方式
①修改Controller
@RestController
public class RedisController {
@Resource
private RedisTemplate redisTemplate;
@PostMapping("/student/{key}/{value}")
public String setKey(@PathVariable String key,@PathVariable String value) {
// 使用RedisTemplate ,在存取值之前,设置序列化
//设置key的序列化方式为String
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式为String
redisTemplate.setValueSerializer(new StringRedisSerializer());
ValueOperations valueOperations = redisTemplate.opsForValue();
valueOperations.set(key,value);
return "添加:" + "key=" + key + ",value=" + value;
}
@GetMapping("/student/{key}")
public String getValue(@PathVariable String key) {
ValueOperations valueOperations = redisTemplate.opsForValue();
return (String)valueOperations.get(key);
}
}
②发送POST请求:http://localhost:9090/student/email/123@qq.com
③查看redis库:
6.4.2 设置为JSON序列化方式
①设置Idea自动生成序列化版本号
②创建实体类,实现序列化接口,在实体类中自动生成序列化版本号
③修改Controller,设置value为JSON序列化方式
@Resource
private RedisTemplate redisTemplate;
@PostMapping("/student")
public String addJson() {
//创建一个Student对象
Student student = new Student();
student.setName("Tom");
student.setAge(40);
student.setEmail("tom@163.com");
//设置key的序列化方式为String
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式为JSON
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Student.class));
//添加操作
redisTemplate.opsForValue().set("myStudent",student);
return "添加:"+student.toString();
}
@GetMapping("/student")
public String getValue() {
//设置key的序列化方式为String
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式为JSON
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Student.class));
ValueOperations valueOperations = redisTemplate.opsForValue();
return valueOperations.get("myStudent").toString();
}
④发送post请求: http://localhost:9090/student (序列化)
⑤查看redis库
⑥发送get请求: http://localhost:9090/student 反序列化
第7章 Spring Boot集成Dubbo
7.1 创建父模块
创建一个普通maven模块作为父模块,模块名:16-dubbo-parent
进行如下操作:
1)删除src目录
2)修改pom.xml,指定打包方式为pom
3)继承spring-boot-starter-parent模块
4)添加dubbo和zookeeper起步依赖
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--继承Spring Boot父模块-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/>
</parent>
<groupId>com.tsccg</groupId>
<artifactId>16-dubbo-parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging><!--指定打包方式为pom-->
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<!--添加dubbo起步依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-spring-boot-starter</artifactId>
<version>2.7.8</version>
</dependency>
<!--添加zookeeper依赖-->
<dependency>
<groupId>org.apache.dubbo</groupId>
<artifactId>dubbo-dependencies-zookeeper</artifactId>
<version>2.7.8</version>
<type>pom</type>
<!--dubbo起步依赖中已经包含了log4j依赖,排除zookeeper依赖中包含的重复依赖-->
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
7.2 创建公共接口模块
创建一个普通maven模块,无父模块,在此模块中只定义公共的接口和实体类。
模块名:common-interface
GAV坐标:
<groupId>com.tsccg</groupId>
<artifactId>common-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
创建实体类Student,实现序列化接口
package com.tsccg.pojo;
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private Integer age;
private String email;
//get set
//toString
}
创建公共接口 StudentService,定义方法
package com.tsccg.pojo.com.tsccg.service;
import com.tsccg.pojo.Student;
public interface StudentService {
//获取Studnet数据
Student getStudent();
}
7.3 创建服务消费者模块
创建普通maven模块:server-consumer,继承父模块 16-dubbo-parent
然后进行如下操作:
①在pom.xml中添加依赖
1)声明Spring Boot的web起步依赖
2)添加公共接口模块依赖
<dependencies>
<!--声明web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加公共接口模块依赖-->
<dependency>
<groupId>com.tsccg</groupId>
<artifactId>common-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
②在resources目录下创建application.properties核心配置文件,配置dubbo
#服务暴露接口
server.port=8081
##配置dubbo
#服务名称
spring.application.name=server-consumer
#扫描dubbo注解所在包
dubbo.scan.base-packages=com.tsccg.service
#指定注册中心地址,此处用的是本地的zookeeper
dubbo.registry.address=zookeeper://localhost:2181
③在java目录下创建com.tsccg.Application 启动类
添加开启Dubbo的注解:@EnableDubbo
package com.tsccg;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo//开启dubbo
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
④创建Controller
使用@DubboReference注解远程注入StudentService对象
package com.tsccg.controller;
import com.tsccg.pojo.Student;
import com.tsccg.pojo.com.tsccg.service.StudentService;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StudentController {
@DubboReference(version = "1.0")//dubbo远程注入
private StudentService studentService;
@GetMapping("/student")
public String getStudent() {
//调用服务方法
Student student = studentService.getStudent();
return student.toString();
}
}
7.4 创建服务提供者模块
同服务消费者,创建一个普通maven模块:server-provider,继承父模块
进行如下操作:
①添加依赖
<dependencies>
<!--声明web起步依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--公共接口依赖-->
<dependency>
<groupId>com.tsccg</groupId>
<artifactId>common-interface</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
②创建核心配置文件:application.properties,配置dubbo
#暴露服务接口
server.port=8080
##配置dubbo
#服务名称
spring.application.name=server-provider
#扫描dubbo注解所在包
dubbo.scan.base-packages=com.tsccg.service
#指定注册中心地址
dubbo.registry.address=zookeeper://localhost:2181
③创建启动类:Application,添加开启dubbo注解
package com.tsccg;
import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
@EnableDubbo//开启dubbo
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
④创建服务实现类
package com.tsccg.service.impl;
import com.tsccg.pojo.Student;
import com.tsccg.pojo.com.tsccg.service.StudentService;
import org.apache.dubbo.config.annotation.DubboService;
//使用Dubbo提供的@DubboService注解,指定接口class为StudentService.class
@DubboService(interfaceClass = StudentService.class,version = "1.0")
public class StudentServiceImpl implements StudentService{
@Override
public Student getStudent() {
//创建一个Student对象
Student student = new Student();
student.setName("杰瑞");
student.setAge(30);
student.setEmail("jerry@qq.com");
return student;
}
}
7.5 测试
①开启zookeeper
②先后运行服务提供者和服务消费者应用
③在浏览器中发送请求: http://localhost:8081/student
第8章 Spring Boot打包方式
Spring Boot 可以打包为 war 或 jar 文件。 以两种方式发布应用。
8.1 打war包
步骤:
1.创建一个Spring Boot项目,添加Web起步依赖
2.修改pom.xml
1)添加内嵌 Tomcat 对 jsp 的解析包依赖
<!--使用jsp-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
2)指定jsp编译目录
<build>
<!--jsp 文件必须编译到指定的 META-INF/resources 目录下-->
<resources>
<resource>
<!--源文件位置-->
<directory>src/main/webapp</directory>
<!--指定编译到 META-INF/resource,该目录不能随便写-->
<targetPath>META-INF/resources</targetPath>
<!--指定要把哪些文件编译进去,**表示 webapp 目录及子目录,*.*表示所有文件-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
<!--把src/main/resources下面的所有文件,都包含到classes目录-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
</build>
3)指定打包方式为war
4)指定打包后生成war包的名称
在build标签内添加如下语句:
<!--指定最终打包后的包名-->
<finalName>myBoot</finalName>
5)完整的pom.xml内容
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.tsccg</groupId>
<artifactId>17-package-war</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging><!--指定打包类型为war-->
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加jsp依赖-->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
</dependency>
</dependencies>
<build>
<!--jsp 文件必须编译到指定的 META-INF/resources 目录下-->
<resources>
<resource>
<!--源文件位置-->
<directory>src/main/webapp</directory>
<!--指定编译到 META-INF/resource,该目录不能随便写-->
<targetPath>META-INF/resources</targetPath>
<!--指定要把哪些文件编译进去,**表示 webapp 目录及子目录,*.*表示所有文件-->
<includes>
<include>**/*.*</include>
</includes>
</resource>
<!--把src/main/resources下面的所有文件,都包含到classes目录-->
<resource>
<directory>src/main/resources</directory>
<includes>
<include>**/*.*</include>
</includes>
</resource>
</resources>
<!--指定最终打包后的包名-->
<finalName>myBoot</finalName>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.创建webapp并引入项目,在其中创建index.jsp作为视图
4.配置视图解析器
在核心配置文件 application.properties中添加如下内容:
#前缀
spring.mvc.view.prefix=/
#后缀
spring.mvc.view.suffix=.jsp
5.创建Controller
package com.tsccg.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
@Controller
public class WarController {
@RequestMapping("/doSome")
public String doSome(Model model) {
model.addAttribute("data","war包");
return "index";
}
}
6.测试,开启应用,在浏览器中访问 http://localhost:8080/doSome
7.让启动类继承SpringBootServletInitializer
只有继承了此类,重写其configure方法后,生成的war包才能单独部署到外部的服务器中。
SpringBootServletInitializer就是原有的web.xml文件的替代。使用了嵌入式Servlet,默认不支持jsp。
package com.tsccg;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
@SpringBootApplication
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
return builder.sources(Application.class);
}
}
8.部署至外部独立服务器
1)将生成的war包部署到外部的Tomcat服务器中
通过maven执行clean---->package后,将target 目录下的 war 文件拷贝到 tomcat 服务器 webapps 目录中
2)启动Tomcat
3)在浏览器中访问 http://localhost:8080/myBoot/doSome
多出的/myBoot
是由于我们开启tomcat后,会自动将war文件解压缩,我们的项目文件都在解压缩的文件夹中。
8.2 打jar包
以前面打war包的例子为基础进行修改。
1.修改pom.xml
1)指定打包方式为jar
默认打包类型就是jar,删除原先指定的war包语句即可
2)指定springboot-maven-plugin版本
打包jar,有jsp文件时,必须指定maven-plugin插件的版本是 1.4.2.RELEASE
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<!--指定maven-plugin插件的版本为1.4.2.RELEASE-->
<version>1.4.2.RELEASE</version>
</plugin>
</plugins>
3)修改Controller
@RequestMapping("/doOther")
public String doOther(Model model) {
model.addAttribute("data","jar包");
return "index";
}
4)修改主启动类不继承SpringBootServletInitializer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.执行打包,通过cmd窗口执行命令运行jar包,启动内置的Tomcat
1)通过maven执行clean-->package,生成myBoot.jar
2)进入myBoot.jar包所在目录,打开cmd窗口
3)运行启动命令,启动内置的Tomcat
java -jar myBoot.jar
4)在浏览器中发送请求 http://localhost:8080/doOther
8.3 war包部署与jar包部署的区别
war包必须部署到独立的外部服务器上,占用资源较多。但独立的服务器功能较多,这种方式能更好的利用服务器。
jar包可以通过内置的tomcat单独运行,占用资源少。但内置的服务器功能较少,性能不如war包方式。
8.4 Spring Boot项目部署和运行方式总结
8.4.1 开发阶段
在IDEA中直接运行主启动类的main方法。
8.4.2 上线部署阶段
1.打jar包
在IDEA中通过maven插件将项目打成jar包,可用java -jar xxx.jar
命令启动内置的Tomcat。
上线部署到Linux系统上时,可以将该命令封装到一个Shell脚本中,步骤如下:
①在jar包同级目录里创建一个shell脚本,编写如下内容
run.sh:
#!/bin/sh
java -jar xxx.jar
②赋予权限
chmod 777 run.sh
③启动shell脚本
./run.sh
2.打war包
在IDEA中通过maven插件将项目打成war包,单独部署到tomcat等服务器的发布目录下运行