spring boot学习笔记(二)

3、Spring Boot 使用 slf4j 日志

        在开发中经常使用 System.out.println()来打印一些信息,但是这样不好,因为大量的使用 System.out 会增加 资源的消耗。实际项目中使用的是 slf4j 的 logback 来输出日志,效率挺高的,Spring Boot 提供了一套日志系 统,logback 是最优的选择。

控制台打印输出日志         

System.out.println(需要输出的内容字符串)

        一般在开发阶段需要输出的信息较多,作为产品部署后则输出信息较少,引入了一种常量的定义方式以控制是 否输出日志。

可以通过 Constants 接口中的常量定义是否需要输出,或者使用 int 型来控制不同的输出等级

外观模式:【应用场景、优缺点、编码】,提醒大家必须记忆设计模式中的 6 大原则

为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容 易使用。可以降低访问复杂系统的内部子系统时的复杂度,简化客户端之间的接口。属于 23 种设计模式中的 结构型设计模式

优点: 1、减少系统相互依赖。 2、提高灵活性。 3、提高了安全性。

缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。 编

码实现:

1、产品接口
 

public interface Shape {

public void draw();

}

2、具体实现

3、定义子系统的外观或者门面。该子系统中包括多个产品组件

class ShapeFacade {
    private Circle circle;
    private Square square;

    public ShapeFacade() {
        circle = new Circle();  // 创建圆形对象
        square = new Square();  // 创建正方形对象
    }

    public void drawCircle() {
        circle.draw();  // 调用圆形对象的绘制方法
    }

    public void drawSquare() {
        square.draw();  // 调用正方形对象的绘制方法
    }

    public void drawCircleAndSquare() {
        circle.draw();  // 绘制圆形
        square.draw();  // 绘制正方形
    }
}

后记:事实上感觉笔记中提到的计算机案例似乎更能说明问题,

感觉电脑的例子更形象:电脑整机是 CPU、内存、硬盘的外观。有了外观以后,启动电脑和关闭电脑都简化 了。直接 new 一个电脑。在 new 电脑的同时把 cpu、内存、硬盘都初始化好并且接好线。对外暴露方法(启动电脑,关闭电脑)。

        启动电脑(按一下电源键):启动 CPU、启动内存、启动硬盘

        关闭电脑(按一下电源键):关闭硬盘、 关闭内存、关闭 CPU

1. slf4j

        SLF4J 即简单日志门面,不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J 是一个用于日志系统的简单 Facade,允许最终用户在部署其应用时使用其所希望的日志系统。 这里的意思是:只需要按统一的方式写记录日志的代码,而无需关心日志是通过哪个日志系统,以什么风格输 出的。因为它们取决于部署项目时绑定的日志系统。例如,在项目中使用了 slf4j 记录日志,并且绑定了 log4j, 即导入相应的依赖,则日志会以 log4j 的风格输出;后期需要改为以 logback 的风格输出日志,只需要将 log4j 替换成 logback 即可,不用修改项目中的代码。这对于第三方组件的引入的不同日志系统来说几乎零学习成本, 况且它的优点不仅仅这一个而已,还有简洁的占位符的使用和日志级别的判断

2021年12月8号爆出的log4j2的远程代码执行漏洞【cve-22144m25】堪称地称史诗级漏洞,虽然过了这么久,大部分现网中的相关漏洞已经修复,但任然可以捡漏...网上也有不少大佬和研究机构都对该漏洞做了分析和复盘,年前年后比较忙,一直没有好好的分析总结该漏洞,最近学习下刚好补上。

漏洞描述及影响
log4j是Apache的一个开源项目,是一个基于Java的日志记录框架。Log4j2是log4j的后继者,被大量用于业务系统开发,记录日志信息。很多互联网公司以及耳熟能详的公司的系统都在使用该框架。Apache Log4j2组件在开启了日志记录功能后,凡是在可触发错误记录日志的地方,插入漏洞利用代码,即可利用成功。特殊情况下,若该组件记录的日志包含其他系统的记录日志,则有可能造成间接投毒。通过中间系统,使得组件间接读取了具有攻击性的漏洞利用代码,亦可间接造成漏洞触发。

