SpringMVC零基础入门 - 概述、入门搭建、PostMan的使用(常见数据类型的传输)、REST风格编程

SpringMVC零基础入门 - 概述、入门搭建、PostMan的使用(常见数据类型的传输)、REST风格编程

  • SpringMVC是隶属于Spring框架的一部分,主要是用来进行Web开发,是对Servlet进行了封装
  • SpringMVC是处于Web层的框架,所以其主要的作用就是用来接收前端发过来的请求和数据然后经过处理并将处理的结果响应给前端,所以如何处理请求响应是SpringMVC中非常重要的一块内容。
  • SSM整合:SpringMVC+Spring+Mybatis整合在一起,三个框架的一个综合应用。

文章目录

  • SpringMVC零基础入门 - 概述、入门搭建、PostMan的使用(常见数据类型的传输)、REST风格编程
    • 1 SpringMVC概述
    • 2 SpringMVC入门案例
      • 2.1 Servlet开发
      • 2.2 案例制作
      • 2.3 案例总结
        • 2.3.1 工作类型
        • 2.3.2 工作流程解析
          • 2.3.2.1 启动服务器初始化过程
          • 2.3.2.2 单次请求过程
      • 2.4 bean加载控制
        • 2.4.1 问题分析
        • 2.4.2 设置bean加载控制
    • 3 PostMan工具的使用
      • 3.1 下载与安装
      • 3.2 请求与响应
        • 3.2.1 设置请求映射路径
        • 3.2.2 请求参数
          • 3.2.2.1 GET
          • 3.2.2.2 GET乱码
          • 3.2.2.3 POST
          • 3.2.2.4 POST乱码
        • 3.2.3 五种类型参数传递
          • 3.2.3.1 普通参数
          • 3.2.3.2 POJO类型参数
          • 3.2.3.3 嵌套POJO类型参数
          • 3.2.3.4 数组类型参数
          • 3.2.3.5 集合类型参数
        • 3.2.4 JSON数据传输参数
          • 3.2.4.1 JSON普通数组
          • 3.2.4.2 JSON对象
          • 3.2.4.3 JSON对象数组
          • 3.2.4.4 小结
        • 3.2.5 日期类型参数传递
          • 步骤1:编写方法接收日期数据
          • 步骤2:启动Tomcat服务器
          • 步骤3:使用PostMan发送请求
          • 步骤4:查看控制台
          • 步骤5:更换日期格式
        • 3.2.6 响应
    • 4 Rest风格
      • 4.1 REST简介
      • 4.2 RESTful入门
        • 4.2.1 行为动作的确定
        • 4.2.2 携带参数
        • 4.2.3 小结
        • 4.2.4 接受参数的注解
        • 4.2.4 接受参数的注解

1 SpringMVC概述

现在web程序大都基于三层架构来实现

image-20231226213549068
  • 浏览器发送一个请求给后端服务器,后端服务器现在是使用Servlet来接收请求和数据

  • 如果所有的处理都交给Servlet来处理的话,所有的东西都耦合在一起,对后期的维护和扩展极为不利

  • 将后端服务器Servlet拆分成三层,分别是web、service和dao

    • web层主要由servlet来处理,负责页面请求数据的收集以及响应结果给前端
    • service层主要负责业务逻辑的处理
    • dao层主要负责数据的增删改查操作
  • servlet处理请求和数据的时候,存在的问题是一个servlet只能处理一个请求

  • 针对web层进行了优化,采用了MVC设计模式,将其设计为controllerviewModel

    • controller负责请求和数据的接收,接收后将其转发给service进行业务处理

    • service根据需要会调用dao对数据进行增删改查

    • dao把数据处理完后将结果交给service, service再交给controller

    • controller根据需求组装成Model(Model 的组成部分包括 Service 层和 DAO 层)和View,Model和View组合起来生成页面转发给前端浏览器

    • 这样做的好处就是controller可以处理多个请求,并对请求进行分发,执行不同的业务操作。

      MVC设计模式中,为什么controller可以处理多个请求,而servlet处理请求和数据的时候,一个servlet只能处理一个请求?

      :总的来说,MVC的Controller是一个设计模式,而Servlet是Java中处理服务器端请求的一种技术

      Controller的设计目标是将请求路由到适当的处理程序,而不是处理具体的数据和业务逻辑

      Servlet是Java平台上的一种服务器端组件,用于处理客户端请求。每个Servlet类实例处理一个请求,这是因为Servlet是基于Java的服务器端技术,每个请求都会导致一个新的线程或处理过程来处理该请求。每个Servlet实例独立处理一个请求,这确保了线程安全性

上面的模式因为是同步调用,性能慢慢的跟不上需求,所以**异步调用慢慢的走到了前台**,是现在比较流行的一种处理方式。

image-20231226214028150
  • 因为是异步调用,所以后端不需要返回view视图,将其去除

    为什么?

    :异步调用后端通常涉及前端通过Ajax(Asynchronous JavaScript and XML)或其他异步技术向后端发送请求,而后端在收到请求后进行处理,然后将结果以某种数据格式返回给前端,而不是返回整个HTML视图。

  • 前端如果通过异步调用的方式进行交互,后台就需要将返回的数据转换成json格式进行返回
  • SpringMVC主要负责的就是
    • controller如何接收请求数据
    • 如何将请求和数据转发给业务层
    • 如何将响应数据转换成json发回到前端

综上:

  • SpringMVC是一种基于Java实现MVC模型的轻量级Web框架

  • 优点

    • 使用简单、开发便捷(相比于Servlet)
    • 灵活性强

2 SpringMVC入门案例

2.1 Servlet开发

因为SpringMVC是一个Web框架,需要我们提供Servlet(将来是要替换Servlet)

用Servlet是如何进行开发的

回顾:用Servlet是如何进行开发的

  1. 创建web工程(Maven结构)

  2. 设置tomcat服务器,加载web工程(tomcat插件)

  3. 导入坐标(Servlet)

  4. 定义处理请求的功能类(UserServlet)

  5. 设置请求映射(配置映射关系)

SpringMVC的制作过程和上述流程几乎是一致的,具体的实现流程:

  1. 创建web工程(Maven结构)

  2. 设置tomcat服务器,加载web工程(tomcat插件)

  3. 导入坐标(SpringMVC+Servlet)

  4. 定义处理请求的功能类(UserController)

  5. 设置请求映射(配置映射关系)

  6. 将SpringMVC设定加载到Tomcat容器中

