SpringBoot-常见场景

1.热部署

  1. SpringBoot为我们提供了一个方便我们开发测试的工具dev-tools。使用后可以实现热部署的效果。当我们运行了程序后对程序进行了修改,程序会自动重启。
  2. 原理是使用了两个ClassLoder,一个ClassLoader加载哪些不会改变的类(第三方jar包),另一个ClassLoader加载会更改的类.称之为Restart ClassLoader,这样在有代码更改的时候,原来的Restart Classloader被丢弃,重新创建一个Restart ClassLoader,由于需要加载的类相比较少,所以实现了较快的重启。

1.1 准备工作

①设置IDEA自动编译

  1. idea中的setting做下面配置<br />![自动编译配置.png](https://cdn.nlark.com/yuque/0/2022/png/25966321/1650039307574-5269d6f7-6db2-45f8-9dd0-4bdc374ecd29.png#clientId=u61dc5cc6-2787-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=ue298986e&margin=%5Bobject%20Object%5D&name=%E8%87%AA%E5%8A%A8%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE.png&originHeight=499&originWidth=960&originalType=binary&ratio=1&rotation=0&showTitle=false&size=52433&status=done&style=none&taskId=ub75bf810-b23a-4a63-8049-4cb3c124b9d&title=)

②设置允许程序运行时自动启动

  1. ctrl + shift + alt + / 这组快捷键后会有一个小弹窗,点击Registry 就会进入下面的界面,找到下面的配置项并勾选,勾选后直接点close<br />![允许运行时自动启动.png](https://cdn.nlark.com/yuque/0/2022/png/25966321/1650039314291-527e8d6a-93c6-4715-a35d-e96cb70d7628.png#clientId=u61dc5cc6-2787-4&crop=0&crop=0&crop=1&crop=1&from=drop&id=ufb3d4676&margin=%5Bobject%20Object%5D&name=%E5%85%81%E8%AE%B8%E8%BF%90%E8%A1%8C%E6%97%B6%E8%87%AA%E5%8A%A8%E5%90%AF%E5%8A%A8.png&originHeight=338&originWidth=1011&originalType=binary&ratio=1&rotation=0&showTitle=false&size=27834&status=done&style=none&taskId=u3082b984-3736-4cd6-bbf6-83fea3a131d&title=)

1.2使用

①添加依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-devtools</artifactId>
  4. <optional>true</optional>
  5. </dependency>

②触发热部署

  1. 当我们在修改完代码或者静态资源后可以切换到其它软件,让IDEA自动进行编译,自动编译后就会触发热部署。
  2. 或者使用Ctrl+F9手动触发重新编译。

2.单元测试

  1. 我们可以使用SpringBoot整合Junit进行单元测试。
  2. **Spring Boot 2.2.0 版本开始引入 JUnit 5 作为单元测试默认库**。
  3. Junit5功能相比于Junit4也会更强大。但是本课程是SpringBoot的课程,所以主要针对SpringBoot如何整合Junit进行单元测试做讲解。暂不针对Junit5的新功能做介绍。如有需要会针对Junit5录制专门的课程进行讲解。

2.1 使用

①添加依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-test</artifactId>
  4. </dependency>

②编写测试类

  1. import com.sangeng.controller.HelloController;
  2. import org.junit.jupiter.api.Test;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. @SpringBootTest
  6. public class ApplicationTest {
  7. @Autowired
  8. private HelloController helloController;
  9. @Test
  10. public void testJunit(){
  11. System.out.println(1);
  12. System.out.println(helloController);
  13. }
  14. }

注意:测试类所在的包需要和启动类是在同一个包下。否则就要使用如下写法指定启动类。

  1. import com.sangeng.controller.HelloController;
  2. import org.junit.jupiter.api.Test;
  3. import org.springframework.beans.factory.annotation.Autowired;
  4. import org.springframework.boot.test.context.SpringBootTest;
  5. //classes属性来指定启动类
  6. @SpringBootTest(classes = HelloApplication.class)
  7. public class ApplicationTest {
  8. @Autowired
  9. private HelloController helloController;
  10. @Test
  11. public void testJunit(){
  12. System.out.println(1);
  13. System.out.println(helloController);
  14. }
  15. }

2.2 兼容老版本

  1. 如果是对老项目中的SpringBoot进行了版本升级会发现之前的单元测试代码出现了一些问题。
  2. 因为Junit5和之前的Junit4有比较大的不同。
  3. 先看一张图:

junit5.jpeg

  1. 从上图可以看出 **JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage**
  • JUnit Platform: 这是Junit提供的平台功能模块,通过它,其它的测试引擎也可以接入
  • JUnit JUpiter:这是JUnit5的核心,是一个基于JUnit Platform的引擎实现,它包含许多丰富的新特性来使得自动化测试更加方便和强大。
  • JUnit Vintage:这个模块是兼容JUnit3、JUnit4版本的测试引擎,使得旧版本的自动化测试也可以在JUnit5下正常运行。

    虽然Junit5包含了JUnit Vintage来兼容JUnit3和Junit4,但是SpringBoot 2.4 以上版本对应的spring-boot-starter-test移除了默认对 Vintage 的依赖。所以当我们仅仅依赖spring-boot-starter-test时会发现之前我们使用的@Test注解和@RunWith注解都不能使用了。

    我们可以单独在依赖vintage来进行兼容。

  1. <dependency>
  2. <groupId>org.junit.vintage</groupId>
  3. <artifactId>junit-vintage-engine</artifactId>
  4. <scope>test</scope>
  5. </dependency>

注意:

  1. **org.junit.Test对应的是Junit4的版本,就搭配@RunWith注解来使用。**

SpringBoot2.2.0之前版本的写法

  1. import com.sangeng.controller.HelloController;
  2. //import org.junit.jupiter.api.Test;
  3. import org.junit.Test;
  4. import org.junit.runner.RunWith;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.boot.test.context.SpringBootTest;
  7. import org.springframework.test.context.junit4.SpringRunner;
  8. //classes属性来指定启动类
  9. @SpringBootTest
  10. @RunWith(SpringRunner.class)
  11. public class ApplicationTest {
  12. @Autowired
  13. private HelloController helloController;
  14. @Test
  15. public void testJunit(){
  16. System.out.println(1);
  17. System.out.println(helloController);
  18. }
  19. }

3.整合mybatis

3.1 准备工作

①数据准备

  1. /*Table structure for table `user` */
  2. DROP TABLE IF EXISTS `user`;
  3. CREATE TABLE `user` (
  4. `id` int(11) NOT NULL AUTO_INCREMENT,
  5. `username` varchar(50) DEFAULT NULL,
  6. `age` int(11) DEFAULT NULL,
  7. `address` varchar(50) DEFAULT NULL,
  8. PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
  10. /*Data for the table `user` */
  11. insert into `user`(`id`,`username`,`age`,`address`) values (2,'pdd',25,'上海'),(3,'UZI',19,'上海11'),(4,'RF',19,NULL),(6,'三更',14,'请问2'),(8,'test1',11,'cc'),(9,'test2',12,'cc2');
  12. /*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
  13. /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
  14. /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
  15. /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;

②实体类

  1. import lombok.AllArgsConstructor;
  2. import lombok.Data;
  3. import lombok.NoArgsConstructor;
  4. @Data
  5. @AllArgsConstructor
  6. @NoArgsConstructor
  7. public class User {
  8. private Integer id;
  9. private String username;
  10. private Integer age;
  11. private String address;
  12. }

3.2 整合步骤

  1. github: [https://github.com/mybatis/spring-boot-starter/](https://github.com/mybatis/spring-boot-starter/)

①依赖

  1. <!--mybatis启动器-->
  2. <dependency>
  3. <groupId>org.mybatis.spring.boot</groupId>
  4. <artifactId>mybatis-spring-boot-starter</artifactId>
  5. <version>2.2.0</version>
  6. </dependency>
  7. <!--mysql驱动-->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <scope>runtime</scope>
  12. </dependency>

②配置数据库信息

  1. spring:
  2. datasource:
  3. url: jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&serverTimezone=UTC
  4. username: root
  5. password: root
  6. driver-class-name: com.mysql.cj.jdbc.Driver

③配置mybatis相关配置

  1. mybatis:
  2. mapper-locations: classpath:mapper/*Mapper.xml # mapper映射文件路径
  3. type-aliases-package: com.sangeng.domain # 配置哪个包下的类有默认的别名

④编写Mapper接口

注意在接口上加上@Mapper @Repository 注解

  1. @Repository
  2. @Mapper
  3. public interface UserMapper {
  4. public List<User> findAll();
  5. }

⑤编写mapper接口对应的xml文件

  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="com.sangeng.mapper.UserMapper">
  4. <select id="findAll" resultType="com.sangeng.domain.User">
  5. select * from user
  6. </select>
  7. </mapper>

⑥测试

  1. @SpringBootTest(classes = HelloApplication.class)
  2. public class SpringMyTest {
  3. @Autowired
  4. UserMapper userMapper;
  5. @Test
  6. public void tesMapper(){
  7. System.out.println(userMapper.findAll());
  8. }
  9. }

4.Web开发

4.1 静态资源访问

  1. 由于SpringBoot的项目是打成jar包的所以没有之前web项目的那些web资源目录(webapps)。
  2. 那么我们的静态资源要放到哪里呢?
  3. SpringBoot官方文档中我们可以知道,我们可以把静态资源放到 `resources/static` (或者 `resources/public` 或者`resources/resources` 或者 `resources/META-INF/resources`) 中即可。
  4. 静态资源放完后,
  5. 例如我们想访问文件:resources/static/index.html 只需要在访问时资源路径写成/index.html即可。
  6. 例如我们想访问文件:resources/static/pages/login.html 访问的资源路径写成: /pages/login.html

4.1.1 修改静态资源访问路径

  1. SpringBoot默认的静态资源路径匹配为/** 。如果想要修改可以通过 `spring.mvc.static-path-pattern` 这个配置进行修改。
  2. 例如想让访问静态资源的url必须前缀有/res。例如/res/index.html 才能访问到static目录中的。我们可以修改如下:

在application.yml中

  1. spring:
  2. mvc:
  3. static-path-pattern: /res/** #修改静态资源访问路径

4.1.2 修改静态资源存放目录

  1. 我们可以修改 spring.web.resources.static-locations 这个配置来修改静态资源的存放目录。
  2. 例如:
  1. spring:
  2. web:
  3. resources:
  4. static-locations:
  5. - classpath:/sgstatic/
  6. - classpath:/static/

4.2 设置请求映射规则@RequestMapping

  1. 详细讲解:[https://www.bilibili.com/video/BV1AK4y1o74Y](https://www.bilibili.com/video/BV1AK4y1o74Y) P5-P12
  2. 该注解可以加到方法上或者是类上。(查看其源码可知)
  3. 我们可以用其来设定所能匹配请求的要求。只有符合了设置的要求,请求才能被加了该注解的方法或类处理。

4.2.1 指定请求路径

  1. path或者value属性都可以用来指定请求路径。

例如:

  1. 我们期望让请求的资源路径为**/test/testPath**的请求能够被**testPath**方法处理则可以写如下代码
  1. @RestController
  2. @RequestMapping("/test")
  3. public class HelloController {
  4. @RequestMapping("/testPath")
  5. public String testPath(){
  6. return "testPath";
  7. }
  8. }
  1. @RestController
  2. public class HelloController {
  3. @RequestMapping("/test/testPath")
  4. public String testPath(){
  5. return "testPath";
  6. }
  7. }

4.2.2 指定请求方式

  1. method属性可以用来指定可处理的请求方式。

例如:

  1. 我们期望让请求的资源路径为**/test/testMethod**的**POST**请求能够被**testMethod**方法处理。则可以写如下代码
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testMethod",method = RequestMethod.POST)
  5. public String testMethod(){
  6. System.out.println("testMethod处理了请求");
  7. return "testMethod";
  8. }
  9. }

注意:我们可以也可以运用如下注解来进行替换

例如:

  1. 上面的需求我们可以使用下面的写法实现
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @PostMapping(value = "/testMethod")
  5. public String testMethod(){
  6. System.out.println("testMethod处理了请求");
  7. return "testMethod";
  8. }
  9. }

4.2.3 指定请求参数

  1. 我们可以使用**params**属性来对请求参数进行一些限制。可以要求必须具有某些参数,或者是某些参数必须是某个值,或者是某些参数必须不是某个值。

例如:

  1. 我们期望让请求的资源路径为**/test/testParams**的**GET**请求,并且请求参数中**具有code参数**的请求能够被testParams方法处理。则可以写如下代码
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code")
  5. public String testParams(){
  6. System.out.println("testParams处理了请求");
  7. return "testParams";
  8. }
  9. }
  1. 如果是要求**不能有code**这个参数可以把改成如下形式
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "!code")
  5. public String testParams(){
  6. System.out.println("testParams处理了请求");
  7. return "testParams";
  8. }
  9. }
  1. 如果要求有code这参数,并且这参数值必须**是某个值**可以改成如下形式
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code=sgct")
  5. public String testParams(){
  6. System.out.println("testParams处理了请求");
  7. return "testParams";
  8. }
  9. }
  1. 如果要求有code这参数,并且这参数值必须**不是某个值**可以改成如下形式
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testParams",method = RequestMethod.GET,params = "code!=sgct")
  5. public String testParams(){
  6. System.out.println("testParams处理了请求");
  7. return "testParams";
  8. }
  9. }