slf4j-log4j 通过 slf4j 调用 log4j 的实现

1、添加依赖

2、在 resources 根目录下创建一个 log4j 的配置文件 log4j.propertie

log4j.rootLogger=DEBUG, stdout    根日志记录器,参数 1 为需要输出的日志等级,

参数 2 为日志输出的目标地名称 stuout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender 设置 stdout 是控制台 输出

log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 配置日志输出的 格式

log4j.appender.stdout.layout.ConversionPattern=%5p [%t] - %m%

3、编程中使用日志记录器输出用户自定义日志信息

Log4j 输出的目的地

org.apache.log4j.ConsoleAppender(控制台)

org.apache.log4j.FileAppender(文件)

org.apache.log4j.DailyRollingFileAppender(每天产生一个日志文件)

org.apache.log4j.RollingFileAppender(文件大小到达指定尺寸的时候产生一个新的文件)

org.apache.log4j.WriterAppender(将日志信息以流格式发送到任意指定的地方)

SpringBoot 输出日志

debug:

        true 在 SpringBoot 框架启动时自动输出日志信息,同时显示相互之间的依赖关系。仅仅用于开发阶段,产品阶段一定关闭,或者删除该配置

        正因为 sfl4j 有如此多的优点,阿里已经将 slf4j 作为他们的日志框架了。在《阿里 Java 开发手册(正式版)》中, 日志规约一项第一条就强制要求使用 slf4j:

1.【强制】应用中不可直接使用日志系统(Log4j、Logback)中的 API,而应依赖使用日志框架 SLF4J 中的 API, 使用门面模式的日志框架,有利于维护和各个类的日志处理方式统一。

强制两个字体现出了 slf4j 的优势,所以建议在实际项目中,使用 slf4j 作为自己的日志框架。使用 slf4j 记录日 志非常简单,直接使用 LoggerFactory 创建即可。

目前 SpringBoot 针对日志系统默认采用 logback
 

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class Test {

private static final Logger logger = LoggerFactory.getLogger(Test.class);

// ……

}

2. application.yml 中对日志的配置

        Spring Boot 对 slf4j 支持的很好,内部已经集成了 slf4j,一般在使用的时候,会对 slf4j 做一下配置。 application.yml 文件是 Spring Boot 中唯一需要配置的文件,一开始创建工程的时候是 application.properties 文件,一般推荐使用 yml 文件,因为 yml 文件的层次感特别好,看起来更直观,但是 yml 文件对格式要求比较高,比如英文冒号后面必须要有个空格,否则项目估计无法启动,而且也不报错。用 properties 还是 yml 视个人习惯而定,实际上都是可以的。

application.yml 文件中对日志的配置:

logging:

        config: logback.xml

        level: 针对不同的包可以设置不同的日志输出等级,基本格式为【包名称: 等级】

        com.xuan.dao: trace

        logging.config 是用来指定项目启动的时候,读取哪个配置文件,这里指定的是日志配置文件是根路径下的 logback.xml 文件,关于日志的相关配置信息,都放在 logback.xml 文件中了。logging.level 是用来指定具体的 mapper 中日志的输出级别,例如配置表示 com.xuan.dao 包下的所有 mapper 日志输出级别为 trace,会将操作 数据库的 sql 打印出来,开发时设置成 trace 方便定位问题,在生产环境上,将这个日志级别再设置成 error 级别即可。

        常用的日志级别按照从高到低依次为:ERROR、WARN、INFO、DEBUG 和 TRACE。可以通过日志输出等级来 控制日志输出的详细程度