2.2 案例制作

步骤1: 创建Maven项目

打开IDEA,创建一个新的web项目

① 使用骨架(archetype):

image-20240105140511204

image-20240105141051793

maven项目的三个坐标,可采用默认,也可自己修改

image-20240105141123960

点击创建后,会自动从阿里云下载包:

image-20240105141416573

下载完成:

image-20240105141440536

如果发现创建的模块位置不对,可以在refactor里面移动:

image-20240105141804939

image-20240105141838961

修改路径:(在这里删掉后面即可)

image-20240105142004932

如果消失了,通过maven导入的方式导入即可:

image-20240105142537821

image-20240105142600342

image-20240105142630290

进行一些修改与添加:

1 在依赖中选择打包方式:war

image-20240105142155268

2 默认没有java和resources目录,需要手动完成创建补齐,最终的目录结果如下

image-20240105142942217

② 不使用骨架:

image-20240105143247285

剩下的就是修改打包方式和补全相关目录了

步骤2:导入jar包

将pom.xml中多余的内容删除掉,再添加SpringMVC需要的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.baidu</groupId><artifactId>springmvc_01_quickstart</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><dependencies><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>3.1.0</version><scope>provided</scope></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-webmvc</artifactId><version>5.2.10.RELEASE</version></dependency></dependencies><build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><port>8080</port><path>/</path></configuration></plugin></plugins></build>
</project>

回顾: servlet的坐标为什么需要添加<scope>provided</scope>?

  • scope是maven中jar包依赖作用范围的描述,

  • 如果不设置默认是compile在在编译、运行、测试时均有效

  • 如果运行有效的话就会和tomcat中的servlet-api包发生冲突,导致启动报错

  • provided代表的是该包只在编译和测试的时候用,运行的时候无效直接使用tomcat中的,就避免冲突

springmvc依赖和servlet依赖和插件

  • Spring Web MVC依赖: 这个依赖用于引入整个Spring Web MVC框架。它包含了在构建基于Spring MVC的Web应用程序时所需的所有Spring框架的相关库和功能

    SpringMVC是基于Spring的,在pom.xml只导入了spring-webmvcjar包的原因是它会自动依赖spring相关坐标

  • Java Servlet API依赖: 这个依赖用于引入Java Servlet API规范。它只包含了Java Servlet规范中定义的类和接口,用于支持Servlet的开发。通常,这个依赖的scope被设置为provided,因为Servlet容器(即我们这个实例中的tomcat)已经包含了这个API,而且在部署时会由Servlet容器提供

  • tomcat7-maven-plugin插件也可以用maven-compiler-plugin插件):定义和配置Java编译器的行为。插件可以帮助你指定编译源代码的Java版本,以及生成的字节码文件的目标Java版本如果没有正确配置插件,可能会导致以下问题:1. Java版本不匹配;2.字节码版本不匹配

    如果不用插件的话,就必须确保Spring的版本和JDK的版本匹配才行,即对Spring框架版本和JDK版本进行调整

    不匹配时所报的错误

    image-20240105164140094

步骤4:创建配置类

@Configuration
@ComponentScan("com.baidu.controller")
public class SpringMvcConfig {
}

步骤5:创建Controller类

@Controller
public class UserController {@RequestMapping("/save")@ResponseBodypublic String save(){System.out.println("user save ...");return "{'info':'springmvc'}";}
}

return "{'info':'springmvc'}":前面我们说过现在主要的是前端发送异步请求,后台响应json数据,如果这里没有返回值,会报错

@ResponseBody:设置当前控制器方法响应内容为当前返回值,无需解析。如果方法直接返回字符串,springmvc会把字符串当成页面的名称在项目中进行查找返回,会报404错误,找不到资源。

步骤6:使用配置类替换web.xml

将web.xml删除,换成ServletContainersInitConfig

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {//加载springmvc配置类protected WebApplicationContext createServletApplicationContext() {//初始化WebApplicationContext对象AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();//加载指定配置类ctx.register(SpringMvcConfig.class);return ctx;}//设置由springmvc控制器处理的请求映射路径protected String[] getServletMappings() {return new String[]{"/"};}//加载spring配置类protected WebApplicationContext createRootApplicationContext() {return null;}
}
  • AbstractDispatcherServletInitializer类是SpringMVC提供的快速初始化Web3.0容器的抽象类

  • AbstractDispatcherServletInitializer提供了三个接口方法供用户实现

    • createServletApplicationContext方法,创建Servlet容器时,加载SpringMVC对应的bean并放入WebApplicationContext对象范围中,而WebApplicationContext的作用范围为ServletContext范围,即整个web容器范围

    • getServletMappings方法,设定SpringMVC对应的请求映射路径,即SpringMVC拦截哪些请求

      注意:

      DispatcherServlet是Spring MVC框架的核心组件,负责处理所有的HTTP请求并将它们分发到相应的控制器(Controller)进行处理。

      return new String[]{"/"};这种配置方式意味着所有的请求都会经过DispatcherServlet,然后由该框架的其他组件来处理和响应。

      DispatcherServlet拦截请求并不意味着请求被阻止或拒绝访问,而是表示DispatcherServlet会接管这个请求并尝试将其分发到合适的Controller进行处理。

      如何取消部分拦截?

      如果希望某些请求不被拦截(特别是某些静态资源),需要配置DispatcherServlet以排除这些路径

      添加一个配置类

      @Configuration
      public class SpringMvcSupport extends WebMvcConfigurationSupport {//设置静态资源访问过滤,当前类需要设置为配置类,并被扫描加载@Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {//当访问/pages/????时候,从/pages目录下查找内容registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");registry.addResourceHandler("/js/**").addResourceLocations("/js/");registry.addResourceHandler("/css/**").addResourceLocations("/css/");registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");}
      }
      

      配置好之后要让SpringMvcConfig扫描到这个包(@ComponentScan注解)

    • createRootApplicationContext方法,如果创建Servlet容器时需要加载非SpringMVC对应的bean,使用当前方法进行,使用方式和createServletApplicationContext相同。

      这类初始化器(initializer)负责配置和初始化 DispatcherServlet,这是 Spring MVC 的中央控制器

      Spring MVC 应用程序通常会包含两个上下文:(仍有疑点,不能区分二者的本质)

      1. Servlet 上下文(Servlet WebApplicationContext): 用于配置 DispatcherServlet。在你的代码中,这个上下文通过 createServletApplicationContext() 方法创建,并加载了指定的配置类 SpringMvcConfig.class
      2. 根应用程序上下文(Root WebApplicationContext): 用于配置应用程序级别的共享的 bean,比如 Service 层、Repository 层等。这个上下文通常被整个应用程序共享,而不是针对某个特定的 Servlet。在你的代码中,createRootApplicationContext() 方法返回 null,表示在这里并没有定义根应用程序上下文。
    • createServletApplicationContext用来加载SpringMVC环境

    • createRootApplicationContext用来加载Spring环境