4.2.4 指定请求头

  1. 我们可以使用**headers**属性来对请求头进行一些限制。

例如:

  1. 我们期望让请求的资源路径为**/test/testHeaders的**GET**请求,并且请求头中**具有**deviceType**的请求能够被testHeaders方法处理。则可以写如下代码
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType")
  5. public String testHeaders(){
  6. System.out.println("testHeaders处理了请求");
  7. return "testHeaders";
  8. }
  9. }
  1. 如果是要求不能有**deviceType**这个请求头可以把改成如下形式
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "!deviceType")
  5. public String testHeaders(){
  6. System.out.println("testHeaders处理了请求");
  7. return "testHeaders";
  8. }
  9. }
  1. 如果要求有deviceType这个请求头,并且其值必须**是某个值**可以改成如下形式
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType=ios")
  5. public String testHeaders(){
  6. System.out.println("testHeaders处理了请求");
  7. return "testHeaders";
  8. }
  9. }
  1. 如果要求有deviceType这个请求头,并且其值必须**不是某个值**可以改成如下形式
  1. @RestController
  2. @RequestMapping("/test")
  3. public class TestController {
  4. @RequestMapping(value = "/testHeaders",method = RequestMethod.GET,headers = "deviceType!=ios")
  5. public String testHeaders(){
  6. System.out.println("testHeaders处理了请求");
  7. return "testHeaders";
  8. }
  9. }

