Spring boot之WEB 开发-静态资源访问--自定义转换器--处理JSON--内容协商

news2024/11/16 18:04:59

Spring boot之WEB 开发-静态资源访问

官方文档

在线文档:
https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.develo\ping-web-applications

基本介绍

1. 只要静态资源放在类路径下: /static 、/public 、/resources 、/META-INF/resources可以被直接访问- 对应文件WebProperties.java

private static final String[] CLASSPATH_RESOURCE_LOCATIONS =
{ "classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/" };

2. 常见静态资源:JS、CSS 、图片(.jpg .png .gif .bmp .svg)、字体文件(Fonts)等

3. 访问方式:默认: 项目根路径/ + 静态资源名比如http://localhost:8080/hi.jpg . - 设置WebMvcProperties.java

private String staticPathPattern = “/**”;

快速入门

1. 创建SpringBoot 项目springbootweb , 使用灵活配置方式来创建项目

2. 创建相关静态资源目录, 并放入测试图片, 没有目录,自己创建即可, 完成测试

静态资源访问注意事项和细节

1. 静态资源访问原理:静态映射是/**, 也就是对所有请求拦截,请求进来,先看Controller
能不能处理,不能处理的请求交给静态资源处理器,如果静态资源找不到则响应404 页面

2. 改变静态资源访问前缀,比如我们希望http://localhost:8080/hellores/* 去请求静态资源,

应用场景:静态资源访问前缀和控制器请求路径冲突

1) 创建application.yml

spring:
mvc:
static-path-pattern: /hellores/**

2) 重启应用,完成测试, 浏览器输入: http://localhost:8080/hellores/1.jpg

3.改变默认的静态资源路径,比如希望在类路径下增加ninhaoimg 目录作为静态资源路径,
并完成测试.

spring:
  mvc:
    static-path-pattern: /hellores/** #修改静态资源访问的路径/前缀

  web:
    resources:
      #修改/指定 静态资源的访问路径/位置
      #
      static-locations: ["classpath:/ninhaoimg/","classpath:/META-INF/resources/",
                         "classpath:/resources/", "classpath:/static/", "classpath:/public/"]      #String[] staticLocations

3) 测试, 浏览器输入http://localhost:8080/hellores/pen.jpg

[提示: 没错就是这样访问pen.jpg, 不是/ninhaoimg /pen.jpg 形式, 另外因为pen.jpg 还是拷贝来的, 一定要保证工作目录target 有pen.jpg ,如果没有, 请rebulid 下项目, 再重启项目]

4) 如果你配置static-locations, 原来的访问路径就被覆盖,如果需要保留,你再指定一下即可


spring:
  mvc:
    static-path-pattern: /hellores/** #修改静态资源访问的路径/前缀
  web:
    resources:
    #修改/指定静态资源的访问路径/位置

    static-locations: ["classpath:/ninhaoimg /","classpath:/META-INF/resources/",
                   "classpath:/resources/", "classpath:/static/", "classpath:/public/"]
#String[] staticLocations

这之所以不需要http://localhost:8080/hellores/ninhaoimg/12.jpg

是因为修改的默认访问路劲 容器在其他目录找不到的时候就会默认去找ninhaoimg目录下的12.jap


自定义转换器

基本介绍

1. SpringBoot 在响应客户端请求时,将提交的数据封装成对象时,使用了内置的转换器

2. SpringBoot 也支持自定义转换器, 这个内置转换器在debug 的时候, 可以看到, 后面给演示, 提供了124 个内置转换器. 看下源码GenericConverter-ConvertiblePair

自定义转换器-应用实例

需求说明: 演示自定义转换器使用

代码实现

修改save.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>添加妖怪</title>
</head>
<body>
<h1>添加妖怪-坐骑[测试封装POJO;]</h1>
<form action="/savemonster" method="post">
    编号: <input name="id" value="100"><br/>
    姓名: <input name="name" value="牛魔王"/> <br/>
    年龄: <input name="age" value="500"/> <br/>
    婚否: <input name="isMarried" value="true"/> <br/>
    生日: <input name="birth" value="2000/11/11"/> <br/>
    <!-- 使用自定义转换器关联car, 字符串整体提交, 使用,号间隔  -->
    坐骑:<input name="car" value="避水金晶兽,666.6"><br/>
    <input type="submit" value="保存"/>
</form>
</body>
</html>

创建WebConfig.java,增加自定义转换器


/**
 * @Configuration(proxyBeanMethods = false)
 * 1. 表示 WebConfig 是一个配置类
 * 2. proxyBeanMethods = false 使用Lite模式
 */
@Configuration(proxyBeanMethods = false)
public class WebConfig  {



