教程9-11:
黑马教程基础篇-09-入门案例解析:starter_哔哩哔哩_bilibili
使用spring boot,在配置依赖的时候可以不需要写依赖坐标,是通过starter实现的,例如想写个依赖只需要这样
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
spring有容器,spring boot同样也有容器,就在启动类的里面
package spring_01_01_quickstart; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; import spring_01_01_quickstart.com.itheima.controller.BookController; @SpringBootApplication public class Spring0101QuickstartApplication { public static void main(String[] args) { ConfigurableApplicationContext ctx= SpringApplication.run(Spring0101QuickstartApplication.class, args); BookController bean=ctx.getBean(BookController.class); System.out.println("bean="+ bean); } }
可以看到在运行后能将bean输出出来
在点开SpringBootApplication注解后可以看到里面有一个ComponentScan注解,当没有指定包时,这个注解会默认扫描当前类所在包及其子包,所以当有配置类不在这里面的时候,spring boot容器是扫描不到的
基础篇-11-入门案例:辅助功能_哔哩哔哩_bilibili
spring boot中没有配置tomcat服务器,但是同样能正常运行,原因是将tomcat服务器的执行过程抽取出来变成一个对象,并且交给spring容器去管理,也就是说spring容器中有一个tomcat对象,然后在tomcat这个对象中运行,所以也可以将这个tomcat服务器换成别的 ,如下图是换成了jetty
Rest风格:
[补]知识加油站-01-REST风格简介_哔哩哔哩_bilibili
[补]知识加油站-02-RESTful入门案例_哔哩哔哩_bilibili
[补]知识加油站-03-RESTful快速开发_哔哩哔哩_bilibili
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import javax.websocket.server.PathParam;
@Controller
public class UserController {
@RequestMapping(value = "/users",method = RequestMethod.POST)//method后面是设置请求的方式,比如此处为POST请求时
@ResponseBody
public String save(){
System.out.println("user save...");
return "{'module':'user save'}";
}
@RequestMapping(value = "/users",method = RequestMethod.PUT)//method后面是设置请求的方式,比如此处为PUT请求时
@ResponseBody
public String update(@RequestBody User user){
System.out.println("user = " + user);
return "{'module':'user update'}";
}
@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)
@ResponseBody
public String delete(@PathVariable Integer id){//@PathVariable注解代表此处需要的参数是从地址中获取的,加上这个参数后还需要在value处加上{}并且其中放入这个参数的名
System.out.println("user delete"+id);
return "{'module':'user delete'}";
}
}
可以看出这个代码中每个方法都有一些重复的东西,比如每个value中都含有/users,都加的ResponseBody注解,这些可以一起放到类上面从而使得更加简洁,如下图
同时@RequestMapping(method = RequestMethod.POST)也可以用PostMapping注解来代替
// @RequestMapping(method = RequestMethod.POST)
@PostMapping
public String save(){
System.out.println("user save...");
return "{'module':'user save'}";
}
配置properties文件的一些
#服务器端口配置
#server.port=80
#修改banner
spring.main.banner-mode=off
#spring.banner.image.location=faker.jpg
#只显示报错时的日志信息
#logging.level.root=error
关于properties文件中的配置可以看这里Common Application Properties (spring.io)
优先级是properties>yml>yaml,核心格式是数据前面要用空格跟冒号隔开
有时候会出现在配置文件中不出提示的现象,原因是idea未识别出该文件为配置文件,需要进行配置一下
基础篇-19-读取yaml单一属性数据_哔哩哔哩_bilibili
取出yml文件中的内容
yml文件中的内容,以及java读取到zi'fu'ch
country: china
@Value("${country}")
String country;
想要在yml文件中引用相应的属性的话
a: 1
b: ${a}
这样,b的值就也是1了
a: \n
b: "\n"
像a这样直接写\n的话输出还是\n这样一个字符串,如果想让转义字符\生效的话,需要像b这样写到一个字符串中
也可以使用自动装配将所有数据封装到一个Environment对象中,再输出出来
@Autowired
Environment env;
System.out.println(env.getProperty("b"));
System.out.println(env.getProperty("a"));
自定义对象封装指定数据
后期等到yml文件中的数据多了之后,想让他们分开赋值,如下想让一个对象只含有test中的内容,而其他的内容如country不含有
server:
port: 81
country: china
a: \n
b: "\n"
test:
c: 1
d: 2
e: 3
f: 4
g: 5
实现这个效果需要先创建一个数据模型封装配置文件中的数据如下
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
//1.定义数据模型封装yml文件中对应的数据
//2.定义为spring管控的bean
@Component
//3.指定加载的数据
@ConfigurationProperties(prefix = "test")
public class MyDataSource {
private String c;
private String d;
private String e;
private String f;
private String g;
@Override
public String toString() {
return "MyDataSource{" +
"c='" + c + '\'' +
", d='" + d + '\'' +
", e='" + e + '\'' +
", f='" + f + '\'' +
", g='" + g + '\'' +
'}';
}
public void setC(String c) {
this.c = c;
}
public void setD(String d) {
this.d = d;
}
public void setE(String e) {
this.e = e;
}
public void setF(String f) {
this.f = f;
}
public void setG(String g) {
this.g = g;
}
public String getC() {
return c;
}
public String getD() {
return d;
}
public String getE() {
return e;
}
public String getF() {
return f;
}
public String getG() {
return g;
}
}
@Autowired
MyDataSource myDataSource;
@GetMapping
public void getById(){
System.out.println(myDataSource);
}
此时运行程序后就会输出下图所示结果
整合第三方技术(26-31)
基础篇-23-SpringBoot整合JUnit_哔哩哔哩_bilibili
使用测试类时,如果测试类中的package的包与引导类的不一样,将无法运行,解决方法可以在SpringBootTest注解中加入(classes=...),...为引导类名或者再加一个ContextConfiguration(classes=...),这样就能解决这个问题
基础篇-25-SpringBoot整合MyBatis_哔哩哔哩_bilibili
创建新项目,需要勾选这两个选项
先在配置文件中设置相应的datasource数据,然后创建一个实体类以及dao
yml文件:
spring:
datasource:
url: jdbc:mysql://localhost:3306/world?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 1027wu
driver-class-name: com.mysql.cj.jdbc.Driver
package com.example.spring_05_mybatis;
public class domain {
public String ID;
public String Name;
public String CountryCode;
public String District;
public String Population;
@Override
public String toString() {
return "domain{" +
"ID='" + ID + '\'' +
", Name='" + Name + '\'' +
", CountryCode='" + CountryCode + '\'' +
", District='" + District + '\'' +
", Population='" + Population + '\'' +
'}';
}
public void setID(String ID) {
this.ID = ID;
}
public void setName(String name) {
Name = name;
}
public void setCountryCode(String countryCode) {
CountryCode = countryCode;
}
public void setDistrict(String district) {
District = district;
}
public void setPopulation(String population) {
Population = population;
}
public String getID() {
return ID;
}
public String getName() {
return Name;
}
public String getCountryCode() {
return CountryCode;
}
public String getDistrict() {
return District;
}
public String getPopulation() {
return Population;
}
}
package com.example.spring_05_mybatis.dao;
import com.example.spring_05_mybatis.domain;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.awt.print.Book;
@Mapper
public interface BookDao {
@Select("select * from city where ID = #{id}")
public domain getById(Integer id);
}
在测试类中先依赖注入BookDao,然后在运行的方法中输出即可查看查询结果:
package com.example.spring_05_mybatis;
import com.example.spring_05_mybatis.dao.BookDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class Spring05MybatisApplicationTests {
@Autowired
private BookDao bookDao;
@Test
void contextLoads() {
System.out.println("bookDao.getById(1) = " + bookDao.getById(1));
// bookDao.getById("1");
}
}
整合mybatis-plus
整合mp时,spring.io这个网站中是找不着这个的,所以在创建项目的时候,要将这个地址改为阿里云的镜像
版本要选为这个(我的java是8版本,jdk是1.8),勾选mysql driver 创建完之后在pom.xml中加入这段依赖,刷新maven加载出来,同样的在yml文件中将datasource配置出来,创建实体类,实体类名要与数据库中的表名相同,创建的接口
数据库中的表名
实体类:
package com.example.mp;
import com.baomidou.mybatisplus.annotation.TableField;
import org.springframework.beans.factory.annotation.Value;
public class city {
public String ID;
public String Name;
@TableField(value = "CountryCode")
public String CountryCode;
public String District;
public String Population;
@Override
public String toString() {
return "domain{" +
"ID='" + ID + '\'' +
", Name='" + Name + '\'' +
", CountryCode='" + CountryCode + '\'' +
", District='" + District + '\'' +
", Population='" + Population + '\'' +
'}';
}
public void setID(String ID) {
this.ID = ID;
}
public void setName(String name) {
Name = name;
}
public void setCountryCode(String countryCode) {
CountryCode = countryCode;
}
public void setDistrict(String district) {
District = district;
}
public void setPopulation(String population) {
Population = population;
}
public String getID() {
return ID;
}
public String getName() {
return Name;
}
public String getCountryCode() {
return CountryCode;
}
public String getDistrict() {
return District;
}
public String getPopulation() {
return Population;
}
}
package com.example.mp.dao;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface BookDao extends BaseMapper<com.example.mp.city> {
}
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
测试类:
package com.example.mp;
import com.baomidou.mybatisplus.annotation.TableField;
import com.example.mp.dao.BookDao;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class MpApplicationTests {
@Autowired
// @TableField(value = "") // 默认为true
private BookDao bookDao;
@Test
void contextLoads() {
System.out.println("bookDao ==================================================== " + bookDao.selectById(1));
}
}
spring:
datasource:
url: jdbc:mysql://localhost:3306/world?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
username: root
password: 1027wu
driver-class-name: com.mysql.cj.jdbc.Driver
运行后我这里出现了一个问题,原因是数据库中
在使用mp后 报这样子的错误
解决方法也很简单,这个是因为实体类中的CountryCode这个被识别为country_code了,只需要在实体类中的CountryCode这个变量上面加上这个注解即可
@TableField(value = "CountryCode")
public String CountryCode;
然后视频中是遇到的另一种情况,他的数据库表名是tbl_book,这样会被mp在数据库中搜索book,结局方法是在配置文件中加上这个
整合Druid
Maven Repository: com.alibaba » druid-spring-boot-starter (mvnrepository.com)
创建项目的时候,选my sql driver跟mybatis,然后导入坐标(注意我这里导入了两个,视频里只导入druid-spring-boot-starter,但是我那样就会报错)
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
,然后配置文件(这两种都可以):
#spring:
# datasource:
# url: jdbc:mysql://localhost:3306/world?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT%2B8
# username: root
# password: 1027wu
# driver-class-name: com.mysql.cj.jdbc.Driver
# type: com.alibaba.druid.pool.DruidDataSource
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/world?useUnicode=true&characterEncoding=utf8&useSSL=false
username: root
password: 1027wu
其他的跟之前的就差不多一样了
package com.example.druid;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface BookDao {
@Select("select * from city where ID = #{id}")
public city getById(Integer id);
}
package com.example.druid;
public class city {
public String ID;
public String Name;
public String CountryCode;
public String District;
public String Population;
@Override
public String toString() {
return "domain{" +
"ID='" + ID + '\'' +
", Name='" + Name + '\'' +
", CountryCode='" + CountryCode + '\'' +
", District='" + District + '\'' +
", Population='" + Population + '\'' +
'}';
}
public void setID(String ID) {
this.ID = ID;
}
public void setName(String name) {
Name = name;
}
public void setCountryCode(String countryCode) {
CountryCode = countryCode;
}
public void setDistrict(String district) {
District = district;
}
public void setPopulation(String population) {
Population = population;
}
public String getID() {
return ID;
}
public String getName() {
return Name;
}
public String getCountryCode() {
return CountryCode;
}
public String getDistrict() {
return District;
}
public String getPopulation() {
return Population;
}
}
然后在测试类中运行成功。
工程打包与运行(56-58)
运维实用篇-51-工程打包与运行_哔哩哔哩_bilibili
成功运行完之后在这个文件夹里可以找到
点击之后 在文件资源管理器中的地址栏输入cmd,输入java -jar (这个jar包的名字),这个运行的时候一定要注意自己配没配置java的系统环境变量,不然是运行不了的
回车后就可以运行了,打开浏览器输入相应的网址会发现已经可以访问了。
在这期间使用apifox的时候发现接收的数据不是json格式的,就比较好奇json应该是怎么发送的,看了好多博客,最后发现可以这样设置一个Map作为返回值,接收到的类型是json的,不过这应该只是其中之一的方法,应该还有别的方法,写到一半发现json数据还可以通过实体类封装后传
不加这个的话,打包之后会找不到启动类而且依赖的jar包不会一块下载到打包之后的jar包中等等的,cmd中会报jar中没有主清单属性的这个问题
有时候运行也会出现端口被占用的问题,在打包成jar后就不容易修改了,所以可以通过以下的这些指令查询相应的 端口进程并杀死等等的,当然还有另一种方法来覆盖原始文件中的设置,这样设置就可以将端口改为8080端口,后面可以继续加--相关的配置,格式就是yml中的格式
运维实用篇-53-Boot工程快速启动(Linux版)_哔哩哔哩_bilibili
linux在系统还原之后还没装上来就先跳了
这里是配置相关属性的优先级
运维实用篇-55-临时属性(开发环境)_哔哩哔哩_bilibili
在这里也可以配置相关的 属性
配置完之后运行程序,可以发现端口已经更改为8082了
这个更改的原因是在运行类中的args传入这些属性,在运行之前打印一下args可以发现其中就是server.port
所以也就是,在run方法中传入args来更改配置的属性,同样,可以创建一个新的字符串数组,并且将run方法中的args数组改为新建的这个,运行后同样可以发现端口已经改为8081了,所以,如果想要防止别人更改jar 包中的一些属性,可以将run方法中的args参数去掉,这样,jar包中的参数就不可以被修改了
配置文件与多环境开发(59-65)
运维实用篇-56-配置文件4级分类_哔哩哔哩_bilibili
3级实在resources包下新创建个文件夹叫做config,将yml文件放进去,二级是在将项目打包成jar后,在jar同级目录下放入一个yml文件,一级是在jar包同级目录下创建一个config文件夹,在这个文件夹中放入一个yml文件
运维实用篇-57-自定义配置文件_哔哩哔哩_bilibili
想要更改配置文件的名字的话,可以采用以下的配置
多环境开发
yml文件中设置spring.profiles.active的属性来选择选用下面的哪个配置,每个配置之间需要用---来分隔开
#应用环境
spring:
profiles:
active: dev
---
#设置环境
#生产环境
spring:
config:
activate:
on-profile: pro
server:
port: 80
---
#开发环境
spring:
config:
activate:
on-profile: dev
server:
port: 81
---
#测试环境
spring:
config:
activate:
on-profile: test
server:
port: 82
运行后可以看到选择的pro配置已经生效了
这是在一个配置文件中,多个配置文件
创建一个新的 配置文件命名为application-dev.yml,以及设置端口为82,再在application.yml文件中设置选用哪个配置信息
server:
port: 82
spring:
profiles:
active: dev
运行之后可以发现端口号已经改为82了
同时使多个文件生效的话可以这样子
配置中后加载的会覆盖先加载的配置文件中相同的属性,但是这样配置active属性对应的文件永远都是最后加载的
这个也可以对配置文件进行分组,比如只启动dev组的 配置文件
spring:
profiles:
active: dev
group:
"dev": dev1
"pro": pro1
运行后会发现dev1是在dev后面运行的,也就说明如果有相同类型的话会覆盖掉dev的
日志相关操作以及热部署(66-73)
发送请求后会发现只打印了三种日志,没有打印debug的日志,原因是默认是info级别的日志,只会打印info日志以及比他级别高的日志信息
private static final Logger Log= LoggerFactory.getLogger(test.class);
// @RequestMapping(method = RequestMethod.POST)
@PostMapping
public String save(){
System.out.println("user save...");
Log.debug("debug...");
Log.info("info...");
Log.warn("warn...");
Log.error("error");
return "{'module':'user save'}";
}
这两种方法可以设置成debug级别的日志,第一种是输出调试信息,常用于检查系统运行状况,第二种打印的信息会更加详细,为整体应用日志,这里的debug也可以改成其他级别
#debug: true
logging:
level:
root: debug
可以加上@Slf4j注解(需要在pom.xml中导入lombok),这样就不需要初始化Log了,如下图这样,要注意log是小写的
设置日志文件,将日志保存到文件中去
热部署导入spring-boot-devtools坐标,每次修改程序运行时需要点build project,这样子每次更新代码就不需要重启服务器了,build project是手动热部署,这个可以让idea改成自动的,分别把这两个位置勾上,然后就实现自动热部署了,在每次idea失去焦点几秒钟就会自动重新build project了
这样设置可以让系统中的热启动功能彻底关闭,也可以在配置文件中将restart功能设置为false也会关闭第三方bean绑定,松散绑定,Hibernate框架(74-81)
d实用开发篇-71-第三方bean属性绑定_哔哩哔哩_bilibili
先初始化一下配置,创建一个空的spring boot项目,不勾选任何内容,在pom.xml中导入lombok的坐标,并且application.yml,serverconfig,运行文件的内容分别如下
application.yml:
servers:
port: 2345
timeout: -1
ipAddress: 192.168.0.1
ServerConfig:
package com.example.springboot_configuration.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "servers")
public class ServerConfig {
String ipAddress;
String port;
String timeout;
}
@Data就是把getter,setter等方法集成了
@ConfigurationProperties中prefix指定的就是配置文件中所要赋值的内容的上一级的名称
这里的ipAddress在绑定属性的时候,名称比较松散,比如配置文件中写的为IPADRESS,或者Ip_address,ip-address这些都可以绑定上,但是这个只局限于@ConfigurationProperties注解所在的类,prefix的属性必须全为小写可以加上中划线-,在配置文件中同样也为忽略大小写下划线中划线等
SpringbootConfigurationApplication:
package com.example.springboot_configuration;
import com.example.springboot_configuration.config.ServerConfig;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
public class SpringbootConfigurationApplication {
public static void main(String[] args) {
ConfigurableApplicationContext ctx= SpringApplication.run(SpringbootConfigurationApplication.class, args);
ServerConfig bean=ctx.getBean(ServerConfig.class);
System.out.println("bean = " + bean);
}
}
运行后可以发现成功将yml文件的内容赋值到ServerConfig中了
这中间我遇到一个问题,就是
这上面爆红了,
它的意思是“Spring Boot配置注解执行器没有配置”
配置注解执行器的作用是,当执行类中已经定义了对象和该对象的字段后,在配置文件中对该类赋值时,便会非常方便的弹出提示信息。
解决方法是在pom文件中加入
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
可能会也会爆红,不用管,直接刷新maven就好了,回到ServerConfig可以发现已经解决了
第三方bean的话跟这个差不多,这个是自定义了一个bean,使用@ConfigurationProperties注解
@EnableConfigurationProperties()跟@ConfigurationProperties的区别:
前者用法是需要在括号里写入需要进行属性绑定的类,比如加上server.class,加上之后则不能在这个类中写component注解了,多个类需要{}将其括起来,ConfigurationProperties是让这个类在配置文件中能找到自己绑定的属性
计量单位
DataSize是内存大小,上面这张图片表示M,可能会出现配置文件的属性格式与定义的不匹配,可以采用bean属性校验:
1,在pom.xml中加入这段
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
</dependency>
2,在需要进行属性校验的类加入@Valid,在相应的变量前加上需要限制的注解
3,再加入,使用Hibernate框架提供的校验器做实现类
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
将配置文件中的timeout设置为99999,超出了设定,运行程序可以发现已经成功了
设定还有:
在这里配置的属性的优先级是高于配置文件的属性的
测试类 :
在测试的时候想加载外部bean的话,可以考虑使用Import注解,如下图在测试类中新建一个测试bean
在运行程序里加入一个import注解
运行后可以发现会输出"测试",证明导入成功了 ,但是如果项目是一个web项目的话,这个测试文件是不能启动服务器的,需要再对SpringBootTest注解进行设置,这样启动 的是随机端口,启动目前不被占用的端口,每次基本都不会相同
也可以这样设置成默认端口
匹配网页响应的相关信息(82-86)
实用开发篇-80-匹配响应执行状态_哔哩哔哩_bilibili
这几集主要就是匹配网页访问响应的内容,比如访问网站地址出错,响应的内容出错等等的,差不多都是这样子,这里只写的响应状态以及响应体,header没有写,这些内容都是基本一样的,项目开发中常常把这些放到一个方法中同时检测很多东西
首先需要导入lombok
创建一个实体类Book:
package com.example.springboot_configuration.domain;
import lombok.Data;
@Data
public class Book {
int id;
String name;
String type;
String description;
}
BookConfig:
package com.example.springboot_configuration;
import com.example.springboot_configuration.domain.Book;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RequestMapping("/books")
@RestController
public class BookConfig {
@GetMapping
public String getById(){
System.out.println("getById....");
return "getById";
}
@GetMapping("/json")
public Book get1(){
Book b=new Book();
b.setDescription("1");
b.setId(1);
b.setType("1");
b.setName("1");
return b;
}
}
还有一个测试类,这些方法分别是发送虚拟请求,匹配相应状态,匹配响应体还有匹配json:
package com.example.springboot_configuration;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockHttpServletRequestDsl;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.ContentResultMatchers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.result.StatusResultMatchers;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//开启虚拟mvc调用
@AutoConfigureMockMvc
public class WebTest {
@Test
void test(){
}
@Test
void testWeb(@Autowired MockMvc mvc) throws Exception {
//创建虚拟请求,当前访问/books
MockHttpServletRequestBuilder builder= MockMvcRequestBuilders.get("/books");
//执行对应的请求
mvc.perform(builder);
}
@Test
void testStatus(@Autowired MockMvc mvc) throws Exception {
//创建虚拟请求,当前访问/books
MockHttpServletRequestBuilder builder= MockMvcRequestBuilders.get("/books");
//执行对应的请求
ResultActions actions= mvc.perform(builder);
//设定预期值 与真实值进行比较,成功测试通过 失败测试失败
//定义本次调用的预期值
StatusResultMatchers status= MockMvcResultMatchers.status();
//预计本次调用成功时:状态200
ResultMatcher ok=status.isOk();
//添加预计值到本次调用过程中进行匹配
actions.andExpect(ok);
}
@Test
void testBody(@Autowired MockMvc mvc) throws Exception {
MockHttpServletRequestBuilder builder= MockMvcRequestBuilders.get("/books");
ResultActions actions= mvc.perform(builder);
//设定预期值 与真实值进行比较,成功测试通过 失败测试失败
//定义本次调用的预期值
ContentResultMatchers content= MockMvcResultMatchers.content();
//添加预计值到本次调用过程中进行匹配
ResultMatcher result=content.string("getById");
actions.andExpect(result);
}
@Test
void testJson(@Autowired MockMvc mvc) throws Exception {
MockHttpServletRequestBuilder builder= MockMvcRequestBuilders.get("/books");
ResultActions actions= mvc.perform(builder);
//设定预期值 与真实值进行比较,成功测试通过 失败测试失败
//定义本次调用的预期值
ContentResultMatchers content= MockMvcResultMatchers.content();
//添加预计值到本次调用过程中进行匹配
ResultMatcher result=content.json("{\"id\":1,\"name\":\"1\",\"type\":\"1\",\"description\":\"1\"}");
actions.andExpect(result);
}
}
同时在这里也发现了传json数据可以用一个实体类
相关技术的整合(87-106)
实用开发篇-84-业务层测试事务回滚_哔哩哔哩_bilibili
在测试类中运行数据库的一些增加等操作时会对数据库进行更改,但是当不想对数据库进行更改时需要让其进行回滚,在测试类上面加一个@Transactional注解,这样在运行程序后,就会进行回滚,可以加一个@Rollback注解并且设置为false,默认是True,改为false后会发现,即使加上@Transactional注解也一样会保存到数据库中
实用开发篇-85-测试用例设置随机数据_哔哩哔哩_bilibili
使用hikari数据源时我这里报了一个错是Exception during pool initialization.
这个问题可能是datasource配置出现问题了,我改了一下url路径为jdbc:mysql://localhost:3306/world就成功了
Druid数据源的两种配置:
数据库H2(替换tomcat):
首先加入这两个配置
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
配置文件中是这样配置的
spring:
h2:
console:
path: /h2
enabled: true
运行后,因为我这个没设置端口所以是默认端口8080,注意在输入地址的时候要加上8080,即访问localhost:8080/h2会到达这个界面
第一次登陆需要在配置文件中加入这些,这样是可以初始化数据源,后面再次登陆就可以不用加了
spring:
datasource:
url: jdbc:h2:~/test
hikari:
driver-class-name: org.h2.Driver
username: sa
password: 123456
成功连接后的操作跟sql差不多就一样了
实用开发篇-89-redis下载安装与基本使用_哔哩哔哩_bilibili
实用开发篇-90-SpringBoot整合Redis_哔哩哔哩_bilibili
实用开发篇-91-SpringBoot读写Redis的客户端_哔哩哔哩_bilibili
实用开发篇-92-SpringBoot操作Redis客户端实现技术切换(jedis)_哔哩哔哩_bilibili
连接redis时候出现这个错误
原因是6379端口已绑定。应该是因为上次服务没有关闭。这样输入后再次运行就成功了
哈希存储的话,简单来说就是先是一个key对应多个键值对的key,这些key再对应一个value
哈希存储的时候我这里报错了,内容就是权限不允许,再以管理员的身份运行命令提示符窗口,重新启动一下redis,再put就成功了
redis提供的api
整合redis Redis下载地址:Releases · tporadowski/redis (github.com)
1,先是在创建项目的时候勾选redis
2,配置文件中进行配置
spring:
redis:
host: localhost
port: 6379
3,测试文件中对一些set,get,put进行测试
package com.example.springboot_redis;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
@SpringBootTest
class SpringbootRedisApplicationTests {
@Autowired
private RedisTemplate redisTemplate;
@Test
void set() {
ValueOperations ops= redisTemplate.opsForValue();
ops.set("age",41);
}
@Test
void get(){
ValueOperations ops= redisTemplate.opsForValue();
Object age= ops.get("age");
System.out.println("age = " + age);
}
@Test
void hset(){
HashOperations hashOperations= redisTemplate.opsForHash();
hashOperations.put("info","a","aa");
}
@Test
void hget(){
HashOperations ops= redisTemplate.opsForHash();
Object a=ops.get("info","a");
System.out.println("a = " + a);
}
}
在java程序中将数据set或者put都是以对象的方式进行处理,读取的时候也是在程序中以文件的形式读取出来,但是如果在命令窗口set一个值,在java程序中还是以同样的方法是读取不出来的,因为在命令窗口set的值是 String类型的,读取的话需要用
@Autowired
StringRedisTemplate stringRedisTemplate;
这样定义完之后,剩下的操作就跟上面的一样了
整合Mongodb
整合ES:
首先还是要启动ES啊(运行的时候给忘了)
视频中是老版的,所以spring boot没有集成ES,现在已经集成了,搜了一下
(2条消息) 《SpringBoot篇》16.SpringBoot整合Elasticsearch_陈老老老板的博客-CSDN博客
这个写的感觉很好,看完这个基本就会整合了
整合过程中我这里也报了一个错误是Elasticsearch exception [type=illegal_argument_exception, reason=request [/user] contains unrecognized parameter: [include_type_name]] ],原因是create方法导入的包已经过时了
我导入的 是这个包,这个已经过时了
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
换成下面这个包就能正常运行了
import org.elasticsearch.client.indices.CreateIndexRequest;
在查询的时候视频里用的是termQuery,因为我数据库的Name都含有大写字母,所以查找的时候在termQuery("name",""),后面的name的value也都写的是有大写字母的单词,这样是搜不到的,因为文档里保存的数据是小写的,差不多是这样子,所以查找的话termQuery中的value必须改为小写的。当然也可以用matchQuery这个,他们的格式都是一样的,但是matchQuery中可以用大写的字母来查找,emm,我看黑马的这个课后面有讲解ES的,就没有深入研究了
具体的代码如下(因为我用的之前的一个数据库,数据库定义的内容跟老师讲的不一样,所以有些地方也不太一样):
pom.xml:
<dependency>
<groupId>org.elasticsearch</groupId>
<artifactId>elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.60</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
测试文件:
package com.example.springboot_es;
import net.minidev.json.JSONObject;
import org.apache.http.HttpHost;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.xcontent.XContentType;
import com.alibaba.fastjson.JSON;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.awt.print.Book;
import java.io.IOException;
import java.util.List;
@SpringBootTest
class SpringbootEsApplicationTests {
@Autowired
BookDao bookDao;
@Autowired
private RestHighLevelClient client;
@Test
void testCreateIndex() throws IOException {
HttpHost host = HttpHost.create("http://localhost:9200");
RestClientBuilder builder = RestClient.builder(host);
client = new RestHighLevelClient(builder);
String json="{\n" +
" \"mappings\":{\n" +
" \"properties\":{\n" +
" \"id\":{\n" +
" \"type\":\"keyword\"\n" +
" },\n" +
" \"name\":{\n" +
" \"type\":\"text\",\n" +
" \"analyzer\":\"ik_max_word\",\n" +
" \"copy_to\":\"all\" },\n" +
" \"type\":{\n" +
" \"type\":\"keyword\"\n" +
" }\n" +
" ,\n" +
" \"description\":{\n" +
" \"type\":\"text\",\n" +
" \"analyzer\":\"ik_max_word\",\n" +
" \"copy_to\":\"all\"\n" +
" },\n" +
" \"all\":{\n" +
" \"type\":\"text\",\n" +
" \"analyzer\":\"ik_max_word\"\n" +
" }\n" +
" }\n" +
" }\n" +
"}\n";
CreateIndexRequest request = new CreateIndexRequest("user");
request.source(json, XContentType.JSON);
client.indices().create(request, RequestOptions.DEFAULT);
client.close();
}
//添加文档
@Test
void testCreateDoc() throws IOException {
// city book=bookDao.selectById("1");//查询单个数据
// IndexRequest request=new IndexRequest("user").id(book.getID().toString());
IndexRequest request=new IndexRequest("user").id("1");
// String json=JSON.toJSONString(book);
//
// request.source(json,XContentType.JSON);
// try{
// client.index(request,RequestOptions.DEFAULT);}catch (Exception e){
// String msg = e.getMessage();
// if(!msg.contains("201 Created") && !msg.contains("200 OK")) {
// throw e;
// }
// }
//**********************************************上面为查询一条数据,保存多条数据可以用批处理容器
List<city> bookList=bookDao.selectList(null);
BulkRequest bulk=new BulkRequest();//bulk为一个容器,所有的请求都往这里面添加就行了
for(city book:bookList){
IndexRequest request=new IndexRequest("user").id(book.getID().toString());//
String json=JSON.toJSONString(book);
//
request.source(json,XContentType.JSON);
bulk.add(request);
}
try{
client.bulk(bulk,RequestOptions.DEFAULT);}catch (Exception e){
String msg = e.getMessage();
if(!msg.contains("201 Created") && !msg.contains("200 OK")) {
throw e;
}
}
// client.close();
}
//按id查询
@Test
void testGet() throws IOException {
GetRequest request=new GetRequest("user","1");
GetResponse response=client.get(request,RequestOptions.DEFAULT);
String JSON=response.getSourceAsString();
System.out.println("JSON = " + JSON);
}
//按条件查询
@Test
void testSearch() throws IOException {
SearchRequest request=new SearchRequest("user");
SearchSourceBuilder builder=new SearchSourceBuilder();
builder.query(QueryBuilders.matchQuery("name","ai"));
request.source(builder);
SearchResponse response=client.search(request,RequestOptions.DEFAULT);
SearchHits hits=response.getHits();
for(SearchHit hit:hits){
String source =hit.getSourceAsString();
System.out.println(source);
}
}
}
application.yml文件:
spring:
datasource:
druid:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/world?serverTimezone=UTC
username: root
password: 1027wu
elasticsearch:
rest:
# uris: http://localhost:9200
mybatis-plus:
global-config:
db-config:
id-type: auto
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
BookDao(后面运行的时候才发现我用的数据库名叫city,这里定义的叫BookDao,有点乱了):
package com.example.springboot_es;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.transaction.annotation.Transactional;
@Mapper
@Transactional
public interface BookDao extends BaseMapper<city> {
}
city(这个类可以看作是视频里的那个Book类):
package com.example.springboot_es;
import com.baomidou.mybatisplus.annotation.TableField;
import lombok.Data;
import lombok.Value;
@Data
public class city {
String ID;
String Name;
@TableField(value = "CountryCode")
String CountryCode;
String District;
}
还有一定要注意导包的时候不要导错了,有些方法在好几个包里都有
Memcached的安装按照视频的顺序就行了,比较简单