为什么这上面没有注解配置?(@XXX)

这个类是作为AbstractDispatcherServletInitializer的子类,而这个类(AbstractDispatcherServletInitializer)本身就是Spring框架提供的用于配置DispatcherServlet初始化的一部分。Spring框架会自动检测并使用这个类,所以并不需要显式地添加其他配置注解

步骤7:配置Tomcat环境

步骤8:启动运行项目

步骤9:浏览器访问

运行结果:

image-20240105164656996

知识点1:@Controller

名称@Controller
类型类注解
位置SpringMVC控制器类定义上方
作用设定SpringMVC的核心控制器bean

知识点2:@RequestMapping

名称@RequestMapping
类型类注解或方法注解
位置SpringMVC控制器类或方法定义上方
作用设置当前控制器方法请求访问路径
相关属性value(默认),请求访问路径

知识点3:@ResponseBody

名称@ResponseBody
类型类注解或方法注解
位置SpringMVC控制器类或方法定义上方
作用设置当前控制器方法响应内容为当前返回值,无需解析

2.3 案例总结

2.3.1 工作类型
  • 一次性工作
    • 创建工程,设置服务器,加载工程
    • 导入坐标
    • 创建web容器启动类,加载SpringMVC配置,并设置SpringMVC请求拦截路径
    • SpringMVC核心配置类(设置配置类,扫描controller包,加载Controller控制器bean)
  • 多次工作
    • 定义处理请求的控制器类
    • 定义处理请求的控制器方法,并配置映射路径(@RequestMapping)与返回json数据(@ResponseBody)
2.3.2 工作流程解析

SpringMVC的使用过程总共分两个阶段来分析,分别是启动服务器初始化过程单次请求过程

image-20240105200152484
2.3.2.1 启动服务器初始化过程
  1. 服务器启动,执行ServletContainersInitConfig类初始化web容器,功能类似于以前的web.xml

  2. 执行createServletApplicationContext方法,创建了WebApplicationContext对象

    该方法加载SpringMVC的配置类SpringMvcConfig来初始化SpringMVC的容器

  3. 加载SpringMvcConfig配置类

    image-20240105200754528

  4. 执行@ComponentScan加载对应的bean

    扫描指定包及其子包下所有类上的注解,如Controller类上的@Controller注解

  5. 加载UserController每个@RequestMapping的名称对应一个具体的方法

    image-20240105201312237

    • 此时就建立了 /save 和 save方法的对应关系
  6. 执行getServletMappings方法,设定SpringMVC拦截请求的路径规则

    image-20240105201329032

    • /代表所拦截请求的路径规则,只有被拦截后才能交给SpringMVC来处理请求
2.3.2.2 单次请求过程
  1. 发送请求http://localhost/save
  2. web容器发现该请求满足SpringMVC拦截规则,将请求交给SpringMVC处理
  3. 解析请求路径/save
  4. 由/save匹配执行对应的方法save()
    • 上面的第5.步已经将请求路径和方法建立了对应关系,通过/save就能找到对应的save方法
  5. 执行save()
  6. 检测到有@ResponseBody直接将save()方法的返回值作为响应体返回给请求方

2.4 bean加载控制

2.4.1 问题分析

SpringMvcConfig配置类和之前的SpringConfig配置类

这两个配置类都需要加载资源,那么它们分别都需要加载哪些内容?

分析项目结构:

  • config目录存入的是配置类,写过的配置类有:
    • ServletContainersInitConfig
    • SpringConfig
    • SpringMvcConfig
    • JdbcConfig
    • MybatisConfig
  • controller目录存放的是SpringMVC的controller类
  • service目录存放的是service接口和实现类
  • dao目录存放的是dao/Mapper接口

controller、service和dao这些类都需要被容器管理成bean对象,

那么到底是该让SpringMVC加载还是让Spring加载呢?

  • SpringMVC加载的bean:
    • 表现层bean(也就是controller包下的类)
  • Spring加载的bean:
    • 业务bean(Service)
    • 功能bean(DataSource,SqlSessionFactoryBean,MapperScannerConfigurer等)

如何让Spring和SpringMVC分开加载各自的内容?

在SpringMVC的配置类SpringMvcConfig中使用注解@ComponentScan,我们只需要将其扫描范围设置到controller即可,如

image-20240105202124900

在Spring的配置类SpringConfig中使用注解@ComponentScan,当时扫描的范围中其实是已经包含了controller,如:

image-20240105204109116

从包结构来看的话,Spring已经多把SpringMVC的controller类也给扫描到,所以针对这个问题该如何解决?

因为功能不同,如何避免Spring错误加载到SpringMVC的bean?

2.4.2 设置bean加载控制
  • 方式一:Spring加载的bean设定扫描范围为精准范围,例如service包、dao包等
  • 方式二:Spring加载的bean设定扫描范围为com.baidu,排除掉controller包中的bean
  • 方式三:不区分Spring与SpringMVC的环境,加载到同一个环境中[了解即可]

方式一: 修改Spring配置类,设定扫描范围为精准范围。

@Configuration
@ComponentScan({"com.baidu.service","com.baidu.dao"})
public class SpringConfig {
}

说明:

上述只是通过例子说明可以精确指定让Spring扫描对应的包结构,真正在做开发的时候,因为Dao最终是交给MapperScannerConfigurer对象来进行扫描处理的,我们只需要将其扫描到service包即可

方式二: 修改Spring配置类,设定扫描范围为com.baidu,排除掉controller包中的bean

@Configuration
@ComponentScan(value="com.baidu",excludeFilters=@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class)
)
public class SpringConfig {
}
  • excludeFilters属性:设置扫描加载bean时,排除的过滤规则

  • type属性:设置排除规则,当前使用按照bean定义时的注解类型进行排除

    • ANNOTATION:按照注解排除
    • ASSIGNABLE_TYPE:按照指定的类型过滤
    • ASPECTJ:按照Aspectj表达式排除,基本上不会用
    • REGEX:按照正则表达式排除
    • CUSTOM:按照自定义规则排除

    只需要知道第一种ANNOTATION即可

  • classes属性:设置排除的具体注解类,当前设置排除@Controller定义的bean