4.2.5 指定请求头Content-Type

  1. 我们可以使用**consumes**属性来对**Content-Type**这个请求头进行一些限制。

范例一
  1. 我们期望让请求的资源路径为**/test/testConsumes**的POST请求,并且请求头中的Content-Type头必须为 **multipart/from-data** 的请求能够被testConsumes方法处理。则可以写如下代码
  1. @RequestMapping(value = "/testConsumes",method = RequestMethod.POST,consumes = "multipart/from-data")
  2. public String testConsumes(){
  3. System.out.println("testConsumes处理了请求");
  4. return "testConsumes";
  5. }

范例二
  1. 如果我们要求请求头Content-Type的值必须**不能为某个multipart/from-data**则可以改成如下形式:
  1. @RequestMapping(value = "/testConsumes",method = RequestMethod.POST,consumes = "!multipart/from-data")
  2. public String testConsumes(){
  3. System.out.println("testConsumes处理了请求");
  4. return "testConsumes";
  5. }

4.3 获取请求参数

4.3.1 获取路径参数

  1. RestFul风格的接口一些参数是在请求路径上的。类似: /user/1 这里的1就是id
  2. 如果我们想获取这种格式的数据可以使用[**@PathVariable **](/PathVariable )** **来实现。

范例一
  1. 要求定义个RestFul风格的接口,该接口可以用来根据id查询用户。请求路径要求为 /user ,请求方式要求为GET
  2. 而请求参数id要写在请求路径上,例如 /user/1 这里的1就是id
  3. 我们可以定义如下方法,通过如下方式来获取路径参数:
  1. @RestController
  2. public class UserController {
  3. @RequestMapping(value = "/user/{id}",method = RequestMethod.GET)
  4. public String findUserById( @PathVariable("id")Integer id){
  5. System.out.println("findUserById");
  6. System.out.println(id);
  7. return "findUserById";
  8. }
  9. }

范例二
  1. 如果这个接口,想根据idusername查询用户。请求路径要求为 /user ,请求方式要求为GET
  2. 而请求参数idname要写在请求路径上,例如 /user/1/zs 这里的1就是idzsname
  3. 我们可以定义如下方法,通过如下方式来获取路径参数:
  1. @RestController
  2. public class UserController {
  3. @RequestMapping(value = "/user/{id}/{name}",method = RequestMethod.GET)
  4. public String findUser(@PathVariable("id") Integer id,@PathVariable("name") String name){
  5. System.out.println("findUser");
  6. System.out.println(id);
  7. System.out.println(name);
  8. return "findUser";
  9. }
  10. }

4.3.2 获取请求体中的Json格式参数

  1. RestFul风格的接口一些比较复杂的参数会转换成Json通过请求体传递过来。这种时候我们可以使用[**@RequestBody **](/RequestBody )** **注解获取请求体中的数据。

4.3.2.1 配置
  1. SpringBootweb启动器已经默认导入了jackson的依赖,不需要再额外导入依赖了。

4.3.2.2 使用

范例一
  1. 要求定义个RestFul风格的接口,该接口可以用来新建用户。请求路径要求为 /user ,请求方式要求为POST

用户数据会转换成json通过请求体传递。
请求体数据

  1. {"name":"三更","age":15}