3. logback.xml 配置文件解析

        在 application.yml 文件中,指定了日志配置文件 logback.xml,logback.xml 文件中主要用来做日志的相关配置。 在 logback.xml 中可以定义日志输出的格式、路径、控制台输出格式、文件大小、保存时长等。

        3.1 定义日志输出格式和存储路径

 <configuration>可以理解为定义常量,name 就是常量名称,value 就是对应的值

        <property name="LOG_PATTERN" value=="%date{HH:mm:ss.ssS[%thread]%-5lev el%logger{36} - %msg%n" />
        <property name="FILE_PATH" value="D:/logs/demo.%d{yyyy-MM-dd}.%i.log" />

  </configuration>

配置文件的含义:首先定义一个格式,命名为 LOG_PATTERN,该格式中%date 表示日期,%thread 表示线程 名,%-5level 表示级别从左显示 5 个字符宽度,%logger{36}表示 logger 名字最长 36 个字符,%msg 表示日 志消息,%n 是换行符。

然后再定义一下名为 FILE_PATH 文件路径,日志都会存储在该路径下。%i 表示第 i 个文件,当日志文件达到 指定大小时,会将日志生成到新的文件里,这里的 i 就是文件索引,日志文件允许的大小可以设置。这里需要 注意的是,不管是 windows 系统还是 Linux 系统,日志存储的路径必须要是绝对路径。

3.2 定义控制台输出

<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder><!--按照上面配置的LOG_PATTERN来打印日志-->
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
</configuration>

 3.3 定义日志文件的相关参数

<configuration>
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <!--按照上面配置的FILE_PATH路径来保存日志-->
            <fileNamePattern>${FILE_PATH}</fileNamePattern>
            <maxHistory>15</maxHistory>日志保存15天                                                                                   
            <timeBasedFileNamingAndTriggeringPolicy
class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
                <maxFileSize>10MB</maxFileSize>单个日志文件的最大,超过则新建日志文件存储        
            </timeBasedFileNamingAndTriggeringPolicy>
        </rollingPolicy>
        <encoder>
            <!-- 按照上面配置的 LOG_PATTERN 来打印日志 -->
            <pattern>${LOG_PATTERN}</pattern>
        </encoder>
    </appender>
</configuration>

使用<appender>定义一个名为 FILE 的文件配置,主要是配置日志文件保存的时间、单个日志文件存储的大小、以及文件保存的路径和日志的输出格式。

3.4 定义日志输出级别

<configuration>
    <logger name="com.xuan" level="INFO"/>
    <root level="INFO">
        <appender-ref ref="CONSOLE"/>
        <appender-ref ref="FILE"/>
    </root>
</configuration>

有了上面那些定义后,最后使用来定义一下项目中默认的日志输出级别,这里定义级别为 INFO,然 后针对 INFO 级别的日志,使用引用上面定义好的控制台日志输出和日志文件的参数。这样 logback.xml 文件中的配置就设置完了。

4. 使用 Logger 在项目中打印日志

在代码中一般使用 Logger 对象来打印出一些 log 信息,可以指定打印出的日志级别,也支持占位符,很方便。

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.

web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping("/test")

public class TestController { private final static Logger logger = LoggerFactory.getLogger(TestController.class);

@RequestMapping("/log")

public String testLog() {

logger.debug("=====测试日志 debug 级别打印====");

logger.info("======测试日志 info 级别打印=====");

logger.error("=====测试日志 error 级别打印====");

logger.warn("======测试日志 warn 级别打印=====");

// 可以使用占位符打印出一些参数信息

String str1 = "blog.xuan.com";

String str2 = "blog.csdn.net/yanjun

        // 输出日志内容时,允许使用{}表示一个占位符,后续参数按照位置对应进行赋值 logger.info("======aix的个人博客:{};aix的 CSDN 博客:{}", str1, str2);

    return "success";

    }

}

启动该项目,在浏览器中输入 localhost:8080/test/log 后可以看到控制台的日志记录: >

======测试日志 info 级别打印=====

> =====测试日志 error 级别打印====

> ======测试日志 warn 级别打印=====