如何测试controller类已经被排除掉了?

public class App{public static void main (String[] args){AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);System.out.println(ctx.getBean(UserController.class));}
}

如果被排除了,该方法执行就会报bean未被定义的错误

image-20240105203351094

注意:

  • 需要把SpringMvcConfig配置类上的@ComponentScan注解注释掉,否则不会报错
  • @Import({JdbcConfig.class,MybatisConfig.class})这类的注解也要注释掉,否则不会报错

原因是:

  • Spring配置类扫描的包是com.baidu
  • SpringMVC的配置类,SpringMvcConfig上有一个@Configuration注解,也会被Spring扫描到
  • SpringMvcConfig上又有一个@ComponentScan,把controller类又给扫描进来了
  • 所以如果不把@ComponentScan注释掉,Spring配置类将Controller排除,但是因为扫描到SpringMVC的配置类,又将其加载回来,演示的效果就出不来
  • 解决方案,也简单,把SpringMVC的配置类移出Spring配置类的扫描范围即可。

方式三:要想在tomcat服务器启动将其加载

有了Spring的配置类,要想在tomcat服务器启动将其加载,我们需要修改ServletContainersInitConfig

Servlet上下文:SpringMvcConfig

根应用程序上下文:SpringConfig

public class ServletContainersInitConfig extends AbstractDispatcherServletInitializer {protected WebApplicationContext createServletApplicationContext() {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringMvcConfig.class);return ctx;}protected String[] getServletMappings() {return new String[]{"/"};}protected WebApplicationContext createRootApplicationContext() {AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();ctx.register(SpringConfig.class);return ctx;}
}

对于上述的配置方式,Spring还提供了一种更简单的配置方式,可以不用再去创建AnnotationConfigWebApplicationContext对象,不用手动register对应的配置类:

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {protected Class<?>[] getRootConfigClasses() {return new Class[]{SpringConfig.class};}protected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}protected String[] getServletMappings() {return new String[]{"/"};}
}

如果没有对应的SpringConfig或者SpringMvcConfig,返回null或者new Class[0](本质上也是null)

知识点1:@ComponentScan

名称@ComponentScan
类型类注解
位置类定义上方
作用设置spring配置类扫描路径,用于加载使用注解格式定义的bean
相关属性excludeFilters:排除扫描路径中加载的bean,需要指定类别(type)和具体项(classes)
includeFilters:加载指定的bean,需要指定类别(type)和具体项(classes)

3 PostMan工具的使用

PostMan是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件

作用:常用于进行接口测试

3.1 下载与安装

官网下载:Postman下载官网

3.2 请求与响应

SpringMVC是web层的框架,主要的作用是接收请求、接收数据、响应结果

3.2.1 设置请求映射路径

多个contoller中都有一个方法,如何设置映射路径?

  • 当类上和方法上都添加了@RequestMapping注解,前端发送请求的时候,要和两个注解的value值相加匹配才能访问到。

  • @RequestMapping注解value属性前面加不加/都可以

    package com.baidu.controller;import org.springframework.stereotype.Controller;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.ResponseBody;@Controller
    //类上方配置的请求映射与方法上面配置的请求映射连接在一起,形成完整的请求映射路径
    @RequestMapping("/user")
    public class UserController {//请求路径映射@RequestMapping("/save")@ResponseBodypublic String save(){System.out.println("user save ...");return "{'module':'user save'}";}//请求路径映射@RequestMapping("/delete")@ResponseBodypublic String delete(){System.out.println("user delete ...");return "{'module':'user delete'}";}
    }
    
3.2.2 请求参数

针对于不同的请求(GET,POST)前端如何发送,后端如何接收?

3.2.2.1 GET

GET发送单个参数

GET发送多个参数

报错:Failed to register servlet with name ‘dispatcher’. Check if there is another servlet registered under the same name.

原因:target下面出现了两个相同的配置类,删去其中一个就好了

注意:Tomcat启动后访问Spring MVC应用时,Tomcat会运行target目录下的编译后的类文件。

@Controller
public class UserController {@RequestMapping("/commonParam")@ResponseBodypublic String commonParam(String name,int age){System.out.println("普通参数传递 name ==> "+name);System.out.println("普通参数传递 age ==> "+age);return "{'module':'commonParam'}";}
}
http://localhost:8080/springmvc_04_request_param/commonParam?name=baidu&age=15

image-20240106133237720

image-20240106133640135

3.2.2.2 GET乱码

GET请求中文乱码

乱码的原因:Tomcat8.5以后的版本已经处理了中文乱码的问题,但是IDEA中的Tomcat插件目前只到Tomcat7;

所以需要修改pom.xml来解决GET请求中文乱码问题

<build><plugins><plugin><groupId>org.apache.tomcat.maven</groupId><artifactId>tomcat7-maven-plugin</artifactId><version>2.1</version><configuration><port>8080</port><!--tomcat端口号--><path>/</path> <!--虚拟目录--><uriEncoding>UTF-8</uriEncoding><!--访问路径编解码字符集--></configuration></plugin></plugins></build>
3.2.2.3 POST

POST发送参数

POST发送表单数据

**注意:要选择x-www-form-urlencoded,而不是form-date,选择后者会报错**报错如下:

Request processing failed; nested exception is java.lang.IllegalStateException: Optional int parameter 'age' is present but cannot be translated into a null value due to being declared as a primitive type. Consider declaring it as object wrapper for the corresponding primitive type.

image-20240106135603794

后端和GET一致,不需要做任何修改

@Controller
public class UserController {@RequestMapping("/commonParam")@ResponseBodypublic String commonParam(String name,int age){System.out.println("普通参数传递 name ==> "+name);System.out.println("普通参数传递 age ==> "+age);return "{'module':'commonParam'}";}
}
3.2.2.4 POST乱码

POST请求中文乱码

解决办法:配置过滤器(即替代web.xml的那个类),重写其getServletFilters方法

CharacterEncodingFilter是在spring-web包中,所以用之前需要导入对应的jar包