1.获取参数封装成实体对象

  1. 如果我们想把Json数据获取出来封装User对象,我们可以这样定义方法:
  1. @RestController
  2. public class UserController {
  3. @RequestMapping(value = "/user",method = RequestMethod.POST)
  4. public String insertUser(@RequestBody User user){
  5. System.out.println("insertUser");
  6. System.out.println(user);
  7. return "insertUser";
  8. }
  9. }
  1. User实体类如下:
  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. public class User {
  5. private Integer id;
  6. private String name;
  7. private Integer age;
  8. }

2.获取参数封装成Map集合

  1. 也可以把该数据获取出来封装成Map集合:
  1. @RequestMapping(value = "/user",method = RequestMethod.POST)
  2. public String insertUser(@RequestBody Map map){
  3. System.out.println("insertUser");
  4. System.out.println(map);
  5. return "insertUser";
  6. }

范例二
  1. 如果请求体传递过来的数据是一个User集合转换成的jsonJson数据可以这样定义:
  1. [{"name":"三更1","age":14},{"name":"三更2","age":15},{"name":"三更3","age":16}]
  1. 方法定义:
  1. @RequestMapping(value = "/users",method = RequestMethod.POST)
  2. public String insertUsers(@RequestBody List<User> users){
  3. System.out.println("insertUsers");
  4. System.out.println(users);
  5. return "insertUser";
  6. }

4.3.2.3 注意事项
  1. 如果需要使用[**@RequestBody **](/RequestBody )** **来获取请求体中Json并且进行转换,要求请求头 Content-Type 的值要为: application/json

4.3.3 获取QueryString格式参数

  1. 如果接口的参数是使用QueryString的格式的话,我们也可以使用SpringMVC快速获取参数。
  2. 我们可以使用[**@RequestParam **](/RequestParam )** **来获取QueryString格式的参数。

4.3.3.1 使用

范例一
  1. 要求定义个接口,该接口请求路径要求为 /testRequestParam,请求方式无要求。参数为idnamelikes。使用QueryString的格式传递。

1.参数单独的获取

  1. 如果我们想把idnamelikes单独获取出来可以使用如下写法:
  2. 在方法中定义方法参数,方法参数名要和请求参数名一致,这种情况下我们可以省略[**@RequestParam **](/RequestParam )** **注解。
  1. @RequestMapping("/testRquestParam")
  2. public String testRquestParam(Integer id, String name, String[] likes){
  3. System.out.println("testRquestParam");
  4. System.out.println(id);
  5. System.out.println(name);
  6. System.out.println(Arrays.toString(likes));
  7. return "testRquestParam";
  8. }
  1. 如果方法参数名和请求参数名不一致,我们可以加上[**@RequestParam **](/RequestParam )** **注解例如:
  1. @RequestMapping("/testRquestParam")
  2. public String testRquestParam(@RequestParam("id") Integer uid,@RequestParam("name") String name, @RequestParam("likes")String[] likes){
  3. System.out.println("testRquestParam");
  4. System.out.println(uid);
  5. System.out.println(name);
  6. System.out.println(Arrays.toString(likes));
  7. return "testRquestParam";
  8. }

2.获取参数封装成实体对象

  1. 如果我们想把这些参数封装到一个User对象中可以使用如下写法:
  1. @RequestMapping("/testRquestParam")
  2. public String testRquestParam(User user){
  3. System.out.println("testRquestParam");
  4. System.out.println(user);
  5. return "testRquestParam";
  6. }
  1. User类定义如下:
  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. public class User {
  5. private Integer id;
  6. private String name;
  7. private Integer age;
  8. private String[] likes;
  9. }
  1. 测试时请求url如下:
  1. http://localhost:8080/testRquestParam?id=1&name=三更草堂&likes=编程&likes=录课&likes=烫头
  1. **注意:实体类中的成员变量要和请求参数名对应上。并且要提供对应的set/get方法。**

4.3.4 相关注解其他属性

4.3.4.1 required
  1. 代表是否必须,默认值为true也就是必须要有对应的参数。如果没有就会报错。
  2. 如果对应的参数可传可不传则可以把其设置为fasle

例如:

  1. @RequestMapping("/testRquestParam")
  2. public String testRquestParam(@RequestParam(value = "id",required = false) Integer uid,@RequestParam("name") String name, @RequestParam("likes")String[] likes){
  3. System.out.println("testRquestParam");
  4. System.out.println(uid);
  5. System.out.println(name);
  6. System.out.println(Arrays.toString(likes));
  7. return "testRquestParam";
  8. }

4.3.4.2 defaultValue
  1. 如果对应的参数没有,我们可以用defaultValue属性设置默认值。

例如:

  1. @RequestMapping("/testRquestParam")
  2. public String testRquestParam(@RequestParam(value = "id",required = false,defaultValue = "777") Integer uid,@RequestParam("name") String name, @RequestParam("likes")String[] likes){
  3. System.out.println("testRquestParam");
  4. System.out.println(uid);
  5. System.out.println(name);
  6. System.out.println(Arrays.toString(likes));
  7. return "testRquestParam";
  8. }

4.4 响应体响应数据

  1. 无论是RestFul风格还是我们之前web阶段接触过的异步请求,都需要把数据转换成Json放入响应体中。

4.4.1 数据放到响应体

  1. 我们的SpringMVC为我们提供了[**@ResponseBody **](/ResponseBody )** **来非常方便的把Json放到响应体中。
  2. [**@ResponseBody **](/ResponseBody )** **可以加在哪些东西上面?类上和方法上
  3. 具体代码请参考范例。

4.4.2 数据转换成Json

4.4.2.1 配置
  1. SpringBoot项目中使用了webstart后,不需要进行额外的依赖和配置

4.4.2.2 使用
  1. 只要把要转换的数据直接作为方法的返回值返回即可。SpringMVC会帮我们把返回值转换成json。具体代码请参考范例。

4.4.3 范例