> ======闫峻的个人博客:blog.xuan.com;闫峻的 CSDN 博客:Aixxn_-CSDN博客

        因为 INFO 级别比 DEBUG 级别高,所以 debug 这条没有打印出来,如果将 logback.xml 中的日志级别设置成 DEBUG,那么四条语句都会打印出来可以测试。同时可以打开 D:\logs\demo\目录,里面有刚刚项目启动,以 后后面生成的所有日志记录。在项目部署后,大部分都是通过查看日志文件来定位问题。

5. 总结

        主要了解 slf4j 的使用,并且对 Spring Boot 中使用 slf4j 输出日志有详细的说明,着重分析 logback.xml 文件中 对日志相关信息的配置,包括日志的不同级别。最后针对这些配置,在代码中使用 Logger 打印出一些进行测 试。在实际项目中,这些日志都是排查问题的过程中非常重要的资料。

4、Spring Boot 的项目属性配置

        在项目中很多时候需要用到一些配置的信息,这些信息可能在测试环境和生产环境下会有不同的配置,后面根 据实际业务情况有可能还会做修改,针对这种情况不能将这些配置在代码中写死,最好就是写到配置文件中。 比如可以把这些信息写到 application.yml 文件中。

        在具体应用中实际上 application.properties 和 application.yml 都可以使用,并允许同时使用。如果同时进行配 置,且配置冲突,则 properties 优先于 yml

 1. 少量配置信息的情形

        例如在微服务架构中,最常见的就是某个服务需要调用其他服务来获取其提供的相关信息,那么在该服务的配 置文件中需要配置被调用的服务地址,比如在当前服务里需要调用订单微服务获取订单相关的信息,假设订单 服务的端口号是 8002,那可以做配置:

server:

        port: 8001

# 配置微服务的地址

url: # 自定义的订单微服务的地址。不是系统预定义的配置,所以不会出现任何提示

orderUrl: http://localhost:8002

        然后在业务代码中如何获取到这个配置的订单服务地址呢?可以使用@Value 注解来解决。在对应的类中加上 一个属性,在属性上使用@Value 注解即可获取到配置文件中的配置信息

@RestController

@RequestMapping("/test")

public class ConfigController {

        private static final Logger LOGGER = LoggerFactory.getLogger(ConfigController.class);         @Value("${url.orderUrl}") 其中的内容为 SpEL 即 Spring 表达式语言,可以获取配置文件中 url.orderUrl 的值

        private String orderUrl;

        @RequestMapping("/config")

        public String testConfig() {

                LOGGER.info("=====获取的订单服务地址为:{}", orderUrl);

                return "success";

        }

}

        @Value 注解上通过${key}即可获取配置文件中和 key 对应的 value 值。启动一下项目在浏览器中输入 localhost:8080/test/config 请求服务后,可以看到控制台会打印出订单服务的地址:

=====获取的订单服务地址为:http://localhost:8002

说明成功获取到了配置文件中的订单微服务地址,在实际项目中也是这么用的,后面如果因为服务器部署的原 因,需要修改某个服务的地址,那么只要在配置文件中修改即可。

2. 多个配置信息的情形

        这里有一个问题,随着业务复杂度的增加,一个项目中可能会有越来越多的微服务,某个模块可能需要调 用多个微服务获取不同的信息,那么就需sa'd'sa'd'sa'd'sa'd 要在配置文件中配置多个微服务的地址。可是在需要调用这些微服务 的代码中,如果这样一个个去使用@Value 注解引入相应的微服务地址的话,太过于繁琐,也不科学。所以在 实际项目中,业务繁琐,逻辑复杂的情况下,需要考虑封装一个或多个配置类。

        举个例子:假如在当前服务中,某个业务需要同时调用订单微服务、用户微服务和购物车微服务,分别获取订 单、用户和购物车相关信息,然后对这些信息做一定的逻辑处理。那么在配置文件中,需要将这些微服务的地 址都配置好