public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {protected Class<?>[] getRootConfigClasses() {return new Class[0];}protected Class<?>[] getServletConfigClasses() {return new Class[]{SpringMvcConfig.class};}protected String[] getServletMappings() {return new String[]{"/"};}//乱码处理@Overrideprotected Filter[] getServletFilters() {CharacterEncodingFilter filter = new CharacterEncodingFilter();filter.setEncoding("UTF-8");return new Filter[]{filter};}
}
3.2.3 五种类型参数传递
  • 普通参数
  • POJO类型参数
  • 嵌套POJO类型参数
  • 数组类型参数
  • 集合类型参数
3.2.3.1 普通参数

不使用参数注解接受的前提:对应的值拼写一定要相同

image-20240106140351415

如果不相同,需要使用参数注解:@RequestParam,否则接受为null

image-20240106140551750

3.2.3.2 POJO类型参数
  • POJO参数:请求参数名与形参对象属性名相同,定义POJO类型形参即可接收参数

POJO类:

public class User {private String name;private int age;//setter...getter...略
}

发送与接受:

image-20240106141026542

注意:

  • POJO参数接收,前端GET和POST发送请求数据的方式不变。

  • 请求参数key的名称要和POJO中属性的名称一致,否则无法封装。

  • 没有的属性可以不用填写,后端接受直接为null

  • 参数的顺序可以不用一一对应,下面的请求同样能达到效果

    http://localhost:8080/springmvc_04_request_param/pojoContainPojoParam?age=15&name=百度
    
3.2.3.3 嵌套POJO类型参数

如果POJO对象中嵌套了其他的POJO类,如:

public class Address {private String province;private String city;//setter...getter...略
}
public class User {private String name;private int age;private Address address;//setter...getter...略
}

发送请求方法:请求参数名与形参对象属性名相同,按照对象层次结构关系即可接收嵌套POJO属性参数

发送与接受:

http://localhost:8080/springmvc_04_request_param/pojoContainPojoParam?name=百度&age=15&address.city=sichuan&address.province=chengdu

image-20240106141645115

3.2.3.4 数组类型参数
  • 数组参数:请求参数名与形参对象属性名相同且请求参数为多个,定义数组类型即可接收参数

注意:参数名必须一致才能封装到一个数组中

发送与接受:

http://localhost:8080/springmvc_04_request_param/arrayParam?likes=movie&likes=music&likes=dance

image-20240106142225573

3.2.3.5 集合类型参数

如List集合

如果:

http://localhost:8080/springmvc_04_request_param/listParam?likes=movie&likes=music&likes=dance

对应的后端:

image-20240106142434147

会报错:SpringMVC将List看做是一个POJO对象来处理,将其创建一个对象并准备把前端的数据封装到对象中,但是List是一个接口无法创建对象,所以报错。

发送与接受:

使用参数注解:@RequestParam,同名请求参数可以使用@RequestParam注解映射到对应名称的集合对象中作为数据

image-20240106142738106
  • 集合保存普通参数:请求参数名与形参集合对象名相同且请求参数为多个,@RequestParam绑定参数关系
  • 对于简单数据类型使用数组会比集合更简单些。
3.2.4 JSON数据传输参数

前端如果发送的是JSON数据,后端该如何接收?

对于JSON数据类型,我们常见的有三种:

  • json普通数组([“value1”,“value2”,“value3”,…])
  • json对象({key1:value1,key2:value2,…})
  • json对象数组([{key1:value1,…},{key2:value2,…}])

SpringMVC默认使用的是jackson来处理json的转换,所以需要在pom.xml添加jackson依赖

<dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.9.0</version>
</dependency>
3.2.4.1 JSON普通数组

用List集合接受

  • 开启SpringMVC注解支持

    在SpringMVC的配置类中开启SpringMVC的注解支持,这里面就包含了将JSON转换成对象的功能。

    @EnableWebMvc是Spring Framework中的注解,用于启用Spring MVC的基本功能。当你在配置类上使用@EnableWebMvc注解时,它会开启Spring MVC的特性,包括但不限于:

    1. 启用@Controller注解
    2. 启用@RequestMapping注解
    3. 启用@ExceptionHandler注解
    4. 启用@ResponseBody注解
    5. 启用视图解析器:于解析Controller方法返回的视图名

    @EnableWebMvc是较旧的配置Spring MVC的方式如果使用SpringBoot,它提供了自动配置,通常不需要显式使用@EnableWebMvc,因为它已经包含在默认配置中。

    @Configuration
    @ComponentScan("com.baidu.controller")
    //开启json数据类型自动转换
    @EnableWebMvc
    public class SpringMvcConfig {
    }
    
  • 参数前添加@RequestBody

    使用**@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据**

    //使用@RequestBody注解将外部传递的json数组数据映射到形参的集合对象中作为数据
    @RequestMapping("/listParamForJson")
    @ResponseBody
    public String listParamForJson(@RequestBody List<String> likes){System.out.println("list common(json)参数传递 list ==> "+likes);return "{'module':'list common for json param'}";
    }
    
  • 启动运行程序

  • PostMan发送JSON数据接收响应

    image-20240110171934966

    image-20240110172000177

3.2.4.2 JSON对象

用对象接受

  • 数据:

    {"name":"itcast","age":15
    }
    
  • 后端接收数据:

    @RequestMapping("/pojoParamForJson")
    @ResponseBody
    public String pojoParamForJson(@RequestBody User user){System.out.println("pojo(json)参数传递 user ==> "+user);return "{'module':'pojo for json param'}";
    }
    
  • 发送请求接受数据

    image-20240110192847407

    image-20240110192423054

    address为null的原因是前端没有传递数据给后端。

    如果想要address也有数据,我们需求修改前端传递的数据内容:

    {"name":"itcast","age":15,"address":{"province":"beijing","city":"beijing"}
    }
    

    image-20240110192711444

3.2.4.3 JSON对象数组

集合中保存多个POJO的情况

用List集合接受

  • 数据

    [{"name":"itcast","age":15},{"name":"baidu","age":12}
    ]
    
  • 后端接收数据:

    @RequestMapping("/listPojoParamForJson")
    @ResponseBody
    public String listPojoParamForJson(@RequestBody List<User> list){System.out.println("list pojo(json)参数传递 list ==> "+list);return "{'module':'list pojo for json param'}";
    }
    
  • 发送请求和接受数据

    image-20240110193053972

    image-20240110193136157

以上这些请求用POST也可以实现

3.2.4.4 小结

SpringMVC接收JSON数据的实现步骤为:

(1)导入jackson包

(2)使用PostMan发送JSON数据

(3)开启SpringMVC注解驱动,在配置类上添加@EnableWebMvc注解

(4)Controller方法的参数前添加@RequestBody注解

知识点1:@EnableWebMvc

名称@EnableWebMvc
类型配置类注解
位置SpringMVC配置类定义上方
作用开启SpringMVC多项辅助功能

知识点2:@RequestBody

名称@RequestBody
类型形参注解
位置SpringMVC控制器方法形参定义前面
作用将请求中请求体所包含的数据传递给请求参数,此注解一个处理器方法只能使用一次

@RequestBody与@RequestParam区别

  • 区别

    • @RequestParam用于接收url地址传参,表单传参【application/x-www-form-urlencoded】
    • @RequestBody用于接收json数据【application/json】
  • 应用

    • 后期开发中,发送json格式数据为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数
3.2.5 日期类型参数传递

难点之一,形式多样,比如:

  • 2088-08-18
  • 2088/08/18
  • 08/18/2088
步骤1:编写方法接收日期数据

在UserController类中添加方法,把**参数设置为日期类型**

@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date)System.out.println("参数传递 date ==> "+date);return "{'module':'data param'}";
}
步骤2:启动Tomcat服务器
步骤3:使用PostMan发送请求

使用PostMan发送**GET请求,并设置date参数**

http://localhost/dataParam?date=2088/08/08

image-20240110194127851

步骤4:查看控制台

image-20240110194328766

步骤5:更换日期格式

我们在方法中多添加一个日期参数(甚至可以携带时间),相应的接受参数要设置相应的接受格式

@RequestMapping("/dataParam")
@ResponseBody
public String dataParam(Date date,@DateTimeFormat(pattern="yyyy-MM-dd") Date date1,@DateTimeFormat(pattern="yyyy/MM/dd HH:mm:ss") Date date2)System.out.println("参数传递 date ==> "+date);System.out.println("参数传递 date1(yyyy-MM-dd) ==> "+date1);System.out.println("参数传递 date2(yyyy/MM/dd HH:mm:ss) ==> "+date2);return "{'module':'data param'}";
}

使用PostMan发送请求,携带多个不同的日期格式,格式的设置可以利用@DateTimeFormat

http://localhost:8080/springmvc_04_request_param/dataParam?date=2018/08/08&date1=2019-09-09&date3=2020/02/20 20:20:20

image-20240110195722721

image-20240110195743627

知识点1:@DateTimeFormat

名称@DateTimeFormat
类型形参注解
位置SpringMVC控制器方法形参前面
作用设定日期时间型数据格式
相关属性pattern:指定日期时间格式字符串

内部实现原理

讲解内部原理之前,我们需要先思考个问题:

  • 前端传递日期,后端使用日期Date接收
  • 前端传递JSON数据,后端使用对象接收
  • 前端传递字符串,后端使用String接收
  • 后台需要的数据类型有很多种
  • 在数据的传递过程中存在很多类型的转换

问:谁来做这个类型转换?

答:SpringMVC

问:SpringMVC是如何实现类型转换的?

答:SpringMVC中提供了很多类型转换接口和实现类

在框架中,有一些类型转换接口,其中有:

  • Converter接口

    /**
    *	S: the source type
    *	T: the target type
    */
    public interface Converter<S, T> {@Nullable//该方法就是将从页面上接收的数据(S)转换成我们想要的数据类型(T)返回T convert(S source);
    }
    

    注意:Converter所属的包为org.springframework.core.convert.converter

    Converter接口的实现类

    Ctrl+D 搜索类

    Ctrl+H 显示类结构图

    image-20240110200558142

    框架中有提供很多对应Converter接口的实现类,用来实现不同数据类型之间的转换,如:

    请求参数年龄数据(String→Integer)

    日期格式转换(String → Date)

  • HttpMessageConverter接口

    该接口是实现对象与JSON之间的转换工作

注意:SpringMVC的配置类把@EnableWebMvc当做标配配置上去,不要省略

3.2.6 响应

4 Rest风格

4.1 REST简介

REST(Representational State Transfer),表现形式状态转换,它是一种软件架构风格

当我们想表示一个网络资源的时候,可以使用两种方式:

  • 传统风格资源描述形式
    • http://localhost/user/getById?id=1 查询id为1的用户信息
    • http://localhost/user/saveUser 保存用户信息
  • REST风格描述形式
    • http://localhost/user/1
    • http://localhost/user
  • 特点:
    • 传统:不仅麻烦,也不安全,因为会程序的人读取了你的请求url地址,就大概知道该url实现的是一个什么样的操作
    • REST:请求地址变的简单了,并且光看请求URL并不是很能猜出来该URL的具体功能

REST的优点:

  • 隐藏资源的访问行为,无法通过地址得知对资源是何种操作
  • 书写简化

如何区分:

一个相同的url地址即可以是新增也可以是修改或者查询,那么到底我们该如何区分该请求到底是什么操作呢?

按照REST风格访问资源时使用行为动作区分对资源进行了何种操作

按照不同的请求方式代表不同的操作类型

  • 发送GET请求是用来做查询

  • 发送POST请求是用来做新增

  • 发送PUT请求是用来做修改

  • 发送DELETE请求是用来做删除

  • http://localhost/users 查询全部用户信息 GET(查询)

  • http://localhost/users/1 查询指定用户信息 GET(查询)

  • http://localhost/users 添加用户信息 POST(新增/保存)

  • http://localhost/users 修改用户信息 PUT(修改/更新)

  • http://localhost/users/1 删除用户信息 DELETE(删除)

请求的方式比较多,但是比较常用的就4种,分别是GET,POST,PUT,DELETE

注意:

  • 上述行为是约定方式,约定不是规范,可以打破,所以称REST风格,而不是REST规范

    • REST中规定GET/POST/PUT/DELETE针对的是查询/新增/修改/删除,但是我们如果非要用GET请求做删除,这点在程序上运行是可以实现的,但是如果绝大多数人都遵循这种风格。
    • REST提供了对应的架构方式,按照这种架构设计项目可以降低开发的复杂性,提高系统的可伸缩性
  • 描述模块的名称通常使用复数,也就是加s的格式描述,表示此类资源,而非单个资源,例如:users、books、accounts…

  • 根据REST风格对资源进行访问称为RESTful

4.2 RESTful入门

4.2.1 行为动作的确定