范例一
  1. 要求定义个RestFul风格的接口,该接口可以用来根据id查询用户。请求路径要求为 /response/user ,请求方式要求为GET
  2. 而请求参数id要写在请求路径上,例如 /response/user/1 这里的1就是id
  3. 要求获取参数id,去查询对应id的用户信息(模拟查询即可,可以选择直接new一个User对象),并且转换成json响应到响应体中。
  1. @Controller
  2. @RequestMapping("/response")
  3. public class ResponseController {
  4. @RequestMapping("/user/{id}")
  5. @ResponseBody
  6. public User findById(@PathVariable("id") Integer id){
  7. User user = new User(id, "三更草堂", 15, null);
  8. return user;
  9. }
  10. }

4.5 跨域请求

4.5.1 什么是跨域

  1. 浏览器出于安全的考虑,使用 XMLHttpRequest对象发起 HTTP请求时必须遵守同源策略,否则就是跨域的HTTP请求,默认情况下是被禁止的。 同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致。

4.5.2 CORS解决跨域

  1. CORS是一个W3C标准,全称是”跨域资源共享”(Cross-origin resource sharing),允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。
  2. 它通过服务器增加一个特殊的Header[Access-Control-Allow-Origin]来告诉客户端跨域的限制,如果浏览器支持CORS、并且判断Origin通过的话,就会允许XMLHttpRequest发起跨域请求。

4.5.3 SpringBoot使用CORS解决跨域

1.使用@CrossOrigin

可以在支持跨域的方法上或者是Controller上加上@CrossOrigin注解

  1. @RestController
  2. @RequestMapping("/user")
  3. @CrossOrigin
  4. public class UserController {
  5. @Autowired
  6. private UserServcie userServcie;
  7. @RequestMapping("/findAll")
  8. public ResponseResult findAll(){
  9. //调用service查询数据 ,进行返回
  10. List<User> users = userServcie.findAll();
  11. return new ResponseResult(200,users);
  12. }
  13. }

2.使用 WebMvcConfigurer 的 addCorsMappings 方法配置CorsInterceptor
  1. @Configuration
  2. public class CorsConfig implements WebMvcConfigurer {
  3. @Override
  4. public void addCorsMappings(CorsRegistry registry) {
  5. // 设置允许跨域的路径
  6. registry.addMapping("/**")
  7. // 设置允许跨域请求的域名
  8. .allowedOriginPatterns("*")
  9. // 是否允许cookie
  10. .allowCredentials(true)
  11. // 设置允许的请求方式
  12. .allowedMethods("GET", "POST", "DELETE", "PUT")
  13. // 设置允许的header属性
  14. .allowedHeaders("*")
  15. // 跨域允许时间
  16. .maxAge(3600);
  17. }
  18. }

4.6 拦截器

4.6.0 登录案例

4.6.0.1 思路分析
  1. 在前后端分离的场景中,很多时候会采用token的方案进行登录校验。
  2. 登录成功时,后端会根据一些用户信息生成一个token字符串返回给前端。
  3. 前端会存储这个token。以后前端发起请求时如果有token就会把token放在请求头中发送给后端。
  4. 后端接口就可以获取请求头中的token信息进行解析,如果解析不成功说明token超时了或者不是正确的token,相当于是未登录状态。
  5. 如果解析成功,说明前端是已经登录过的。

4.6.0.2 Token生成方案-JWT
  1. 本案例采用目前企业中运用比较多的JWT来生成token
  2. 使用时先引入相关依赖
  1. <dependency>
  2. <groupId>io.jsonwebtoken</groupId>
  3. <artifactId>jjwt</artifactId>
  4. <version>0.9.0</version>
  5. </dependency>
  1. 然后可以使用下面的工具类来生成和解析token
  1. import io.jsonwebtoken.Claims;
  2. import io.jsonwebtoken.JwtBuilder;
  3. import io.jsonwebtoken.Jwts;
  4. import io.jsonwebtoken.SignatureAlgorithm;
  5. import javax.crypto.SecretKey;
  6. import javax.crypto.spec.SecretKeySpec;
  7. import java.util.Base64;
  8. import java.util.Date;
  9. import java.util.UUID;
  10. /**
  11. * JWT工具类
  12. */
  13. public class JwtUtil {
  14. //有效期为
  15. public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一个小时
  16. //设置秘钥明文
  17. public static final String JWT_KEY = "sangeng";
  18. /**
  19. * 创建token
  20. * @param id
  21. * @param subject
  22. * @param ttlMillis
  23. * @return
  24. */
  25. public static String createJWT(String id, String subject, Long ttlMillis) {
  26. SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  27. long nowMillis = System.currentTimeMillis();
  28. Date now = new Date(nowMillis);
  29. if(ttlMillis==null){
  30. ttlMillis=JwtUtil.JWT_TTL;
  31. }
  32. long expMillis = nowMillis + ttlMillis;
  33. Date expDate = new Date(expMillis);
  34. SecretKey secretKey = generalKey();
  35. JwtBuilder builder = Jwts.builder()
  36. .setId(id) //唯一的ID
  37. .setSubject(subject) // 主题 可以是JSON数据
  38. .setIssuer("sg") // 签发者
  39. .setIssuedAt(now) // 签发时间
  40. .signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥
  41. .setExpiration(expDate);// 设置过期时间
  42. return builder.compact();
  43. }
  44. /**
  45. * 生成加密后的秘钥 secretKey
  46. * @return
  47. */
  48. public static SecretKey generalKey() {
  49. byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);
  50. SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");
  51. return key;
  52. }
  53. /**
  54. * 解析
  55. *
  56. * @param jwt
  57. * @return
  58. * @throws Exception
  59. */
  60. public static Claims parseJWT(String jwt) throws Exception {
  61. SecretKey secretKey = generalKey();
  62. return Jwts.parser()
  63. .setSigningKey(secretKey)
  64. .parseClaimsJws(jwt)
  65. .getBody();
  66. }
  67. }

4.6.0.3 登录接口实现

数据准备

  1. DROP TABLE IF EXISTS `sys_user`;
  2. CREATE TABLE `sys_user` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT,
  4. `username` varchar(50) DEFAULT NULL,
  5. `password` varchar(50) DEFAULT NULL,
  6. PRIMARY KEY (`id`)
  7. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
  8. /*Data for the table `sys_user` */
  9. insert into `sys_user`(`id`,`username`,`password`) values (1,'root','root'),(2,'sangeng','caotang');