    //注入bean WebMvcConfigurer
    @Bean
    public WebMvcConfigurer webMvcConfigurer() {

        return new WebMvcConfigurer() {
            @Override
            public void addFormatters(FormatterRegistry registry) {
                /**
                 * 解读
                 * 1. 在addFormatters 方法中,增加一个自定义的转换器
                 * 2. 增加自定义转换器 String -> Car
                 * 3. 增加的自定义转换器会注册到 converters 容器中
                 * 4. converters 底层结构是 ConcurrentHashMap 内置有124转换器
                 * 5. 一会会使用debug来看到这些转换器
                 */

                registry.addConverter(new Converter<String, Car>() {
                    @Override
                    public Car convert(String source) {//source就是 传入的字符串 避水金晶兽,666.6
                        //这里就加入你的自定义的转换业务代码
                        if (!ObjectUtils.isEmpty(source)) {

                            Car car = new Car();
                            String[] split = source.split(",");
                            car.setName(split[0]);
                            car.setPrice(Double.parseDouble(split[1]));
                            return car;
                        }
                        return null;
                    }
                });



                //转种写法来注册自定义转换器-方便理解

                1.先创建自定义的转换器
                //Converter<String,Car> hspConverter = new Converter<String, Car>() {
                //    @Override
                //    public Car convert(String source) {//source就是 传入的字符串 避水金晶兽,666.6
                //        //这里就加入你的自定义的转换业务代码
                //        if (!ObjectUtils.isEmpty(source)) {
                //
                //            Car car = new Car();
                //            String[] split = source.split(",");
                //            car.setName(split[0]);
                //            car.setPrice(Double.parseDouble(split[1]));
                //            return car;
                //        }
                //        return null;
                //    }
                //};
                //
                还可以增加更多的转换器
                //2个自定义转换器
                //Converter<String,Monster> hspConverter2 = new Converter<String, Monster>() {
                //    @Override
                //    public Monster convert(String source) {//source就是 传入的字符串 避水金晶兽,666.6
                //        return null;
                //    }
                //};
                //3个自定义转换器
                //Converter<String,Car> hspConverter3 = new Converter<String, Car>() {
                //    @Override
                //    public Car convert(String source) {//source就是 传入的字符串 避水金晶兽,666.6
                //        System.out.println("source-" + source);
                //        return null;
                //    }
                //};
                //
                2添加转换器到converters key-[源类型->目标类型]
                //registry.addConverter(hspConverter);
                //registry.addConverter(hspConverter2);
                //registry.addConverter(hspConverter3);
            }
        };
    }
}

3. 完成测试, 浏览器http://localhost:8080/save.html

4. Debug 可以看到我们新增的Converter

------注意看, 多了一个我们自定义的转换器String->com.wyxedu.web.bean.Car


处理JSON

需求说明:

演示返回JSON 格式数据

应用实例

1. SpringBoot 支持返回JSON 格式数据,在启用WEB 开发场景时,已经引入了相关依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

创建ResponseController.java

@Controller
public class ResponseController {

    //返回Monster数据-要求以json格式返回

    @GetMapping("/get/monster")
    @ResponseBody
    public Monster getMonster() {
        //说明
        //开发中, monster对象是从DB获取-这里模拟一个monster对象
        Monster monster = new Monster();
        monster.setId(100);
        monster.setName("奔波霸");
        monster.setAge(200);
        monster.setIsMarried(false);
        monster.setBirth(new Date());
        Car car = new Car();
        car.setName("奔驰");
        car.setPrice(222.2);
        monster.setCar(car);
        return monster;
    }
}

Postman 完成测试

Debug 一下monster 对象以Json 格式返回


内容协商

基本介绍

1. 根据客户端接收能力不同,SpringBoot 返回不同媒体类型的数据

2. 比如: 客户端Http 请求Accept: application/xml 则返回xml 数据,客户端Http 请求Accept: application/json 则返回json 数据

比如下面的示意图

内容协商-应用实例

● 需求说明: 使用Postman 发送Http 请求,根据请求头不同,返回对应的json 数据或者xml
数据, 如图

在pom.xml 增加处理xml 的依赖

        <dependency>
            <groupId>com.fasterxml.jackson.dataformat</groupId>
            <artifactId>jackson-dataformat-xml</artifactId>
        </dependency>

2. 使用Postman 发出不同的Http Header , 可以看到返回对应的数据格式(说明: 测试前请重启一把项目)

3. 切换Postman 不同的Accept 类型, 来Debug 源码, 看看对应的JsonGenerator 类型

4. 使用浏览器请求,为什么会返回xml 数据分析,而不是json?

注意事项和使用细节

1. Postman 可以通过修改Accept 的值,来返回不同的数据格式

2. 对于浏览器,我们无法修改其Accept 的值,怎么办? 解决方案: 开启支持基于请求参数的内容协商功能

1) 修改application.yml, 开启基于请求参数的内容协商功能

