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)完成测试
- 注意,参数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…