实体类

  1. @Data
  2. @NoArgsConstructor
  3. @AllArgsConstructor
  4. public class SystemUser {
  5. private Integer id;
  6. private String username;
  7. private String password;
  8. }

SystemUserController

  1. import com.sangeng.domain.ResponseResult;
  2. import com.sangeng.domain.SystemUser;
  3. import com.sangeng.service.SystemUserService;
  4. import com.sangeng.utils.JwtUtil;
  5. import org.springframework.beans.factory.annotation.Autowired;
  6. import org.springframework.web.bind.annotation.PostMapping;
  7. import org.springframework.web.bind.annotation.RequestBody;
  8. import org.springframework.web.bind.annotation.RequestMapping;
  9. import org.springframework.web.bind.annotation.RestController;
  10. import java.util.HashMap;
  11. import java.util.Map;
  12. import java.util.UUID;
  13. @RestController
  14. @RequestMapping("/sys_user")
  15. public class SystemUserController {
  16. @Autowired
  17. private SystemUserService userService;
  18. @PostMapping("/login")
  19. public ResponseResult login(@RequestBody SystemUser user) {
  20. //校验用户名密码是否正确
  21. SystemUser loginUser = userService.login(user);
  22. Map<String, Object> map;
  23. if (loginUser != null) {
  24. //如果正确 生成token返回
  25. map = new HashMap<>();
  26. String token = JwtUtil.createJWT(UUID.randomUUID().toString(), String.valueOf(loginUser.getId()), null);
  27. map.put("token", token);
  28. } else {
  29. //如果不正确 给出相应的提示
  30. return new ResponseResult(300, "用户名或密码错误,请重新登录");
  31. }
  32. return new ResponseResult(200, "登录成功", map);
  33. }
  34. }

Service

  1. public interface SystemUserService {
  2. public SystemUser login(SystemUser user);
  3. }
  4. @Service
  5. public class SystemUserServcieImpl implements SystemUserService {
  6. @Autowired
  7. private SystemUserMapper systemUserMapper;
  8. @Override
  9. public SystemUser login(SystemUser user) {
  10. SystemUser loginUser = systemUserMapper.login(user);
  11. return loginUser;
  12. }
  13. }

dao

  1. @Mapper
  2. @Repository
  3. public interface UserMapper {
  4. List<User> findAll();
  5. }
  1. <?xml version="1.0" encoding="UTF-8" ?>
  2. <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
  3. <mapper namespace="com.sangeng.mapper.SystemUserMapper">
  4. <select id="login" resultType="com.sangeng.domain.SystemUser">
  5. select * from sys_user where username = #{username} and password = #{password}
  6. </select>
  7. </mapper>

4.6.0.4 登录页面
  1. 见资料

4.6.1 拦截器的概念

  1. 如果我们想在多个Handler方法执行之前或者之后都进行一些处理,甚至某些情况下需要拦截掉,不让Handler方法执行。那么可以使用SpringMVC为我们提供的拦截器。
  2. 详情见 [https://space.bilibili.com/663528522](https://space.bilibili.com/663528522) SpringMVC课程中拦截器相关章节。

4.6.1 使用步骤

①创建类实现HandlerInterceptor接口
  1. public class LoginInterceptor implements HandlerInterceptor {
  2. }

②实现方法
  1. @Component
  2. public class LoginInterceptor implements HandlerInterceptor {
  3. @Override
  4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
  5. //获取请求头中的token
  6. String token = request.getHeader("token");
  7. //判断token是否为空,如果为空也代表未登录 提醒重新登录(401)
  8. if(!StringUtils.hasText(token)){
  9. response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
  10. return false;
  11. }
  12. //解析token看看是否成功
  13. try {
  14. Claims claims = JwtUtil.parseJWT(token);
  15. String subject = claims.getSubject();
  16. System.out.println(subject);
  17. } catch (Exception e) {
  18. e.printStackTrace();
  19. //如果解析过程中没有出现异常说明是登录状态
  20. //如果出现了异常,说明未登录,提醒重新登录(401)
  21. response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
  22. return false;
  23. }
  24. return true;
  25. }
  26. }

③配置拦截器
  1. @Configuration
  2. public class LoginConfig implements WebMvcConfigurer {
  3. @Autowired
  4. private LoginInterceptor loginInterceptor;
  5. @Override
  6. public void addInterceptors(InterceptorRegistry registry) {
  7. registry.addInterceptor(loginInterceptor)//添加拦截器
  8. .addPathPatterns("/**") //配置拦截路径
  9. .excludePathPatterns("/sys_user/login");//配置排除路径
  10. }
  11. }

4.7 异常统一处理

①创建类加上@ControllerAdvice注解进行标识

  1. @ControllerAdvice
  2. public class MyControllerAdvice {
  3. }

②定义异常处理方法

  1. 定义异常处理方法,使用[**@ExceptionHandler **](/ExceptionHandler )** **标识可以处理的异常。
  1. @ControllerAdvice
  2. public class MyControllerAdvice {
  3. @ExceptionHandler(RuntimeException.class)
  4. @ResponseBody
  5. public ResponseResult handlerException(Exception e){
  6. //获取异常信息,存放如ResponseResult的msg属性
  7. String message = e.getMessage();
  8. ResponseResult result = new ResponseResult(300,message);
  9. //把ResponseResult作为返回值返回,要求到时候转换成json存入响应体中
  10. return result;
  11. }
  12. }

4.8 获取web原生对象

  1. 我们之前在web阶段我们经常要使用到request对象,responsesession对象等。我们也可以通过SpringMVC获取到这些对象。(不过在MVC中我们很少获取这些对象,因为有更简便的方式,避免了我们使用这些原生对象相对繁琐的API。)
  2. 我们只需要在方法上添加对应类型的参数即可,但是注意数据类型不要写错了,SpringMVC会把我们需要的对象传给我们的形参。
  1. @RestController
  2. public class TestController {
  3. @RequestMapping("/getRequestAndResponse")
  4. public ResponseResult getRequestAndResponse(HttpServletRequest request, HttpServletResponse response, HttpSession session){
  5. System.out.println(request);
  6. return new ResponseResult(200,"成功");
  7. }
  8. }