spring:
  mvc:
    #static-path-pattern: /hellores/** #修改静态资源访问的路径/前缀
    hiddenmethod:
      filter:
        enabled: true #启用了HiddenHttpMethodFilter,开启页面表单的Rest功能
    view:       #配置视图解析器
      suffix: .html
      prefix: /        #这里是需要注意 prefix需要和当前的static-path-pattern一致
    contentnegotiation:
      favor-parameter: true #开启基于请求参数的内容协商功能
  web:
    resources:
      #修改/指定 静态资源的访问路径/位置
      #
      static-locations: ["classpath:/ninhaoimg/","classpath:/META-INF/resources/",
                         "classpath:/resources/", "classpath:/static/", "classpath:/public/"]      #String[] staticLocations

2)完成测试

  1. 注意,参数format 是规定好的, 在开启请求参数的内容协商功能后,SpringBoot 底层ParameterContentNegotiationStrategy 会通过format 来接收参数,然后返回对应的媒体类型/
    数据格式, 当然format=xx 这个xx 媒体类型/数据格式是SpringBoot 可以处理的才行,不能乱写.

如果需要自定义format 在配置文件加一个

parameter-name: wwwformat #指定一个内容协商的参数名 就好了然后要指定上面格式就不是format=json 而是 wwwformat=json

spring:
  mvc:
    #static-path-pattern: /hellores/** #修改静态资源访问的路径/前缀
    hiddenmethod:
      filter:
        enabled: true #启用了HiddenHttpMethodFilter,开启页面表单的Rest功能
    view:       #配置视图解析器
      suffix: .html
      prefix: /        #这里是需要注意 prefix需要和当前的static-path-pattern一致
    contentnegotiation:
      favor-parameter: true #开启基于请求参数的内容协商功能
      parameter-name: wwwformat #指定一个内容协商的参数名
  web:
    resources:
      #修改/指定 静态资源的访问路径/位置
      #
      static-locations: ["classpath:/ninhaoimg/","classpath:/META-INF/resources/",
                         "classpath:/resources/", "classpath:/static/", "classpath:/public/"]      #String[] staticLocations

.l…

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

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

相关文章

2023-06-11:redis中,如何在100个亿URL中快速判断某URL是否存在?

2023-06-11&#xff1a;redis中&#xff0c;如何在100个亿URL中快速判断某URL是否存在&#xff1f; 答案2023-06-11&#xff1a; 传统数据结构的不足 当然有人会想&#xff0c;我直接将网页URL存入数据库进行查找不就好了&#xff0c;或者建立一个哈希表进行查找不就OK了。 …

【Java】数组是引用类型

【Java】数组是引用类型 Java虚拟机运行时的数据区基本类型变量与引用类型变量的区别 Java虚拟机运行时的数据区 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址。 虚拟机栈(JVM Stack): 与方法调用相关的一些信息&#xff0c;每个方法在执行时&a…

【算法系列 | 5】深入解析排序算法之——快速排序

序言 你只管努力&#xff0c;其他交给时间&#xff0c;时间会证明一切。 文章标记颜色说明&#xff1a; 黄色&#xff1a;重要标题红色&#xff1a;用来标记结论绿色&#xff1a;用来标记一级论点蓝色&#xff1a;用来标记二级论点 决定开一个算法专栏&#xff0c;希望能帮助大…

【日志解析】【频率分析】ULP:基于正则表达式和本地频率分析进行日志模板提取

An Effective Approach for Parsing Large Log Files 文章目录 An Effective Approach for Parsing Large Log Files1 论文出处2 背景2.1 背景介绍2.2 针对问题2.3 创新点 3 主要设计思路3.1 预处理3.2 日志事件分组3.3 通过频率分析生成日志模板 4 实验设计4.1 准确性4.2 效率…

物联网Lora模块从入门到精通(八)Lora无线通信

一、前言 在某些环境下&#xff0c;无法通过有线传输数据&#xff0c;这时候我们需要使用Lora无线通信传输数据&#xff0c;Lora无线数据传输具有低功耗、距离长的特点&#xff0c;常用于工厂内等&#xff0c;需要Lora基站。 我曾做过距离测试&#xff1a;Lora模块距离测试-物联…

【Pytest实战】pytest 基本概念及使用大全

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。&#x1f60a; 座右铭&#xff1a;不想…

Spring6-02

JdbcTemplate JdbcTemplate是Spring提供的一个JDBC模板&#xff0c;是对JDBC的封装&#xff0c;简化了JDBC代码。当然也可以不用JdbcTemplate&#xff0c;可以让Spring集成其他的ORM框架&#xff0c;例如MyBatis、Hibernate等。接下来使用JdbcTemplate完成增删改查。 环境准备…

重写并自定义console.log()输出样式

