首页
statistical
wallpaper
Search
1
Serv00虚拟主机
385 阅读
2
Azure 100(AZ100) 学生申请
316 阅读
3
项目搭建
277 阅读
4
Raft论文研读 Ⅳ
257 阅读
5
Raft论文研读 Ⅱ
256 阅读
Java
VPS
BlockChain
Paper
Other
备战
登录
Search
标签搜索
Raft
VPS
Java
共识算法
区块链
论文
项目搭建
Docker
改进Raft
SE
Web
Git
SSM
Spring Boot
Blog
Nat
科学上网
ChatGpt
探针
AZ100
ZhenXI
累计撰写
35
篇文章
累计收到
12
条评论
首页
栏目
Java
VPS
BlockChain
Paper
Other
备战
页面
statistical
wallpaper
搜索到
1
篇与
的结果
2022-07-31
Spring Boot
1 Spring Boot1.1 Spring Boot概述Spring Boot设计目的是用来简化Spring应用的创建、运行、调试、部署等。使用Spring Boot可以做到专注于Spring应用的开发,而无需过多关注XML的配置。Spring Boot使用“约定优于配置”的理念,简单来说,它提供了一堆依赖打包,并已经按照使用习惯解决了依赖问题。1.2 Spring Boot的核心功能可独立运行的Spring项目:Spring Boot可以以jar包的形式独立运行。内嵌的Servlet容器:Spring Boot可以选择内嵌Tomcat、Jetty或者Undertow,无须以war包形式部署项目。简化的Maven配置:Spring提供推荐的基础 POM 文件来简化Maven 配置。自动配置Spring:Spring Boot会根据项目依赖来自动配置Spring 框架,极大地减少项目要使用的配置。提供生产就绪型功能:提供可以直接在生产环境中使用的功能,如性能指标、应用信息和应用健康检查。无代码生成和xml配置:Spring Boot不生成代码。完全不需要任何xml配置即可实现Spring的所有配置。1.3 SpringBootB的相关好处使用 Spring 项目引导页面可以在⼏秒构建⼀个项⽬;方便对外输出各种形式的服务,如 REST API、WebSocket、Web、Streaming、Tasks;非常简洁的安全策略集成;⽀持关系数据库和⾮关系数据库;⽀持运行期内嵌容器,如 Tomcat、Jetty;强⼤的开发包,⽀持热启动;⾃动管理依赖;⾃带应⽤监控;⽀持各种 IED,如 IntelliJ IDEA 、NetBeans。和Spirng程序相比,SpringBoot程序在开发的过程中各个层面均具有优势类配置文件SpringSpringBootpom文件中的坐标手工添加勾选添加web3.0配置类手工制作无Spring/SpringMVC配置类手工制作无控制器手工制作手工制作2 Spring Boot快速创建2.1 使用Spring Initializr引导页面进行创建①创建新模块,选择Spring Initializr,并配置模块相关基础信息②选择当前模块需要使用的技术集③开发控制器类package com.liu.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/user") public class UserController { @GetMapping @RequestMapping("quick1") public String findUsers() { System.out.println("Spring boot is running"); return "Spring is running"; } }④运行自动生成的Application类2.2 进入Spring Boot官网进行创建①点击Spring Initializr后进入到创建SpringBoot程序的界面上,下面是输入信息的过程,和前面的一样,只是界面变了而已,根据自己的要求,在左侧选择对应信息和输入对应的信息即可。右侧的ADD DEPENDENCIES用于选择使用何种技术,和之前勾选的Spring WEB是在做同一件事,仅仅是界面不同而已,点击后打开网页版的技术选择界面②所有信息设置完毕后,点击下面左侧按钮,生成一个文件包,保存后得到一个压缩文件,这个文件打开后就是创建的SpringBoot工程文件夹。解压缩此文件后,得到工程目录,在Idea中导入即可使用,和之前创建的东西完全一样。下面就可以自己创建一个Controller测试一下是否能用了。2.3 使用阿里云地址创建Spring Boot项目①创建新模块,选择Spring Initializr,选择Server URL为start.aliyun.com,并配置模块相关基础信息②选择当前模块需要使用的技术集③运行自动生成的Application类进行测试3 Spring Boot简介3.1 parent:进行版本的统一管理①parent概述SpringBoot为了解决最合理的依赖版本配置方案,于是将所有的技术版本的常见使用方案都给开发者整理了出来,以后开发者使用时直接用它提供的版本方案,就不用担心冲突问题了,相当于SpringBoot做了无数个技术版本搭配的列表,这个技术搭配列表的名字叫做parent。 parent自身具有很多个版本,每个parent版本中包含有几百个其他技术的版本号,不同的parent间使用的各种技术的版本号有可能会发生变化。当开发者使用某些技术时,直接使用SpringBoot提供的parent就行了,由parent帮助开发者统一的进行各种技术的版本管理。②Spring Boot项目中引用的parent项目中的pom.xml中继承了一个坐标,打开后可以查阅到其中又继承了一个坐标,这个坐标中定义了两组信息。第一组是各式各样的依赖版本号属性,下面列出依赖版本属性的局部,可以看的出来,定义了若干个技术的依赖版本号;第二组是各式各样的的依赖坐标信息,可以看出依赖坐标定义中没有具体的依赖版本号,而是引用了第一组信息中定义的依赖版本属性值。<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.3</version> <relativePath/> <!-- lookup parent from repository --> </parent>③parent功能定义了 Java 编译版本为 1.8 。使用 UTF-8 格式编码。继承自 spring-boot-dependencies,这个里边定义了依赖的版本,也正是因为继承了这个依赖,所以我们在写4、依赖时才不需要写版本号。执行打包操作的配置。自动化的资源过滤。自动化的插件配置。针对 application.properties 和 application.yml 的资源过滤,包括通过 profile 定义的不同环境的配置文件,例如 application-dev.properties 和 application-dev.yml。3.2 starter:减少依赖配置①starter概述SpringBoot把所有的技术使用的固定搭配格式都给开发出来,开发者使用的时候,就不用一次写一堆依赖了,直接用Spring Boot做好的这个东西就好了,对于这样的固定技术搭配,SpringBoot给它起了个名字叫做starter。starter定义了使用某种技术时对于依赖的固定搭配格式,也是一种最佳解决方案,使用starter可以帮助开发者减少依赖配置。②Spring Boot项目中引用的starter项目中的pom.xml定义了使用SpringMVC技术,但是并没有写SpringMVC的坐标,而是添加了一个名字中包含starter的依赖,在spring-boot-starter-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>③starter与parent的区别starter是一个坐标中定了若干个坐标,以前写多个的,现在写一个,是用来减少依赖配置的书写量的。parent是定义了几百个依赖版本号,以前写依赖需要自己手工控制版本,现在由SpringBoot统一管理,这样就不存在版本冲突了,是用来减少依赖冲突的。3.3 引导类运行这个类就可以启动SpringBoot工程:@SpringBootApplication public class Springboot0101QuickstartApplication { public static void main(String[] args) { SpringApplication.run(Springboot0101QuickstartApplication.class, args); } }SpringBoot本身是为了加速Spring程序的开发的,而Spring程序运行的基础是需要创建自己的Spring容器对象(IoC容器)并将所有的对象交给Spring的容器管理,也就是一个一个的Bean。当前这个类运行后就会产生一个Spring容器对象,并且可以将这个对象保存起来,通过容器对象直接操作Bean。@SpringBootApplication public class Springboot01QuickstartApplication { public static void main(String[] args) { ConfigurableApplicationContext applicationContext = SpringApplication.run(Springboot01QuickstartApplication.class, args); UserController userController = applicationContext.getBean(UserController.class); System.out.println(userController); } }通过上述操作不难看出,其实SpringBoot程序启动还是创建了一个Spring容器对象。这个类在SpringBoot程序中是所有功能的入口,称这个类为引导类。作为一个引导类最典型的特征就是当前类上方声明了一个注解@SpringBootApplication打开该注解可以发现,这个类就是学习Spring的注解核心配置类。3.4 内嵌tomcat打开查看web的starter,发现有一个tomcat的starter,这里面有一个核心的坐标,tomcat-embed-core,叫做tomcat内嵌核心。就是这个东西把tomcat功能引入到了我们的程序中。更换内嵌TomcatSpringBoot提供了3款内置的服务器tomcat(默认):apache出品,粉丝多,应用面广,负载了若干较重的组件jetty:更轻量级,负载性能远不及tomcatundertow:负载性能勉强跑赢tomcat想用哪个,加个坐标就OK。前提是把tomcat排除掉,因为tomcat是默认加载的。<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jetty</artifactId> </dependency> </dependencies>现在就已经成功替换了web服务器,核心思想就是用什么加入对应坐标就可以了。如果有starter,优先使用starter。4 Rest风格,RestFul开发在学习Spring MVC时学过REST风格,但是讲课老师讲的不太深入,对于一些注解并没有进行讲解。于是重新复习一遍。4.1 RESTFUL概述RESTFUL是一种网络应用程序的设计风格和开发方式,基于HTTP,可以使用 XML 格式定义或 JSON 格式定义。最常用的数据格式是JSON。由于JSON能直接被JavaScript读取,所以,使用JSON格式的REST风格的API具有简单、易读、易用的特点。REST 是 Representational State Transfer 的缩写,如果一个架构符合 REST 原则,就称它为 RESTful 架构RESTful 架构可以充分的利用 HTTP 协议的各种功能,是 HTTP 协议的最佳实践。RESTful API 是一种软件架构风格、设计风格,可以让软件更加清晰,更简洁,更有层次,可维护性更好4.2 RESTFUL API 请求设计请求方式含义GET(SELECT)从服务器取出资源(一项或多项)POST(CREATE)在服务器新建一个资源PUT(UPDATE)在服务器更新资源(更新完整资源)PATCH(UPDATE)在服务器更新资源, PATCH更新个别属性DELETE(DELETE)从服务器删除资源4.3 在Spring MVC中使用RESTFUL开发设计@Controller public class ZoosController { @RequestMapping(value = "/zoos",method = RequestMethod.GET) @ResponseBody public String findAll(){ System.out.println("ZoosController.findAll"); return "zoosController.findAll"; } @RequestMapping(value = "/zoos/{id}",method = RequestMethod.GET) @ResponseBody public String findOne(@PathVariable Integer id){ System.out.println("ZoosController.findOne"); return "zoosController.findOne"; } @RequestMapping(value = "/zoos",method = RequestMethod.PUT) @ResponseBody public String update(@RequestBody Zoo zoo){ System.out.println("ZoosController.update"); return "zoosController.update"; } @RequestMapping(value = "/zoos/{id}",method = RequestMethod.DELETE) @ResponseBody public String delete(@PathVariable Integer id){ System.out.println("ZoosController.delete"); return "zoosController.delete"; } @RequestMapping(value = "/zoos",method = RequestMethod.POST) @ResponseBody public String insert(){ System.out.println("ZoosController.insert"); return "zoosController.insert"; } }简化开发相关注解注解作用@RestController由 @Controller + @ResponseBody组成(返回 JSON 数据格式)@PathVariableURL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到控制器处理方法的形参中@RequestMapping注解用于请求地址的解析,是最常用的一种注解@GetMapping查询请求@PostMapping添加请求@PutMapping更新请求@DeleteMapping删除请求@RequestParam将请求参数绑定到你控制器的方法参数上(是springmvc中接收普通参数的注解)@RestController @RequestMapping("/zoos") @ResponseBody public class ZoosController { @GetMapping public String findAll(){ System.out.println("ZoosController.findAll"); return "zoosController.findAll"; } @GetMapping(value = "/{id}") public String findOne(@PathVariable Integer id){ System.out.println("ZoosController.findOne"); return "zoosController.findOne"; } @PutMapping public String update(@RequestBody Zoo zoo){ System.out.println("ZoosController.update"); return "zoosController.update"; } @DeleteMapping(value = "/{id}") public String delete(@PathVariable Integer id){ System.out.println("ZoosController.delete"); return "zoosController.delete"; } @PostMapping public String insert(){ System.out.println("ZoosController.insert"); return "zoosController.insert"; } }5 SpringBoot基础配置5.1 属性配置SpringBoot通过配置文件application.properties就可以修改默认的配置,properties格式的文件书写规范是key=value。SpringBoot程序可以在application.properties文件中进行属性配置。application.properties文件中只要输入要配置的属性关键字就可以根据提示进行设置。SpringBoot将配置信息集中在一个文件中写,不管你是服务器的配置,还是数据库的配置,总之都写在一起,逃离一个项目十几种配置文件格式的尴尬局面。更改端口号# 服务器的端口配置 server.port=80关闭运行日志图表(banner)# 关闭banner spring.main.banner-mode=off # 修改banner spring.banner.image.location=wallhaven-2879mg.png设置运行日志的显示级别# 日志 logging.level.root = error5.2 配置文件分类SpringBoot除了支持properties格式的配置文件,还支持另外两种格式的配置文件。分别如下:application.properties(properties格式)server.port=80application.yml(yml格式)server: port: 81application.yaml(yaml格式)server: port: 82仔细看会发现yml格式和yaml格式除了文件名后缀不一样,格式完全一样,是这样的,yml和yaml文件格式就是一模一样的,只是文件后缀不同,所以可以合并成一种格式来看。5.3 配置文件优先级其实三个文件如果共存的话,谁生效说的就是配置文件加载的优先级别。application.properties > application.yml > application.yaml配置文件间的加载优先级 properties(最高)> yml > yaml(最低),不同配置文件中相同配置按照加载优先级相互覆盖,不同配置文件中不同配置全部保留。5.4 yaml文件的使用YAML(YAML Ain't Markup Language),一种数据序列化格式。具有容易阅读、容易与脚本语言交互、以数据为核心,重数据轻格式的特点。常见的文件扩展名有两种:.yml格式(主流).yaml格式对于文件自身在书写时,具有严格的语法格式要求,具体如下:大小写敏感属性层级关系使用多行描述,每行结尾使用冒号结束使用缩进表示层级关系,同层级左侧对齐,只允许使用空格(不允许使用Tab键)属性值前面添加空格(属性名与属性值之间使用冒号+空格作为分隔)号 表示注释常见的数据书写格式:boolean: TRUE #TRUE,true,True,FALSE,false,False均可 float: 3.14 #6.8523015e+5 #支持科学计数法 int: 123 #0b1010_0111_0100_1010_1110 #支持二进制、八进制、十六进制 null: ~ #使用~表示null string: HelloWorld #字符串可以直接书写 string2: "Hello World" #可以使用双引号包裹特殊字符 date: 2018-02-17 #日期必须使用yyyy-MM-dd格式 datetime: 2018-02-17T15:02:31+08:00 #时间和日期之间使用T连接,最后使用+代表时区 subject: - Java - 前端 - 大数据 enterprise: name: itcast age: 16 subject: - Java - 前端 - 大数据 likes: [王者荣耀,刺激战场] #数组书写缩略格式 users: #对象数组格式一 - name: Tom age: 4 - name: Jerry age: 5 users: #对象数组格式二 - name: Tom age: 4 - name: Jerry age: 5 users2: [ { name:Tom , age:4 } , { name:Jerry , age:5 } ] #对象数组缩略格式5.5 yaml文件数据读取读取单一数据yaml中保存的单个数据,可以使用Spring中的注解直接读取,使用@Value可以读取单个数据,属性名引用方式:${一级属性名.二级属性名……}address: 河南 user: userName: admin password: 123456 likes: - game - music - video baseDir: c:\windows\system32 tempDir: ${baseDir}\temp@RestController @RequestMapping("/user") public class UserController { @Value("${address}") private String address; @Value("${user.userName}") private String userName; @Value("${likes[1]}") private String likes1; @Value("${tempDir}") private String tempDir; @GetMapping("/quick1") public String findUsers() { System.out.println("Spring boot is running"); System.out.println(address); System.out.println(userName); System.out.println(likes1); System.out.println(tempDir); }读取全部数据SpringBoot提供了一个对象,能够把所有的数据都封装到这一个对象中,这个对象叫做Environment,使用自动装配注解可以将所有的yaml数据封装到这个对象中。@RestController @RequestMapping("/user") public class UserController { //自动装配,把所有对象加载到environment对象中 @Autowired private Environment environment; @GetMapping("/quick1") public String findUsers() { System.out.println("Spring boot is running"); //使用environment获得yMl文件中的信息 String address = environment.getProperty("address"); System.out.println(address); } }读取对象数据单一数据读取书写比较繁琐,全数据封装又封装的太厉害了,每次拿数据还要一个一个的getProperties(),总之用起来都不是很舒服。由于Java是一个面向对象的语言,很多情况下,我们会将一组数据封装成一个对象。SpringBoot也提供了可以将一组yaml对象数据封装一个Java对象的操作。①首先定义一个对象,并将该对象纳入Spring管控的范围,也就是定义成一个bean,然后使用注解@ConfigurationProperties指定该对象加载哪一组yaml中配置的信息。@Component @ConfigurationProperties(prefix = "datasource") public class MyDataSource { private String driver; private String url; private String username; private String password; @Override public String toString() { return "MyDataSource{" + "driver='" + driver + '\'' + ", url='" + url + '\'' + ", username='" + username + '\'' + ", password='" + password + '\'' + '}'; } public String getDriver() { return driver; } public void setDriver(String driver) { this.driver = driver; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }这个@ConfigurationProperties必须告诉他加载的数据前缀是什么,这样当前前缀下的所有属性就封装到这个对象中。记得数据属性名要与对象的变量名一一对应啊,不然没法封装。其实以后如果你要定义一组数据自己使用,就可以先写一个对象,然后定义好属性,下面到配置中根据这个格式书写即可。datasource: driver: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost username: root password: 1314115.6 yaml配置中遇到的问题①配置yml文件时,设置键名为大写报错:dataSource: driver: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost username: root password: 131411Invalid characters: 'S' Bean: userController Reason: Canonical names should be kebab-case ('-' separated), lowercase alpha-numeric characters and must start with a letter 无效字符:'S' Bean:userController 原因:规范名称应为 kebab-case('-' 分隔)、小写字母数字字符且必须以字母开头6 Spring Boot整合JunitSpring整合JUnit的制作方式@ContextConfiguration("classpath:applicationContext.xml") @RunWith(SpringJUnit4ClassRunner.class) public class TransactionManagerTest { @Autowired private AccountService accountService; @Test public void test() { accountService.transfer(); } }@RunWith是设置Spring专用于测试的类运行器,简单说就是Spring程序执行程序有自己的一套独立的运行程序的方式,不能使用JUnit提供的类运行方式了,必须指定一下。@ContextConfiguration是用来设置Spring核心配置文件或配置类的,简单说就是加载Spring的环境你要告诉Spring具体的环境配置是在哪里写的。SpringBoot就抓住上述两条没有技术含量的内容书写进行开发简化,能走默认值的走默认值,能不写的就不写,具体格式如下:①导入test的starter坐标<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency>②使用一个注解@SpringBootTest替换了前面两个注解。@SpringBootTest class SpringDemo1ApplicationTests { @Autowired private BookMapper bookMapper; @Test void contextLoads() { bookMapper.save(); } }7 Spring Boot整合Mybatis①创建模块时勾选要使用的技术,MyBatis,由于要操作数据库,还要勾选对应数据库②配置数据源相关信息spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test username: root password: 131411③使用Lombok创建实体类@Data public class User { private Integer id; private String username; private String password; private String gender; private String address; }④创建映射接口@Mapper public interface UserMapper { @Select("select * from tb_user") List<User> findAll(); @Insert("insert into tb_user(username, password, gender, address) values (#{username},#{password},#{gender},#{address})") void insert(User user); @Update("update tb_user set username = #{username} where id=#{id}") int update(@Param("username") String username, @Param("id") int id); @Delete("delete from tb_user where id=#{id}") void delete(int id); }⑤进行测试@SpringBootTest class SpringBootMybatisApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads() { List<User> userList = userMapper.findAll(); for (User user : userList) { System.out.println(user); } } @Test void userInserts() { User user = new User(); user.setUsername("刘畅"); user.setPassword("1314"); user.setGender("男"); user.setAddress("河南"); userMapper.insert(user); } @Test void userUpdates() { userMapper.update("六珍惜", 1); } @Test void userDeletes() { userMapper.delete(1); } }⑥部分测试结果8 Spring Boot整合Mybatis-plus①导入对应的starter<!-- https://mvnrepository.com/artifact/com.baomidou/mybatis-plus-boot-starter --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency>②配置数据源相关信息spring: datasource: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test username: root password: 131411③创建映射接口@Mapper public interface UserMapper extends BaseMapper<User> { }④进行测试@SpringBootTest class SpringBootMybatisplusApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads() { List<User> userList = userMapper.selectList(null); for (User user : userList) { System.out.println(user); } } @Test void findUserById(){ User user = userMapper.selectById(1); System.out.println(user); } }9 Spring Boot整合druid数据源①导入对应的starter<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.2.11</version> </dependency>②配置数据源相关信息spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test username: root password: 131411③创建映射接口@Mapper public interface UserMapper { @Select("select * from tb_user") List<User> findAll(); @Insert("insert into tb_user(username, password, gender, address) values (#{username},#{password},#{gender},#{address})") void insert(User user); @Update("update tb_user set username = #{username} where id=#{id}") int update(@Param("username") String username, @Param("id") int id); @Delete("delete from tb_user where id=#{id}") void delete(int id); }④进行测试@SpringBootTest class SpringBootMybatisApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads() { List<User> userList = userMapper.findAll(); for (User user : userList) { System.out.println(user); } } @Test void userInserts() { User user = new User(); user.setUsername("刘畅"); user.setPassword("1314"); user.setGender("男"); user.setAddress("河南"); userMapper.insert(user); } @Test void userUpdates() { userMapper.update("六珍惜", 1); } @Test void userDeletes() { userMapper.delete(1); } }学习总结:本周学习进度有些慢,本周主要学习了Spring Boot基础篇的相关知识。通过本次的学习,对SpringMVC的相关知识更加的熟悉;通过进行SSM整合,使用注解开发Spring程序更加得心应手;对于Spring Boot的学习,必须要打牢Spring的基础,只要有牢固的Spring基础,SpringBoot的开发更加的简单。下周学习计划:完成Spring Boot基础篇、运维实用篇等课程。由于临近开学,需要整理解决一些开学事务,导致学习时间有所减少,SpringBoot的课程在开学前无法学习完毕,不过在开学后会尽快完成任务,达到Java全栈初级工程师水平。继续努力!SpringBoot学习笔记 21 基于Spring Boot整合SSMP1.1 模块创建导入MyBatisPlus与Druid对应的starter,当然mysql的驱动不能少<dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version>3.5.2</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency>1.2 数据层开发①创建实体类:User@Data public class User { private Integer id; private String username; private String password; private String gender; private String address; }②配置数据源server: port: 80 spring: datasource: druid: driver-class-name: com.mysql.cj.jdbc.Driver url: jdbc:mysql://localhost:3306/test username: root password: 131411 mybatis-plus: global-config: db-config: table-prefix: tb_③编写映射接口@Mapper public interface UserMapper extends BaseMapper<User> { }④测试@SpringBootTest public class UserMapperTest { @Autowired private UserMapper userMapper; @Test public void test(){ List<User> userList = userMapper.selectList(null); for (User user : userList) { System.out.println(user); } } @Test public void test2(){ User user = userMapper.selectById(1); System.out.println(user); } @Test public void test3(){ User user = new User(); user.setUsername("齐大"); user.setPassword("0000"); user.setGender("男"); user.setAddress("齐齐哈尔"); userMapper.insert(user); } @Test public void test4(){ userMapper.deleteById(191561735); } @Test public void test5(){ User user = new User(); user.setId(15); user.setUsername("郑大"); user.setPassword("0000"); user.setGender("男"); user.setAddress("河南郑州"); userMapper.updateById(user); } }发现问题一:自动增长的Id值太大。解决方式一:通过配置的方式:mybatis-plus: global-config: db-config: table-prefix: tb_ id-type: auto #设置主键id字段的生成策略为参照数据库设定的策略,当前数据库设置id生成策略为自增解决方式二:通过注解:在实体类User类的id属性上添加此注解。@TableId(value = "id", type = IdType.AUTO) private Integer id;发现问题二:控制台没有打印SQL语句,不利于查看解决方式:通过配置的形式就可以查阅执行期SQL语句,配置如下:mybatis-plus: global-config: db-config: table-prefix: tb_ id-type: auto configuration: log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 开启打印日志⑤分页查询测试前面仅仅是使用了MP提供的基础CRUD功能,实际上MP给我们提供了几乎所有的基础操作。其中selectPage方法需要传入一个封装分页数据的对象,可以通过new的形式创建这个对象,当然这个对象也是MP提供的。创建此对象时就需要指定分页的两个基本数据当前显示第几页每页显示几条数据可以通过创建Page对象时利用构造方法初始化这两个数据IPage page = new Page(2,5);将该对象传入到查询方法selectPage后,可以得到查询结果,但是我们会发现当前操作查询结果返回值仍然是一个IPage对象。IPage page = bookDao.selectPage(page, null);原来这个IPage对象中封装了若干个数据,而查询的结果作为IPage对象封装的一个数据存在的,可以理解为查询结果得到后,又塞到了这个IPage对象中,其实还是为了高度的封装,一个IPage描述了分页所有的信息。下面5个操作就是IPage对象中封装的所有信息了。@Test public void test6() { IPage<User> page = new Page<User>(1,5); userMapper.selectPage(page,null); System.out.println(page.getCurrent()); System.out.println(page.getSize()); System.out.println(page.getPages()); System.out.println(page.getTotal()); System.out.println(page.getRecords()); }到这里就知道这些数据如何获取了,但是当你去执行这个操作时,你会发现并不像我们分析的这样,实际上这个分页当前是无效的。为什么这样呢?这个要源于MP的内部机制。对于MySQL的分页操作使用limit关键字进行,而并不是所有的数据库都使用limit关键字实现的,这个时候MP为了制作的兼容性强,将分页操作设置为基础查询操作的升级版,你可以理解为IPhone6与IPhone6S-PLUS的关系。基础操作中有查询全部的功能,而在这个基础上只需要升级一下(PLUS)就可以得到分页操作。所以MP将分页操作做成了一个开关,你用分页功能就把开关开启,不用就不需要开启这个开关。而我们现在没有开启这个开关,所以分页操作是没有的。这个开关是通过MP的拦截器的形式存在的,其中的原理这里不分析了,有兴趣的小伙伴可以学习MyBatisPlus这门课程进行详细解读。具体设置方式如下定义MP拦截器并将其设置为Spring管控的bean@Configuration public class MPConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor(){ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor()); return interceptor; } }上述代码第一行是创建MP的拦截器栈,这个时候拦截器栈中没有具体的拦截器,第二行是初始化了分页拦截器,并添加到拦截器栈中。如果后期开发其他功能,需要添加全新的拦截器,按照第二行的格式继续add进去新的拦截器就可以了。⑥按条件查询模糊匹配对应的操作,由like条件书写变为了like方法的调用。@Test public void test7() { QueryWrapper<User> queryWrapper = new QueryWrapper<>(); queryWrapper.like("username","刘"); userMapper.selectList(queryWrapper); }第一句QueryWrapper对象是一个用于封装查询条件的对象,该对象可以动态使用API调用的方法添加条件,最终转化成对应的SQL语句。第二句就是一个条件了,需要什么条件,使用QueryWapper对象直接调用对应操作即可。比如做大于小于关系,就可以使用lt或gt方法,等于使用eq方法,等等。这组API使用还是比较简单的,但是关于属性字段名的书写存在着安全隐患,比如查询字段name,当前是以字符串的形态书写的,万一写错,编译器还没有办法发现,只能将问题抛到运行器通过异常堆栈告诉开发者,不太友好。MP针对字段检查进行了功能升级,全面支持Lambda表达式,就有了下面这组API。由QueryWrapper对象升级为LambdaQueryWrapper对象,这下就解决了上述问题的出现。@Test public void test8() { String name = "liu"; LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(name!=null,User::getUsername,name); userMapper.selectList(queryWrapper); }1.3 业务层开发传统业务层开发①业务层接口定义public interface UserService { Boolean save(User user); Boolean update(User user); Boolean delete(Integer id); User findById(Integer id); List<User> getUsers(); IPage<User> getPages(int currentPage, int pageSize); }②业务层实现类如下,转调数据层即可@Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Override public Boolean save(User user) { return userMapper.insert(user) > 0; } @Override public Boolean update(User user) { return userMapper.updateById(user) > 0; } @Override public Boolean delete(Integer id) { return userMapper.deleteById(user) > 0; } @Override public User findById(Integer id) { return userMapper.selectById(id); } @Override public List<User> getUsers() { return userMapper.selectList(null); } @Override public IPage<User> getPages(int currentPage, int pageSize) { Page<User> page = new Page<>(); return userMapper.selectPage(page,null); } }③对业务层接口进行测试@SpringBootTest public class UserServiceTest { @Autowired private UserService userService; @Test public void test() { System.out.println(userService.findById(1)); } @Test public void test2() { IPage<User> page = userService.getPages(1, 5); System.out.println(page.getRecords()); } @Test public void test3() { List<User> userList = userService.getUsers(); for (User user : userList) { System.out.println(user); } } @Test public void test4() { User user = new User(); user.setId(15); user.setUsername("郑大"); user.setPassword("0000"); user.setGender("男"); user.setAddress("河南郑州"); userService.save(user); } @Test public void test5() { User user = new User(); user.setId(15); user.setUsername("he"); user.setPassword("0000"); user.setGender("男"); user.setAddress("河南郑州"); userService.update(user); } }使用mybatis-plus业务层快速开发MP技术不仅提供了数据层快速开发方案,业务层MP也给了一个通用接口,实际开发慎用。①业务层接口快速开发public interface IUserService extends IService<User> { }②业务层接口实现类快速开发,关注继承的类需要传入两个泛型,一个是数据层接口,另一个是实体类@Service public class IUserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService { }③对业务层快速开发接口进行测试@SpringBootTest public class IUserServiceTest { @Autowired private IUserService userService; @Test public void test() { System.out.println(userService.getById(1)); } @Test public void test2() { IPage<User> page = new Page<User>(1, 5); userService.page(page); System.out.println(page.getRecords()); } @Test public void test3() { List<User> userList = userService.list(); for (User user : userList) { System.out.println(user); } } @Test public void test4() { User user = new User(); user.setId(15); user.setUsername("郑大"); user.setPassword("0000"); user.setGender("男"); user.setAddress("河南郑州"); userService.save(user); } @Test public void test5() { User user = new User(); user.setId(15); user.setUsername("he"); user.setPassword("0000"); user.setGender("男"); user.setAddress("河南郑州"); userService.updateById(user); } @Test public void test6() { userService.removeById(16); } }1.4 表现层开发不规范的表现层开发如下①编写表现层相关方法@RestController @RequestMapping("/users") public class UserController { @Autowired private IUserService userService; @GetMapping public List<User> getUsers() { return userService.list(); } @PostMapping public Boolean save(@RequestBody User user) { return userService.save(user); } @PutMapping public Boolean update(@RequestBody User user) { return userService.updateById(user); } @DeleteMapping("/{id}") public Boolean delete(@PathVariable Integer id) { return userService.removeById(id); } @GetMapping("/{id}") public User getUser(@PathVariable Integer id) { return userService.getById(id); } @GetMapping("/{currentPage}/{pageSize}") public IPage<User> getPages(@PathVariable int currentPage,@PathVariable int pageSize) { return userService.getPages(currentPage, pageSize); } }②使用PostMan进行测试:为什么说是不规范呢?目前我们通过Postman测试后业务层接口功能时通的,但是这样的结果给到前端开发者会出现一个小问题。不同的操作结果所展示的数据格式差异化严重。每种不同操作返回的数据格式都不一样,而且还不知道以后还会有什么格式,这样的结果让前端人员看了是很容易让人崩溃的,必须将所有操作的操作结果数据格式统一起来,需要设计表现层返回结果的模型类,用于后端与前端进行数据格式统一,也称为前后端数据协议。规范表现层的开发①创建一个标准的返回类型R,其中flag用于标识操作是否成功,data用于封装操作数据package com.liu.controller.utils; import lombok.Data; /** * @author LiuChang * @version 1.0.0 * @description TODO * @date 2022/8/26 10:03 */ @Data public class R { private boolean flag; private Object data; public R() { } public R(boolean flag) { this.flag = flag; } public R(boolean flag, Object data) { this.flag = flag; this.data = data; } }②规范表现层方法@RestController @RequestMapping("/users") public class UserController { @Autowired private IUserService userService; @GetMapping public R getUsers() { return new R(true,userService.list()); } @PostMapping public R save(@RequestBody User user) { return new R(userService.save(user)); } @PutMapping public R update(@RequestBody User user) { return new R(userService.updateById(user)); } @DeleteMapping("/{id}") public R delete(@PathVariable Integer id) { return new R(userService.removeById(id)); } @GetMapping("/{id}") public R getUser(@PathVariable Integer id) { return new R(true,userService.getById(id)); } @GetMapping("/{currentPage}/{pageSize}") public R getPages(@PathVariable int currentPage,@PathVariable int pageSize) { return new R(true,userService.getPages(currentPage, pageSize)); } }1.5 页面基础功能开发①查询所有功能页面添加条件字段对应的数据模型绑定名称<el-table size="small" current-row-key="id" :data="dataList" stripe highlight-current-row> <el-table-column type="index" align="center" label="序号"></el-table-column> <el-table-column prop="username" label="用户名称" align="center"></el-table-column> <el-table-column prop="password" label="用户密码" align="center"></el-table-column> <el-table-column prop="gender" label="用户性别" align="center"></el-table-column> <el-table-column prop="address" label="用户地址" align="center"></el-table-column> <el-table-column label="操作" align="center"> <template slot-scope="scope"> <el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button> <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button> </template> </el-table-column> </el-table>页面封装字段data:{ dataList: [],//当前页要展示的列表数据 }编写方法获取数据//钩子函数,VUE对象初始化完成后自动执行 created() { this.getAll(); }, //列表 getAll() { axios.get("/users").then((res)=>{ console.log(res.data); this.dataList = res.data.data; }) },②添加功能页面添加条件字段对应的数据模型绑定名称<!-- 新增标签弹层 --> <div class="add-form"> <el-dialog title="新增用户" :visible.sync="dialogFormVisible"> <el-form ref="dataAddForm" :model="formData" :rules="rules" label-position="right" label-width="100px"> <el-row> <el-col :span="12"> <el-form-item label="用户名称" prop="username"> <el-input v-model="formData.username"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="用户密码" prop="password"> <el-input v-model="formData.password"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="用户性别" prop="gender"> <el-input v-model="formData.gender"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="地址"> <el-input v-model="formData.address" type="address"></el-input> </el-form-item> </el-col> </el-row> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="cancel()">取消</el-button> <el-button type="primary" @click="handleAdd()">确定</el-button> </div> </el-dialog> </div>页面封装字段data:{ dialogFormVisible: false,//添加表单是否可见 formData: {},//表单数据 }编写方法插入数据//弹出添加窗口 handleCreate() { this.dialogFormVisible = true; this.resetForm(); }, //重置表单 resetForm() { this.formData = {}; }, //添加 handleAdd () { axios.post("/users",this.formData).then((res)=> { //判断当前操作是否成功 if (res.data.flag) { this.dialogFormVisible = false; this.$message.success("添加成功"); }else { this.$message.error("添加失败"); } }).finally(()=> { this.getAll(); }) }, //取消 cancel(){ this.dialogFormVisible = false; this.$message.info("操作取消"); },③删除功能页面添加条件字段对应的数据模型绑定名称 <el-button type="danger" size="mini" @click="handleDelete(scope.row)">删除</el-button>编写方法删除数据// 删除 handleDelete(row) { console.log(row); this.$confirm("是否删除?","提示",{type:"info",}).then(()=>{ axios.delete("/users/"+row.id).then((res)=>{ if (res.data.flag) { this.$message.success("删除成功"); }else { this.$message.error("删除失败"); } }).finally(()=> { this.getAll(); }) }).catch(()=>{ this.$message.info("取消操作"); }) },④修改操作页面添加条件字段对应的数据模型绑定名称<el-button type="primary" size="mini" @click="handleUpdate(scope.row)">编辑</el-button> <div class="add-form"> <el-dialog title="编辑检查项" :visible.sync="dialogFormVisible4Edit"> <el-form ref="dataEditForm" :model="formData" :rules="rules" label-position="right" label-width="100px"> <el-row> <el-col :span="12"> <el-form-item label="用户名称" prop="username"> <el-input v-model="formData.username"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="用户密码" prop="password"> <el-input v-model="formData.password"/> </el-form-item> </el-col> <el-col :span="12"> <el-form-item label="用户性别" prop="gender"> <el-input v-model="formData.gender"/> </el-form-item> </el-col> </el-row> <el-row> <el-col :span="24"> <el-form-item label="地址"> <el-input v-model="formData.address" type="address"></el-input> </el-form-item> </el-col> </el-row> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="cancel()">取消</el-button> <el-button type="primary" @click="handleEdit()">确定</el-button> </div> </el-dialog> </div>页面封装字段data:{ dialogFormVisible4Edit:false,//编辑表单是否可见 }编写方法更新数据//弹出编辑窗口 handleUpdate(row) { axios.get("/users/" + row.id).then((res)=>{ if (res.data.flag && res.data.data!=null) { this.dialogFormVisible4Edit = true; this.formData = res.data.data; }else { this.$message.error("数据同步失败,自动刷新"); } }).finally(()=> { this.getAll(); }); }, //修改 handleEdit() { axios.put("/users",this.formData).then((res)=> { //判断当前操作是否成功 if (res.data.flag) { this.dialogFormVisible4Edit = false; this.$message.success("修改成功"); }else { this.$message.error("修改失败"); } }).finally(()=> { this.getAll(); }) },⑤分页查询页面添加条件字段对应的数据模型绑定名称<!--分页组件--> <div class="pagination-container"> <el-pagination class="pagiantion" @current-change="handleCurrentChange" :current-page="pagination.currentPage" :page-size="pagination.pageSize" layout="total, prev, pager, next, jumper" :total="pagination.total"> </el-pagination> </div>页面封装字段data:{ pagination: {//分页相关模型数据 currentPage: 1,//当前页码 pageSize:10,//每页显示的记录数 total:0,//总记录数 }编写方法分页查询数据//列表 getAll() { axios.get("/users/"+this.pagination.currentPage+"/"+this.pagination.pageSize).then((res)=>{ this.pagination.currentPage = res.data.data.current; this.pagination.pageSize = res.data.data.size; this.pagination.total = res.data.data.total; this.dataList = res.data.data.records; }) }, //切换页码 handleCurrentChange(currentPage) { this.pagination.currentPage = currentPage; this.getAll();⑥条件查询LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.like(Strings.isNotEmpty(user.getUsername()),User::getUsername,user.getUsername()); queryWrapper.like(Strings.isNotEmpty(user.getPassword()),User::getPassword,user.getPassword()); queryWrapper.like(Strings.isNotEmpty(user.getGender()),User::getGender,user.getGender()); queryWrapper.like(Strings.isNotEmpty(user.getAddress()),User::getAddress,user.getAddress());getAll() { //1.获取查询条件,拼接查询条件 param = "?username="+this.pagination.username; param += "&password="+this.pagination.password; param += "&gender="+this.pagination.gender; param += "&address="+this.pagination.address; axios.get("/users/"+this.pagination.currentPage+"/"+this.pagination.pageSize+param).then((res)=>{ this.pagination.currentPage = res.data.data.current; this.pagination.pageSize = res.data.data.size; this.pagination.total = res.data.data.total; this.dataList = res.data.data.records; }) },2 Spring Boot项目打包<plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin>Spring Boot的jar包在Window环境中运行:Spring Boot的jar包在Linux环境中运行:先查看了自己的ubuntu系统版本号:进入IDEA查看Maven自己是否配置成功:查看java版本号:使用Linux环境运行SpringBoot的jar包:运行成功之后发现了相关错误:可以看到是由于用户权限不够,于是使用sudo加权加权后发现本数据库中没有相关表,于是直接运行相关sql语句:再次运行可以发现项目已经成功跑出来了:可以看到后台输出的日志:3 临时属性配置SpringBoot提供了灵活的配置方式,如果你发现你的项目中有个别属性需要重新配置,可以使用临时属性的方式快速修改某些配置。在启动的时候添加上对应参数就可以了。打开SpringBoot引导类的运行界面,在里面找到配置项。其中Program arguments对应的位置就是添加临时属性的。对于IDEA没有出现的需要在Add中寻找:可以看到端口号已经修改成了8080端口:也可以在启动类中进行相关设置:4 SpringBoot高级配置4.1 SpringBoot加载第三方Bean使用@ConfigurationProperties注解其实可以为第三方bean加载属性。@Component @Data @ConfigurationProperties(prefix = "servers") public class ServletConfig { private String ipAddress; private int port; private long timeout; }servers: ipAddress: 192.168.1.2 port: 8080 timeout: 30 datasource: driverClassName: com.mysql.jdbc.cj.Driver@SpringBootApplication public class Springboot13configurationApplication { //加载第三方Bean @Bean @ConfigurationProperties(prefix = "datasource") public DruidDataSource dataSource(){ DruidDataSource dataSource = new DruidDataSource(); return dataSource; } public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(Springboot13configurationApplication.class, args); ServletConfig config = context.getBean(ServletConfig.class); System.out.println(config); DruidDataSource dataSource = context.getBean(DruidDataSource.class); System.out.println(dataSource.getDriverClassName()); } }绑定第三方数据源:@DurationUnit(ChronoUnit.HOURS) private Duration serverTimeout; @DataSizeUnit(DataUnit.KILOBYTES) private DataSize dataSize;servers: ipAddress: 192.168.1.2 port: 8080 timeout: 30 serverTimeout: 3 dataSize: 1284.2 校验配置SpringBoot给出了强大的数据校验功能,可以有效的避免此类问题的发生。在JAVAEE的JSR303规范中给出了具体的数据校验标准,开发者可以根据自己的需要选择对应的校验框架,此处使用Hibernate提供的校验框架来作为实现进行数据校验。<!--导入JSP303规范--> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> </dependency> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> </dependency>@Component @Data @ConfigurationProperties(prefix = "servers") //开启对当前Bean的属性注入校验 @Validated public class ServletConfig { private String ipAddress; @Max(value = 8888,message = "最大值不能超过8888") @Min(value = 202,message = "最小值不能小于202") private int port; private long timeout; @DurationUnit(ChronoUnit.HOURS) private Duration serverTimeout; @DataSizeUnit(DataUnit.KILOBYTES) private DataSize dataSize; }4.3 测试配置加载测试专用配置@Configuration public class MsgConfig { @Bean public String msg() { return "Bean msg"; } }@SpringBootTest @Import({MsgConfig.class}) public class ConfigurationTest { @Autowired private String msg; @Test void test1(){ System.out.println(msg); } }测试类中启动web环境@RestController @RequestMapping("/books") public class BookController { @GetMapping public String getById(){ System.out.println("getById() called"); return "springboot"; } }//开启web环境 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //开启虚拟调用MVC @AutoConfigureMockMvc public class WebTest { @Test void testWeb(@Autowired MockMvc mvc) throws Exception { //执行get请求 MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books"); mvc.perform(builder); } }匹配响应执行状态@Test void testStatus(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books1"); 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(); //预计本次调用时成功的:body ResultMatcher result = content.string("springboot1"); //添加预计值到本次调用过程中进行匹配 actions.andExpect(result); }匹配json响应体格式:@Test void testBody(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books"); ResultActions actions = mvc.perform(builder); //设定预期值,与真实的值进行比较,成功测试通过,失败测试失败 ContentResultMatchers content = MockMvcResultMatchers.content(); //预计本次调用时成功的:body ResultMatcher result = content.json("{\"name\":\"瓦尔登湖\",\"id\":1,\"type\":\"自然科学\",\"description\":\"一位隐士记录生活\"}"); //添加预计值到本次调用过程中进行匹配 actions.andExpect(result); }匹配响应头@Test void testContentType(@Autowired MockMvc mvc) throws Exception { MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.get("/books"); ResultActions actions = mvc.perform(builder); //设定预期值,与真实的值进行比较,成功测试通过,失败测试失败 HeaderResultMatchers header = MockMvcResultMatchers.header(); ResultMatcher matcher = header.string("Content-Type", "application/json"); //添加预计值到本次调用过程中进行匹配 actions.andExpect(matcher); }业务层测试事务回滚@SpringBootTest //Spring添加事务注解 @Transactional @Rollback(true) class SpringBootMybatisApplicationTests { @Autowired private UserMapper userMapper; @Test void userInserts() { User user = new User(); user.setUsername("刘畅"); user.setPassword("1314"); user.setGender("男"); user.setAddress("河南"); userMapper.insert(user); } }测试用例设置随机数据testcase: user: id: ${random.int} username: ${random.value} password: ${random.value} gender: ${random.value} address: ${random.value}@SpringBootTest //Spring添加事务注解 @Transactional @Rollback(true) class SpringBootMybatisApplicationTests { @Autowired private UserMapper userMapper; @Autowired private User user; @Test public void test(){ System.out.println(user.getId()); System.out.println(user.getUsername()); System.out.println(user.getPassword()); System.out.println(user.getGender()); System.out.println(user.getAddress()); } }4.4 数据层解决方案配置内嵌Hikari数据源spring: datasource: url: jdbc:mysql://localhost:3306/test hikari: driver-class-name: com.mysql.cj.jdbc.Driver username: root password: 131411配置内嵌 H2数据库:<dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-jpa</artifactId> </dependency>spring: h2: console: path: /h2 enabled: true datasource: url: jdbc:h2:~/test hikari: driver-class-name: org.h2.Driver username: sa password: 123456 mybatis-plus: global-config: db-config: table-prefix: tb_ server: port: 80连接H2数据库:进入H2数据库界面:查询表操作:创建表操作:插入表数据操作:查询所有操作:发生报错:Database may be already in use: "C:/Users/77339/test.mv.db". Possible solutions: close all other connection(s); use the server mode [90020-214]经过查询发现:是数据库被占用,将服务器停掉之后,问题就解决掉了。NoSQL:Redis与SpringBoot框架结合:创建新模块,选择Redis缓存。spring: redis: host: localhost port: 6379 client-type: jedis@SpringBootTest class SpringBootRedisApplicationTests { @Autowired private RedisTemplate redisTemplate; @Test void set() { ValueOperations ops = redisTemplate.opsForValue(); ops.set("age",23); } @Test void get() { ValueOperations ops = redisTemplate.opsForValue(); Object age = ops.get("age"); System.out.println(age); } @Test void setHash(){ HashOperations hash = redisTemplate.opsForHash(); hash.put("info","a","aa"); } @Test void getHash(){ HashOperations hash = redisTemplate.opsForHash(); Object o = hash.get("info", "a"); System.out.println(o); } }@SpringBootTest public class StringRedis { @Autowired private StringRedisTemplate stringRedisTemplate; @Test void get() { ValueOperations<String, String> ops = stringRedisTemplate.opsForValue(); String name = ops.get("name"); System.out.println(name); } }ES分布式全文搜索引擎1.启动ES2.操作索引
2022年07月31日
24 阅读
0 评论
1 点赞