4.9 自定义参数解析

  1. 如果我们想实现像获取请求体中的数据那样,在Handler方法的参数上增加一个@RepuestBody注解就可以获取到对应的数据的话。
  2. 可以使用HandlerMethodArgumentResolver来实现自定义的参数解析。

①定义用来标识的注解

  1. @Target(ElementType.PARAMETER)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface CurrentUserId {
  4. }

②创建类实现HandlerMethodArgumentResolver接口并重写其中的方法

注意加上@Component注解注入Spring容器

  1. public class UserIdArgumentResolver implements HandlerMethodArgumentResolver {
  2. //判断方法参数使用能使用当前的参数解析器进行解析
  3. @Override
  4. public boolean supportsParameter(MethodParameter parameter) {
  5. //如果方法参数有加上CurrentUserId注解,就能把被我们的解析器解析
  6. return parameter.hasParameterAnnotation(CurrentUserId.class);
  7. }
  8. //进行参数解析的方法,可以在方法中获取对应的数据,然后把数据作为返回值返回。方法的返回值就会赋值给对应的方法参数
  9. @Override
  10. public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
  11. //获取请求头中的token
  12. String token = webRequest.getHeader("token");
  13. if(StringUtils.hasText(token)){
  14. //解析token,获取userId
  15. Claims claims = JwtUtil.parseJWT(token);
  16. String userId = claims.getSubject();
  17. //返回结果
  18. return userId;
  19. }
  20. return null;
  21. }
  22. }

③配置参数解析器

  1. @Configuration
  2. public class ArgumentResolverConfig implements WebMvcConfigurer {
  3. @Autowired
  4. private UserIdArgumentResolver userIdArgumentResolver;
  5. @Override
  6. public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
  7. resolvers.add(userIdArgumentResolver);
  8. }
  9. }

④测试

在需要获取UserId的方法中增加对应的方法参数然后使用@CurrentUserId进行标识即可获取到数据

  1. @RestController
  2. @RequestMapping("/user")
  3. //@CrossOrigin
  4. public class UserController {
  5. @Autowired
  6. private UserServcie userServcie;
  7. @RequestMapping("/findAll")
  8. public ResponseResult findAll(@CurrentUserId String userId) throws Exception {
  9. System.out.println(userId);
  10. //调用service查询数据 ,进行返回s
  11. List<User> users = userServcie.findAll();
  12. return new ResponseResult(200,users);
  13. }
  14. }

4.10 声明式事务

  1. 直接在需要事务控制的方法上加上对应的注解[**@Transactional **](/Transactional )** **
  1. @Service
  2. public class UserServiceImpl implements UserServcie {
  3. @Autowired
  4. private UserMapper userMapper;
  5. @Override
  6. public List<User> findAll() {
  7. return userMapper.findAll();
  8. }
  9. @Override
  10. @Transactional
  11. public void insertUser() {
  12. //添加2个用户到数据库
  13. User user = new User(null,"sg666",15,"上海");
  14. User user2 = new User(null,"sg777",16,"北京");
  15. userMapper.insertUser(user);
  16. System.out.println(1/0);
  17. userMapper.insertUser(user2);
  18. }
  19. }