0. 背景 笔者在开发的实践过程中对于控制台内容的输出情况有一些特殊的需求&#xff0c;然而&#xff0c;普通的console.log()函数不能提供很好的支持&#xff0c;因此需要探索一些自定义的实现方式&#xff0c;以便满足开发需求&#xff0c;一些开发需求如下&#xff1a; 输…

编译详细过程与交叉编译

GCC的编译过程&#xff1a; GCC编译分为四步&#xff0c;预处理、编译、汇编、链接。具体功能如上图所示&#xff0c;我们在稍微解释一下&#xff1a; 1.预处理&#xff1a; 实现过程&#xff1a;gcc -E xxx.c -o xxx.i 目的&#xff1a;我们的c程序中除了main函数以外&…

如何在Linux中使用read命令读取用户输入?——read命令实战

前言 大家好&#xff0c;又见面了&#xff0c;我是沐风晓月&#xff0c;本文是专栏【linux基本功-基础命令实战】的第64篇文章。 专栏地址&#xff1a;[linux基本功-基础命令专栏] &#xff0c; 此专栏是沐风晓月对Linux常用命令的汇总&#xff0c;希望对你有用。 今天我们一…

实现jvm内存溢出

那么我们如何来构建一个堆内存溢出呢&#xff1f;其实很简单&#xff0c;我们只要定义一个List对象&#xff0c;然后通过一个循环不停的往List里面塞对象。因为只要Controller不被回收&#xff0c;那么它里面的成员变量也是不会被回收的。这样就会导致List里面的对象越来越多&a…

Play wright自动化测试工具该如何更加完美地使用

目录 1.1 拦截网络请求 1.2 pytest 管理用例 1.3 PO模型 1.4 API 和 UI 自动化测试融合 1.5 数据驱动 1.6 动态挑选用例执行 1.6 Allure测试报告 1.7 持续集成 1.1 拦截网络请求 网络拦截&#xff1a; 无响应 pass 中止 route.abort("aborted") 放行 route…

Hazel游戏引擎(013)Layers游戏的层级

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言增加Layer后的主要类图项目相关代码项目流程效果 LayerStack类的错误 前言 此节目的 为完成008事件系统设计的第四步&#xff0c;将事件从Application传递分发给Layer层。 使引擎事件系统模块完整 Layer的理解 …

在VSCode下利用PlateFormIO开发Arduino的MicroROS遇到的一些问题

简介 我是按照鱼香ROS的教程【3.搭建PlateFormIO开发环境】进行的&#xff0c;但是在进行的过程中&#xff0c;遇到了一些问题&#xff0c;这里记录下来&#xff0c;供有同样问题的同学进行参考。其实只要你使用的板子的MCU是ESP32&#xff0c;都可以按照他这个教程进行操作。…

k8s实践之mysql集群搭建(十五)

先下载 k8s实践之mysql集群搭建资料 主从模式简介&#xff1a; 当master主服务器上的数据发生改变时&#xff0c;则将其改变写入二进制&#xff08;binlog&#xff09;事件日志文件中&#xff1b; slave从服务器会在一定时间间隔内对master主服务器上的二进制日志进行探测&am…

掌握Vue生命周期,让你的前端开发效率翻倍!

1 Vue实例 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Vue实例</title><script src../vue.js></script> </head> <body><div id"root"><!-- v…

位图以及布隆过滤器

本文主要讲解哈希思想的实际应用&#xff0c;位图和布隆过滤器。 位图 讲解位图之前我们先来解答这样一道腾讯的面试题 给40亿个不重复的无符号整数&#xff0c;没排过序。给一个无符号整数&#xff0c;如何快速判断一个数是否在这40亿个数中。【腾讯】 很多人立马就想到了用…

Seata TCC 模式理论学习、生产级使用示例搭建及注意事项 | Spring Cloud55

一、前言 通过以下系列章节&#xff1a; docker-compose 实现Seata Server高可用部署 | Spring Cloud 51 Seata AT 模式理论学习、事务隔离及部分源码解析 | Spring Cloud 52 Spring Boot集成Seata利用AT模式分布式事务示例 | Spring Cloud 53 Seata XA 模式理论学习、使用…

STL——set容器、map容器

初识STL **set容器/multiset容器****set容器——构造和赋值****set容器——大小和交换****set容器——插入和删除****set容器的查找和统计****set和multiset的区别****set的相关操作源码&#xff1a;****multiset的相关操作源码** **pair使用——pair队组的创建****set容器——…

FreeRTOS-定时器详解

✅作者简介&#xff1a;嵌入式入坑者&#xff0c;与大家一起加油&#xff0c;希望文章能够帮助各位&#xff01;&#xff01;&#xff01;&#xff01; &#x1f4c3;个人主页&#xff1a;rivencode的个人主页 &#x1f525;系列专栏&#xff1a;玩转FreeRTOS &#x1f4ac;保持…