Spring Boot 学习3

        1、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.hashCode();
}
public void drawCircleAndSqure(){
circle.draw();
square.draw();
}
}

 1. slf4j 介绍

SLF4J 即简单日志门面,不是具体的日志解决方案,它只服务于各种各样的日志系统。按照官方的说法,SLF4J 是一个用于日志系统的简单 Facade,允许最终用户在部署其应用时使用其所希望的日志系统。

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

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

1 、添加依赖

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

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%n

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.yan.dao: trace

logging.config 是用来指定项目启动的时候,读取哪个配置文件,这里指定的是日志配置文件是根路径下的

logback.xml 文件,关于日志的相关配置信息,都放在 logback.xml 文件中了。logging.level 是用来指定具体的

mapper 中日志的输出级别,例如配置表示 com.yan.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] %-5level 
%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> 

使用<appender>节点设置个控制台输出 class="ch.qos.logback.core.ConsoleAppender"的配置,定义为CONSOLE。使用上面定义好的输出格式 LOG_PATTERN 来输出,使用${}引用进来即可。

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.yan" level="INFO" /> 
<root level="INFO"> 
<appender-ref ref="CONSOLE" /> 
<appender-ref ref="FILE" /> 
</root> 
</configuration> 

有了上面那些定义后,最后使用<logger>来定义一下项目中默认的日志输出级别,这里定义级别为 INFO,然后针对 INFO 级别的日志,使用<root>引用上面定义好的控制台日志输出和日志文件的参数。这样 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.zhang.com"; 
String str2 = "blog.csdn.net/zhangsan";
// 输出日志内容时,允许使用{}表示一个占位符,后续参数按照位置对应进行赋值 
logger.info("======张三的个人博客:{};张三的 CSDN 博客:{}", str1, str2); 
return "success"; 
} 
} 

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

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

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

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

> ======张三的个人博客:blog.zhang.com;张三的 CSDN 博客:blog.csdn.net/zhangsna

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

2、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. 多个配置信息的情形

这里再引申一个问题,随着业务复杂度的增加,一个项目中可能会有越来越多的微服务,某个模块可能需要调用多个微服务获取不同的信息,那么就需要在配置文件中配置多个微服务的地址。可是在需要调用这些微服务的代码中,如果这样一个个去使用@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 注解需要导入它的依赖:

<dependency> 
<groupId>org.springframework.boot</groupId> 
<artifactId>spring-boot-configuration-processor</artifactId> 
<optional>true</optional> 
</dependency>

到此为止将配置写好了,接下来写个 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 文件

3、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 实体,一个是表单提交。在实际项目中根据具体场景和需要使用对应的注解即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值