4.11 AOP

  1. AOP详细知识学习见:[https://space.bilibili.com/663528522](https://space.bilibili.com/663528522) 中的Spring教程
  2. SpringBoot中默认是开启AOP功能的。如果不想开启AOP功能可以使用如下配置设置为false
  1. spring:
  2. aop:
  3. auto: false

4.11.1 使用步骤

①添加依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-aop</artifactId>
  4. </dependency>

②自定义注解

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface InvokeLog {
  4. }

③定义切面类

  1. @Aspect //标识这是一个切面类
  2. @Component
  3. public class InvokeLogAspect {
  4. //确定切点
  5. @Pointcut("@annotation(com.sangeng.aop.InvokeLog)")
  6. public void pt(){
  7. }
  8. @Around("pt()")
  9. public Object printInvokeLog(ProceedingJoinPoint joinPoint){
  10. //目标方法调用前
  11. Object proceed = null;
  12. MethodSignature signature = (MethodSignature) joinPoint.getSignature();
  13. String methodName = signature.getMethod().getName();
  14. System.out.println(methodName+"即将被调用");
  15. try {
  16. proceed = joinPoint.proceed();
  17. //目标方法调用后
  18. System.out.println(methodName+"被调用完了");
  19. } catch (Throwable throwable) {
  20. throwable.printStackTrace();
  21. //目标方法出现异常了
  22. System.out.println(methodName+"出现了异常");
  23. }
  24. return proceed;
  25. }
  26. }

④在需要正确的地方增加对应的注解

  1. @Service
  2. public class UserServiceImpl implements UserServcie {
  3. @Autowired
  4. private UserMapper userMapper;
  5. @Override
  6. @InvokeLog //需要被增强方法需要加上对应的注解
  7. public List<User> findAll() {
  8. return userMapper.findAll();
  9. }
  10. }

4.11.2 切换动态代理

  1. 有的时候我们需要修改AOP的代理方式。
  2. 我们可以使用以下方式修改:
  3. 在配置文件中配置spring.aop.proxy-target-classfalse这为使用jdk动态代理。该配置默认值为true,代表使用cglib动态代理。
  1. @SpringBootApplication
  2. @EnableAspectJAutoProxy(proxyTargetClass = false)//修改代理方式
  3. public class WebApplication {
  4. public static void main(String[] args) {
  5. ConfigurableApplicationContext context = SpringApplication.run(WebApplication.class, args);
  6. }
  7. }
  1. 如果想生效还需要在配置文件中做如下配置
  1. spring:
  2. aop:
  3. proxy-target-class: false #切换动态代理的方式

4.12 模板引擎相关-Thymeleaf

4.12.1 快速入门

4.12.1.1依赖
  1. <!--thymeleaf依赖-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  5. </dependency>

4.12.1.2定义Controller

在controller中往域中存数据,并且跳转

  1. @Controller
  2. public class ThymeleafController {
  3. @Autowired
  4. private UserServcie userServcie;
  5. @RequestMapping("/thymeleaf/users")
  6. public String users(Model model){
  7. //获取数据
  8. List<User> users = userServcie.findAll();
  9. //望域中存入数据
  10. model.addAttribute("users",users);
  11. model.addAttribute("msg","hello thymeleaf");
  12. //页面跳转
  13. return "table-standard";
  14. }
  15. }

4.12.1.3 htmL

resources\templates下存放模板页面。

在html标签中加上 xmlns:th=”http://www.thymeleaf.org

获取域中的name属性的值可以使用: ${name} 注意要在th开头的属性中使用

  1. <html lang="en" class="no-ie" xmlns:th="http://www.thymeleaf.org">
  2. .....
  3. <div class="panel-heading" th:text="${msg}">Kitchen Sink</div>

如果需要引入静态资源,需要使用如下写法。

  1. <link rel="stylesheet" th:href="@{/app/css/bootstrap.css}">
  2. <!-- Vendor CSS-->
  3. <link rel="stylesheet" th:href="@{/vendor/fontawesome/css/font-awesome.min.css}">
  4. <link rel="stylesheet" th:href="@{/vendor/animo/animate+animo.css}">
  5. <link rel="stylesheet" th:href="@{/vendor/csspinner/csspinner.min.css}">
  6. <!-- START Page Custom CSS-->
  7. <!-- END Page Custom CSS-->
  8. <!-- App CSS-->
  9. <link rel="stylesheet" th:href="@{/app/css/app.css}">
  10. <!-- Modernizr JS Script-->
  11. <script th:src="@{/vendor/modernizr/modernizr.js}" type="application/javascript"></script>
  12. <!-- FastClick for mobiles-->
  13. <script th:src="@{/vendor/fastclick/fastclick.js}" type="application/javascript"></script>

遍历语法:遍历的语法 th:each=”自定义的元素变量名称 : ${集合变量名称}”

  1. <tr th:each="user:${users}">
  2. <td th:text="${user.id}"></td>
  3. <td th:text="${user.username}"></td>
  4. <td th:text="${user.age}"></td>
  5. <td th:text="${user.address}"></td>
  6. </tr>

5.整合Redis

①依赖

  1. <!--redis-->
  2. <dependency>
  3. <groupId>org.springframework.boot</groupId>
  4. <artifactId>spring-boot-starter-data-redis</artifactId>
  5. </dependency>

②配置Redis地址和端口号

  1. spring:
  2. redis:
  3. host: 127.0.0.1 #redis服务器ip地址
  4. port: 6379 #redis端口号

③注入RedisTemplate使用

  1. @Autowired
  2. private StringRedisTemplate redisTemplate;
  3. @Test
  4. public void testRedis(){
  5. redisTemplate.opsForValue().set("name","三更");
  6. }

6.环境切换

6.1 为什么要使用profile

  1. 在实际开发环境中,我们存在开发环境的配置,部署环境的配置,测试环境的配置等等,里面的配置信息很多时,例如:端口、上下文路径、数据库配置等等,若每次切换环境时,我们都需要进行修改这些配置信息时,会比较麻烦,profile的出现就是为了解决这个问题。它可以让我们针对不同的环境进行不同的配置,然后可以通过激活、指定参数等方式快速切换环境。

6.2 使用

6.2.1 创建profile配置文件

  1. 我们可以用**application-xxx.yml**的命名方式 创建配置文件,其中xxx可以根据自己的需求来定义。
  2. 例如
  3. 我们需要一个测试环境的配置文件,则可以命名为:**application-test.yml**
  4. 需要一个生产环境的配置文件,可以命名为:**application-prod.yml**
  5. 我们可以不同环境下不同的配置放到对应的profile文件中进行配置。然后把不同环境下都相同的配置放到application.yml文件中配置。

6.2.2 激活环境

  1. 我们可以再**application.yml**文件中使用**spring.profiles.active**属性来配置激活哪个环境。
  2. 也可以使用虚拟机参数来指定激活环境。例如 **-Dspring.profiles.active=test**
  3. 也可以使用命令行参数来激活环境。例如: **--spring.profiles.active =test**

7.日志

  1. 开启日志
  1. debug: true #开启日志
  2. logging:
  3. level:
  4. com.sangeng: debug #设置日志级别

8.指标监控

  1. 我们在日常开发中需要对程序内部的运行情况进行监控, 比如:健康度、运行指标、日志信息、线程状况等等 。而SpringBoot的监控Actuator就可以帮我们解决这些问题。

8.1 使用

①添加依赖

  1. <dependency>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-actuator</artifactId>
  4. </dependency>

②访问监控接口

http://localhost:81/actuator

③配置启用监控端点

  1. management:
  2. endpoints:
  3. enabled-by-default: true #配置启用所有端点
  4. web:
  5. exposure:
  6. include: "*" #web端暴露所有端点

8.2 常用端点

端点名称 描述
beans 显示应用程序中所有Spring Bean的完整列表。
health 显示应用程序运行状况信息。
info 显示应用程序信息。
loggers 显示和修改应用程序中日志的配置。
metrics 显示当前应用程序的“指标”信息。
mappings 显示所有@RequestMapping
路径列表。
scheduledtasks 显示应用程序中的计划任务。

8.3 图形化界面 SpringBoot Admin

①创建SpringBoot Admin Server应用

要求引入spring-boot-admin-starter-server依赖

  1. <dependency>
  2. <groupId>de.codecentric</groupId>
  3. <artifactId>spring-boot-admin-starter-server</artifactId>
  4. </dependency>

然后在启动类上加上@EnableAdminServer注解

②配置SpringBoot Admin client应用

在需要监控的应用中加上spring-boot-admin-starter-client依赖

  1. <dependency>
  2. <groupId>de.codecentric</groupId>
  3. <artifactId>spring-boot-admin-starter-client</artifactId>
  4. <version>2.3.1</version>
  5. </dependency>

然后配置SpringBoot Admin Server的地址

  1. spring:
  2. boot:
  3. admin:
  4. client:
  5. url: http://localhost:8888 #配置 Admin Server的地址