在controller中,设置当前请求方法为GET/POST/PUT/DELETE,表示REST风格中的某种操作

例如删除:

@Controller
public class UserController {//设置当前请求方法为DELETE,表示REST风格中的删除操作@RequestMapping(value = "/users",method = RequestMethod.DELETE)@ResponseBodypublic String delete(Integer id) {System.out.println("user delete..." + id);return "{'module':'user delete'}";}
}

如果想访问这个方法但是发送的不是DELETE请求,会报错

4.2.2 携带参数
  • 前端发送请求的时候直接添加要传递的参数
  • 修改@RequestMapping的value属性,并在方法的形参前添加@PathVariable注解,确保路径匹配,并且能够接收参数

例:删除用户,传递单个参数

http://localhost/users/1

@Controller
public class UserController {//设置当前请求方法为DELETE,表示REST风格中的删除操作@RequestMapping(value = "/users/{id}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id) {System.out.println("user delete..." + id);return "{'module':'user delete'}";}
}

参数匹配规则:

image-20240112123350695

例:删除用户,传递多个参数

http://localhost/users/1/tom

@Controller
public class UserController {//设置当前请求方法为DELETE,表示REST风格中的删除操作//@PathVariable注解用于设置路径变量(路径参数),要求路径上设置对应的占位符,并且占位符名称与方法形参名称相同@RequestMapping(value = "/users/{id}/{username}",method = RequestMethod.DELETE)@ResponseBodypublic String delete(@PathVariable Integer id,@PathVariable String username){System.out.println("user delete..." + id+" "+username);return "{'module':'user delete'}";}
}

image-20240112124652636

image-20240112124749218

或者

@Controller
public class UserController {//设置当前请求方法为PUT,表示REST风格中的修改操作@RequestMapping(value = "/users",method = RequestMethod.PUT)@ResponseBodypublic String update(@RequestBody User user) {System.out.println("user update..." + user);return "{'module':'user update'}";}
}

image-20240112124235903

image-20240112124253868

例:查询用户,不传入参数

@Controller
public class UserController {//设置当前请求方法为GET,表示REST风格中的查询操作@RequestMapping(value = "/users" ,method = RequestMethod.GET)@ResponseBodypublic String getAll() {System.out.println("user getAll...");return "{'module':'user getAll'}";}
}

image-20240112124935579

image-20240112124956040

4.2.3 小结

RESTful入门案例,我们需要学习的内容如下:

(1)设定Http请求动作(动词)

@RequestMapping(value="",method = RequestMethod.POST|GET|PUT|DELETE)

(2)设定请求参数(路径变量)

@RequestMapping(value="/users/{id}",method = RequestMethod.DELETE)
@ReponseBody
public String delete(@PathVariable Integer id){}

知识点1:@PathVariable

名称@PathVariable
类型形参注解
位置SpringMVC控制器方法形参定义前面
作用绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
4.2.4 接受参数的注解

关于接收参数,我们学过三个注解@RequestBody@RequestParam@PathVariable,这三个注解之间的区别和应用分别是什么?

  • 区别
    • @RequestParam用于接收url地址传参或表单传参
    • @RequestBody用于接收json数据
    • @PathVariable用于接收路径参数,使用{参数名称}描述路径参数
  • 应用
    • 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数
      为GET,表示REST风格中的查询操作
      @RequestMapping(value = “/users” ,method = RequestMethod.GET)
      @ResponseBody
      public String getAll() {
      System.out.println(“user getAll…”);
      return “{‘module’:‘user getAll’}”;
      }
      }

[外链图片转存中...(img-hGW5qLbj-1705223006403)][外链图片转存中...(img-SWln2QCw-1705223006403)]#### 4.2.3 小结RESTful入门案例,我们需要学习的内容如下:(1)设定Http请求动作(动词)```java
@RequestMapping(value="",method = RequestMethod.POST|GET|PUT|DELETE)

(2)设定请求参数(路径变量)

@RequestMapping(value="/users/{id}",method = RequestMethod.DELETE)
@ReponseBody
public String delete(@PathVariable Integer id){}

知识点1:@PathVariable

名称@PathVariable
类型形参注解
位置SpringMVC控制器方法形参定义前面
作用绑定路径参数与处理器方法形参间的关系,要求路径参数名与形参名一一对应
4.2.4 接受参数的注解

关于接收参数,我们学过三个注解@RequestBody@RequestParam@PathVariable,这三个注解之间的区别和应用分别是什么?

  • 区别
    • @RequestParam用于接收url地址传参或表单传参
    • @RequestBody用于接收json数据
    • @PathVariable用于接收路径参数,使用{参数名称}描述路径参数
  • 应用
    • 后期开发中,发送请求参数超过1个时,以json格式为主,@RequestBody应用较广
    • 如果发送非json格式数据,选用@RequestParam接收请求参数
    • 采用RESTful进行开发,当参数数量较少时,例如1个,可以采用@PathVariable接收请求路径变量,通常用于传递id值

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/622775.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决“win11无法识别U盘“问题

在15.6寸笔记本上插上U盘&#xff0c;有时候出现U盘无法识别的现象&#xff0c;出现这种问题的原因有许多&#xff0c;比如U盘的格式不被当前电脑支持、电脑的USB接口电压过低、没有安装U盘驱动等等。     若是U盘格式不支持&#xff0c;则把U盘改成电脑能够识别的格式&#…

字符串处理(将字符串中符合十六进制数据格式的数字和字符按照其对应的十进制数值进行累加) C语言xdoj704

题目描述&#xff1a; 输入由数字和字符构成的字符串&#xff08;不包含空格&#xff09;&#xff0c;将字符串中符合十六进制数据格式的数字和字符按照其对应的十进制数值进行累加&#xff0c;并输出累加结果&#xff0c;如果字符串中不含有任何满足十六进制格式的字符&#x…

CES 2024丨引领变革,美格智能为智能终端带来生成式AI能力

作为电子行业的“风向标”&#xff0c;CES 2024&#xff08;国际消费电子展&#xff09;于1月9日至12日在美国拉斯维加斯举办。本届展会可谓是AI的盛宴&#xff0c;芯片、AI PC、智能家居、汽车科技、消费电子等领域与AI相关的前沿成果接连发布&#xff0c;引领人工智能领域的科…

6.2 声音编辑工具GoldWave5简介(8)