url: 配置多个微服务的地址 orderUrl: http://localhost:8002 订单微服务的地址,注意 key 值不能重复,但是允许 key 对应的值是集合 类型 userUrl: http://localhost:8003 用户微服务的地址 shoppingUrl: http://localhost:8004 购物车微服务的地址 实际上在实际业务中,可能远远不止这三个微服务,甚至十几个都有可能。对于这种情况可以先定义一个MicroServiceUrl 类来专门保存微服务的 url。如果配置较多,可以自定义一个专门用于存储配置参数的类 @Component 定义受管 bean,否则 Spring 无法注入配置参数值 @ConfigurationProperties(prefix = "url") 用于读取配置信息,声明配置以 url 开头。需要解析的 key 是以 url. 开始的 public class MicroServiceUrl { 专门用于存储配置信息的类 private String orderUrl; 其中的属性名称和 key 对应的除去 url.部分之外的内容一致,例如这里对应 url.orderUrl private String userUrl; private String shoppingUrl; // 省去 get 和 set 方法 } 使用@ConfigurationProperties 注解并且使用 prefix 来指定一个前缀,然后该类中的属性名就是配置中去掉前 缀后的名字,一一对应即可。即:前缀名+属性名就是配置文件中定义的 key。同时,该类上需要加@Component 注解,把该类作为组件放到 Spring 容器中,让 Spring 去管理,使用的时候直接注入即可。 需要注意的是,使用@ConfigurationProperties 注解需要导入它的依赖: org.springframework.boot spring-boot-configuration-processor true 到此为止将配置写好了,接下来写个 Controller 来测试一下。此时不需要在代码中一个个引入这些微服务的 url 了,直接通过@Resource 注解将刚刚写好配置类注入进来即可使用了,非常方便。 @RestController @RequestMapping("/test") public class TestController { private static final Logger LOGGER = LoggerFactory.getLogger(TestController.class); @Resource 可以使用 Autowired 按照类型自动装配,也可以使用 Resource 按照名称自动装配 private MicroServiceUrl microServiceUrl; @RequestMapping("/config") public String testConfig() { LOGGER.info("=====获取的订单服务地址为:{}", microServiceUrl.getOrderUrl()); LOGGER.info("=====获取的用户服务地址为:{}", microServiceUrl.getUserUrl());LOGGER.info("=====获取的购物车服务地址为:{}", microServiceUrl.getShoppingUrl()); return "success"; } } 再次启动项目,请求一下可以看到,控制台打印出如下信息,说明配置文件生效,同时正确获取配置文件内容: =====获取的订单服务地址为:http://localhost:8002 =====获取的订单服务地址为:http://localhost:8002 =====获取的用户服务地址为:http://localhost:8003 =====获取的购物车服务地址为:http://localhost:8004 注意:使用@Value 获取配置数据和通过配置参数 bean 的方式获取配置数据,两者不互斥,可以同时使用 @RestController @RequestMapping("/test") public class TestController { @Value("${url.orderUrl}") private String orderURL; @Autowired private MicroServiceUrl microServiceUrl; private static final Logger logger= LoggerFactory.getLogger(TestController.class); @GetMapping("/params") public String params(){ logger.warn("========="+orderURL); logger.error("========="+microServiceUrl.getOrderUrl()); logger.error("========="+microServiceUrl.getUserUrl()); return "success"; } } 3. 指定项目配置文件 在实际项目中,一般有两个环境:开发环境和生产环境。开发环境中的配置和生产环境中的配置往往不同,比 如环境、端口、数据库、相关地址等。实际上不可能在开发环境调试好之后,部署到生产环境后,又要将配置 信息全部修改成生产环境上的配置,这样太麻烦,也不科学。 最好的解决方法就是开发环境和生产环境都有一套对用的配置信息,然后当在开发时,指定读取开发环境的配 置,当将项目部署到服务器上之后,再指定去读取生产环境的配置。 新建两个配置文件:application-dev.yml 和 application-prod.yml,分别用来对开发环境和生产环境进行相关配 置。这里为了方便分别设置两个访问端口号,开发环境用 8001,生产环境用 8002. # 开发环境配置文件 server: port: 8001 # 生产环境配置文件server: port: 8002 然后在 application.yml 文件中指定读取哪个配置文件即可。比如在开发环境下指定读取 applicationn-dev.yml 文件 spring: profiles: active: - dev 这样就可以在开发的时候,指定读取 application-dev.yml 文件,访问的时候使用 8001 端口,部署到服务器后, 只需要将 application.yml 中指定的文件改成 application-pro.yml 即可,然后使用 8002 端口访问,非常方便。 注意:这里不是相互覆盖定义,而是只有一个配置文件生效,具体哪个配置生效却决于 active 的值。例如 active 为 abc,则自动查询对应的 application-abc.yml 文件 4. 总结 这里主要了解 Spring Boot 中在业务代码中读取相关配置,包括单一配置和多个配置项,在微服务中,这种情 况非常常见,往往会有很多其他微服务需要调用,所以封装一个配置类来接收这些配置是个很好的处理方式。 除此之外,例如数据库相关的连接参数等,也可以放到一个配置类中,其他遇到类似的场景,都可以这么处理。 最后了解开发环境和生产环境配置的快速切换方式,省去了项目部署时,诸多配置信息的修改。 5、Spring Boot 中的 MVC 支持 Spring Boot 的 MVC 支持主要来最常用的几个注解,包括@RestController 用于声明控制器、@RequestMapping 用于实现方法映射地址、@PathVariable 用于接受路径中的参数、@RequestParam 用于接受 request 请求中的 参数以及@RequestBody 用于接受 application/json 类型的请求信息。主要掌握几个注解常用的使用方式和特 点。 1. @RestController @RestController 是 Spring Boot 新增的一个注解,等价于@Controller+@ResponseBody @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Controller @ResponseBody public @interface RestController { String value() default ""; } 可以看出@RestController 注解包含了原来的@Controller 和@ResponseBody 注解,使用过 Spring 的对 @Controller 注解已经非常了解了,@ResponseBody 注解是将返回的数据结构转换为 Json 格式。所以@RestController可以看作是@Controller和@ResponseBody的结合体,为了编码方便建议使用@RestController 后就不用再使用@Controller 了。@Controller 则返回的是逻辑地址名 但是需要注意一个问题:如果是前后端分离,不用模板渲染的话,如 Thymeleaf,这种情况下是可以直接使用 @RestController 将数据以 json 格式传给前端,前端拿到之后解析;但如果不是前后端分离,需要使用模板来 渲染的话,一般 Controller 中都会返回到具体的页面,那么此时就不能使用@RestController public String getUser() { return "user"; } 其实是需要返回到 user.html 页面的,如果使用@RestController 的话,会将 user 作为字符串返回的。如果使 用@Controller 注解则表示返回一个逻辑地址名 user 字符串,需要依赖于 ViewResovler 组件将逻辑地址名称转 换为物理地址。在 Spring Boot 集成 Thymeleaf 模板引擎中会使用。 spring.mvc.view.prefix=/ spring.mvc.view.suffix=.html 如果使用@Controller,方法的返回值是字符串 user,则前后缀自动生效,将逻辑地址名 user 转换为物理地址名/user.html,静态页面默认存储位置可以考虑使用 resources/static 目录 2. @RequestMapping @RequestMapping 是一个用来处理请求地址映射的注解,它可以用于类上,也可以用于方法上。在类的级别 上的注解会将一个特定请求或者请求模式映射到一个控制器之上,表示类中的所有响应请求的方法都是以该地 址作为父路径;在方法的级别表示进一步指定到处理方法的映射关系。 @Controller @RequestMapping("/test") 表示当前类中每个方法映射路径的统一前缀/test public class TestController { @RequestMapping("/get") 针对方法的映射,加上类上的映射配置,则当前方法 的请求地址为/test/get public String get(){ return "user";} } 该注解有 6 个属性,一般在项目中比较常用的有三个属性:value、method 和 produces。 value 属性:指定请求的实际地址,如果注解中只有一个 value 属性时,value=可以省略不写 method 属性:指定请求的类型,主要有 GET、PUT、POST、DELETE,默认为 GET。如果没有对应请求 方法的定义,则页面上报错 type=Method Not Allowed, status=405 produces 属性:指定返回内容类型,如 produces = "application/json; charset=UTF-8" @RestController @RequestMapping(value = "/test", produces = "application/json; charset=UTF-8") public class TestController { @RequestMapping(value = "/bbbb", method = RequestMethod.GET) public String testGet() { return "success"; } } 针对 GET、POST、DELETE 和 PUT 四种不同的请求方式是有相应注解的,例如@GetMapping、@PostMappging 等,使用对应请求的注解后则不用每次在@RequestMapping 注解中加 method 属性来指定,上面的 GET 方式 请求可以直接使用@GetMapping("/bbbb")注解,效果一样。相应地 PUT 方式、POST 方式和 DELETE 方式对 应注解分别为@PutMapping、@PostMapping 和 DeleteMapping。 3. @PathVariable @PathVariable 注解主要是用来获取 url 参数,Spring Boot 支持 restfull 风格的 url,比如一个 GET 请求携带一 个参数 id 过来 localhost:8080/user?id=123,可以将 id 作为参数接收,注解使用@RequestParam。如果使用 路径参数则使用@PathVariable 注解。 @GetMapping("/user/{id}") 例如 http://localhost:8080/user/123 这里的{id}对应的就是 123 值。如果请求路 径为 localhost:8080/user/abc 则由于将 abc 无法转换为 Integer 类型所以报错 public String testPathVariable(@PathVariable Integer id) { 将路径参数中的 123 赋值给方法参数 id System.out.println("获取到的 id 为:" + id); return "success"; } 这里需要注意一个问题,如果想要 url 中占位符中的{id}值直接赋值到参数 id 中,需要保证 url 中的参数和方 法接收参数一致,否则就无法接收。如果不一致的话,其实也可以解决,需要用@PathVariable 中的 value 属 性来指定对应关系。 @RequestMapping("/user/{idd}") public String testPathVariable(@PathVariable(value = "idd") Integer id)System.out.println("获取到的 id 为:" + id); return "success"; } 对于访问的 url,占位符的位置可以在任何位置,不一定非要在最后,比如这样也行/xxx/{id}/user。另外 url 也支持多个占位符,方法参数使用同样数量的参数来接收,原理和一个参数是一样的 @GetMapping("/user/{idd}/{name}") 例如对应的请求地址为 localhost:8080/user/123/abc,按照位置对应 的 idd=123,name=abc public String testPathVariable(@PathVariable(value = "idd") Integer id, @PathVariable String name) { System.out.println("获取到的 id 为:" + id); System.out.println("获取到的 name 为:" + name); return "success"; } 运行项目在浏览器中请求 localhost:8080/test/user/2/zhangsan 可以看到控制台输出信息: 获取到的 id 为:2 获取到的 name 为:zhangsan 所以支持多个参数的接收。同样地,如果 url 中的参数和方法中的参数名称不同的话,也需要使用 value 属性 来绑定两个参数。 4. @RequestParam @RequestParam 也是获取请求参数的,@PathValiable 注解也是获取请求参数的, @RequestParam 和@PathVariable 有什么不同呢?主要区别在于:@PathValiable 是从 url 模板中获取参数值, 即这种风格的 url 为 http://localhost:8080/user/{id};而@RequestParam 是从 request 里面获取参数值,即这 种风格的 url 为 http://localhost:8080/user?id=1。可以使用该 url 带上参数 id 来测试代码: @GetMapping("/user") 例如请求路径为 localhost:8080/user?id=123,将数据 123 赋值给方法中的同名参数, 如果参数不是 String 类型,则自动执行数据类型转换 public String testRequestParam(@RequestParam Integer id) { System.out.println("获取到的 id 为:" + id); return "success"; } 可以正常从控制台打印出 id 信息。同样地 url 上面的参数和方法的参数需要一致,如果不一致,也需要使用 value 属性来说明,比如 url 为 http://localhost:8080/user?idd=1 @RequestMapping("/user") 例如请求路径为 localhost:8080/user?idd=123,如果没有@RequestParam 注解 则 id 为 null public String testRequestParam(@RequestParam(value = "idd", required = false) Integer id) { System.out.println("获取到的 id 为:" + id); return "success"; }除了 value 属性外,还有个两个属性比较常用: required 属性:true 表示该参数必须要传,否则就会报 404 错误,false 表示可有可无,如果没有传递这 个参数,则方法参数为 null。 defaultValue 属性:默认值,表示如果请求中没有同名参数时的默认值。 从 url 中可以看出,@RequestParam 注解用于 GET 请求上时,接收拼接在 url 中的参数【URL 重写】。除此之 外,该注解还可以用于 POST 请求,接收前端表单提交的参数,假如前端通过表单提交 username 和 password 两个参数,那可以使用@RequestParam 来接收 @PostMapping("/form1") public String testForm(@RequestParam String username, @RequestParam String password) { System.out.println("获取到的 username 为:" + username); System.out.println("获取到的 password 为:" + password); return "success"; } 具体测试种可以使用 postman 来模拟一下表单提交,测试一下接口。但是如果表单数据很多,不可能在后台 方法中写上很多参数,每个参数还要@RequestParam 注解。针对这种情况,需要封装一个实体类来接收这些 参数,实体中的属性名和表单中的参数名一致即可。 public class User { private String username; private String password; // set get } 使用实体接收的话,不能在前面加@RequestParam 注解了,直接使用即可。 @PostMapping("/form2") public String testForm(User user) { System.out.println("获取到的 username 为:" + user.getUsername()); System.out.println("获取到的 password 为:" + user.getPassword()); return "success"; } 如果写成 public String testForm(User user,String username)则提交的请求参数 username 的值会赋值两个 地址,一个 user 中的 username 属性,另外一个是方法的参数 username 可以使用 postman 再次测试一下表单提交,观察一下返回值和控制台打印出的日志即可。在实际项目中,一 般都是封装一个实体类来接收表单数据,因为实际项目中表单数据一般都很多。 5. @RequestBody @RequestBody 注解用于接收前端传来的实体,接收参数也是对应的实体,比如前端通过 json 提交传来两个参数 username 和 password,此时需要在后端封装一个实体来接收。在传递的参数比较多的情况下,使用 @RequestBody 接收会非常方便。 public class User { private String username; private String password; // set get } 控制器中方法的定义 @PostMapping("/user") public String testRequestBody(@RequestBody User user) { System.out.println("获取到的 username 为:" + user.getUsername()); System.out.println("获取到的 password 为:" + user.getPassword()); return "success"; } 可以使用 postman 工具来测试一下效果,打开 postman 然后输入请求地址和参数,参数用 json 来模拟,调用 之后返回 success。 同时看一下后台控制台输出的日志: 获取到的 username 为:闫峻 获取到的 password 为:123456 可以看出,@RequestBody 注解用于 POST 请求上,接收 json 实体参数。它和上面表单提交有点类似,只不过 参数的格式不同,一个是 json 实体,一个是表单提交。在实际项目中根据具体场景和需要使用对应的注解即 可。 6. 总结 这里主要掌握 Spring Boot 中对 MVC 的支持,重点掌握@RestController、@RequestMapping、@PathVariable、 @RequestParam 和@RequestBody 四个注解的使用方式,由于@RestController 中集成了@ResponseBody 所 以对返回 json 的注解。以上四个注解是使用频率很高的注解,在所有的实际项目中基本都会遇到,必须熟练 掌握

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值