2&#xff0e;降噪 如果声卡的质量不太好&#xff0c;在录音的过程中免不了会掺杂一些杂音&#xff0c;比如&#xff1a;电流声、爆破声等&#xff0c;此时就需要进行降噪处理。 (1) 选择【效果】|【波波器】|【噪声减小】命令&#xff0c;打开“降噪”对话框。如图6-2-14所示…

Shell编程自动化之Shell数学运算与条件测试

一、Shell数学运算 1.Shell常见的算术运算符号 序号算术运算符号意义1、-、*、/、%加、减、乘、除、取余2**幂运算3、–自增或自减4&&、||、&#xff01;与、或、非5、!相等、不相等&#xff0c;也可写成6、、-、*、/、%赋值运算符&#xff0c;a1相等于aa1 2.Shell常…

C语言之字符串和指针

目录 用数组实现的字符串和用指针实现的字符串 █用数组实现的字符串str █用指针实现的字符串ptr 注意 用数组和指针实现字符串的不同点 字符串数组 用数组实现的字符串的数组——二维数组 用指针实现的字符串数组——指针数组 注意 字符串和指针有着紧密的联系&#…

TikTok系列算法定位还原x-ss-stub

TikTok的x系列的算法比较有名,很多粉丝也问过,之前没有深入研究,本人工作量也比较大。 我们上次说到TikTok的x-ss-stub的算法就是ccmd5标准库算的,今天要讲细致点,表面这个结论本不是直接将数据md5那么来的,是经过一系列分析来的 上图是上次截图的,这次我们分析整个定位…

node(express.js创建项目)+连接mysql数据库

1.node npm的安装 2.express的安装 全局安装:npm install express -gnpm install -g express-generator// ps: 4.0版本把generator分离出来了&#xff0c;需要单独安装3.创建express项目 express 项目名称 cd 项目名称 npm install npm start4.项目中安装数据库 npm install…

C语言督学营(高级阶段)

文章目录 高级阶段19.C语言语法进阶1.条件运算符、逗号运算符(1)条件运算符 / 三目运算符   ? :(2)逗号运算符   , 2.自增自减运算符3.位运算符&#xff1a;按位或、按位异或、按位取反(1)逻辑与、按位与、左移、右移(2)有符号数右移 vs 无符号数右移(3)按位与、按位或、按位…

Docker学习与应用(五)-DockerFile

1、DockerFile 1&#xff09;DockerFile介绍 dockerfile是用来构建docker镜像的文件&#xff01;命令参数脚本&#xff01; 构建步骤&#xff1a; 1. 编写一个dockerfile文件 2. docker build 构建称为一个镜像 3. docker run运行镜像 4. docker push发布镜像&#xff08;D…

LC 83. 删除排序链表中的重复元素

83. 删除排序链表中的重复元素 难度 &#xff1a; 简单 题目&#xff1a; 给定一个已排序的链表的头 head &#xff0c; 删除所有重复的元素&#xff0c;使每个元素只出现一次 。返回 已排序的链表 。 提示&#xff1a; 链表中节点数目在范围 [0, 300] 内-100 < Node.va…

蓝桥杯准备

书籍获取&#xff1a;Z-Library – 世界上最大的电子图书馆。自由访问知识和文化。 (zlibrary-east.se) 书评&#xff1a;(豆瓣) (douban.com) 一、观千曲而后晓声 别人常说蓝桥杯拿奖很简单&#xff0c;但是拿奖是一回事&#xff0c;拿什么奖又是一回事。况且&#xff0c;如果…

Docker教程

docker 安装 官方文档 wget -qO- https://get.docker.com/ | sh sudo usermod -aG docker your-user sudo usermod -aG docker ${USER} newgrp docker # 更新docker用户组 cat /etc/group | grep docker docker --version 使用非root用户管理 帮助启动类 命令 system…

寄快递有没有什么省钱的小妙招? 怎样寄快递才能省钱呢?

快递物流行业的快速崛起刺激了人们的消费欲望&#xff0c;其中典型的是每每到重大节日尤其是双十一或者双十二&#xff0c;消费市场异常火爆&#xff0c;这也使得快递行业加班加点的干也不追不上人们下单的速度。如今&#xff0c;互联网时代崛起&#xff0c;网购成为了大家最寻…

机器学习_捕捉函数的变化趋势(凸函数)

文章目录 连续性是求导的前提条件通过求导发现 y 如何随 x 而变凸函数有一个全局最低点 机器学习所关心的问题之一捕捉函数的变化趋势&#xff0c;也就是标签&#xff08;y&#xff09;是如何随着特征字段&#xff08;x&#xff09;而变化的&#xff0c;这个变化趋势是通过求导…

代码随想录day30 回溯算法最终章

51. N皇后 题目 n 皇后问题 研究的是如何将 n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 给你一个整数 n &#xff0c;返回所有不同的 n 皇后问题 的解决方案。 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案&#xff0c;该方案中 Q 和…

想做好项目,网工必看!

上午好&#xff0c;我是老杨。 做项目&#xff0c;贯穿一个网络工程师职业生涯的始终。不管是大项目还是小项目&#xff0c;做久了项目&#xff0c;都会形成一种自己的方法论。 项目要划分&#xff0c;无非就是新网组建&#xff0c;旧网优化&#xff0c;以及网络排障三大类。…

ISO11898-闭环高速CAN网络 (125K~1Mbps)

ISO11898 标准的物理框图如下图 可理解为一个高速闭环 CAN 总线网络&#xff1b;CAN 闭环总线网络允许总线最大长度为 40m;最高速度为 1Mbps;可以看到总线的两端各有一个 120Ω 的电阻&#xff0c;此电阻作为阻抗匹配功能&#xff0c;以减少回波反射;节点就是不同的设备&#…

Pytorch基础知识点复习

文章目录 并行计算单卡训练多卡训练单机多卡DP多机多卡DDPDP 与 DDP 的优缺点 PyTorch的主要组成模块Pytorch的主要组成模块包括那些呢&#xff1f;Dataset和DataLoader的作用是什么&#xff0c;我们如何构建自己的Dataset和DataLoader&#xff1f;神经网络的一般构造方法&…

k8s的策略

集群调度&#xff1a; Scheduler的调度算法&#xff1a; 预算策略 过滤出合适的节点 优先策略 选择部署的节点 NodeName&#xff1a;硬策略&#xff0c;不走调度策略&#xff0c;node1 nodeSelector&#xff1a;根据节点的标签选择&#xff0c;会走一个调度算法 只要是…