SpringBoot 静态资源访问
1. 默认的静态资源地址
By default, Spring Boot serves static content from a directory called (or or or ) in the classpath. It uses the from Spring WebFlux so that you can modify that behavior by adding your own and overriding the method.
/static
或者/public
或者/resources
或者/METAINF/resources
默认情况下,Spring Boot 从类路径中名为 (/static或 /public 或 /resources 或 /META-INF/resources)的目录或 ServletContext 的根目录中提供静态内容
1.1 默认地址测试
- html资源,放置在META-INF/resources目录下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>默认静态地址测试</title>
<link rel="stylesheet" href="test.css">
<script src="test.js"></script>
</head>
<body>
<div id="testDiv" onclick="test()">
静态资源地址测试 , 点击添加图片
</div>
</body>
</html>
- css资源,放在public目录下
div{
color:red;
}
- js资源,放在resources目录下
function test() {
let e = document.getElementById("testDiv")
let img = document.createElement("img")
img.src="1.png"
e.appendChild(img)
}
- img资源,放在static目录下
1.2 测试结果
直接访问test.html:
点击div后:
==可以看到,只要我们将静态资源放置在以上四个目录下的任意一个中,就可以直接访问得到。
2. 默认地址原理
- SpringBoot 在启动时会默认加载以 AutoConfiguration 结尾的自动配置类,由于 SpringBoot 封装了 SpringMVC 的功能,因此与 Web 开发相关的自动配置类 org.springframework.boot.autoconfigure.web.servlet.WebMvcAutoConfiguration 也会被自动加载。
@AutoConfiguration(after = { DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,
ValidationAutoConfiguration.class })
@ConditionalOnWebApplication(type = Type.SERVLET)
@ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class })
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE + 10)
@ImportRuntimeHints(WebResourcesRuntimeHints.class)
public class WebMvcAutoConfiguration {
// ......
// Defined as a nested config to ensure WebMvcConfigurer is not read when not
// on the classpath
@Configuration(proxyBeanMethods = false)
@Import(EnableWebMvcConfiguration.class)
@EnableConfigurationProperties({ WebMvcProperties.class, WebProperties.class })
@Order(0)
public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {
private static final Log logger = LogFactory.getLog(WebMvcConfigurer.class);
private final Resources resourceProperties;
private final WebMvcProperties mvcProperties;
//.....
}
}
- 可以看到在WebMvcAutoConfigurationAdapter中有private final Resources resourceProperties; 成员,查看Resources源码
public static class Resources {
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
/**
* Whether to enable default resource handling.
*/
// ......省略部分代码
public String[] getStaticLocations() {
return this.staticLocations;
}
public void setStaticLocations(String[] staticLocations) {
this.staticLocations = appendSlashIfNecessary(staticLocations);
this.customized = true;
}
//......省略部分代码
}
-
可以看到,默认的静态资源就定义在这个类中,并且提供有获取和修改的方法。
-
在WebMvcAutoConfiguration中有这样一段代码
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
return;
}
addResourceHandler(registry, this.mvcProperties.getWebjarsPathPattern(),
"classpath:/META-INF/resources/webjars/");
addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> {
registration.addResourceLocations(this.resourceProperties.getStaticLocations());
if (this.servletContext != null) {
ServletContextResource resource = new ServletContextResource(this.servletContext, SERVLET_LOCATION);
registration.addResourceLocations(resource);
}
});
}
- 其中所调用的getStaticLocations()方法就是Resources所提供的获取静态路径的方法
private static final String[] CLASSPATH_RESOURCE_LOCATIONS = { "classpath:/META-INF/resources/",
"classpath:/resources/", "classpath:/static/", "classpath:/public/" };
/**
* Locations of static resources. Defaults to classpath:[/META-INF/resources/,
* /resources/, /static/, /public/].
*/
private String[] staticLocations = CLASSPATH_RESOURCE_LOCATIONS;
//......省略部分代码
public String[] getStaticLocations() {
return this.staticLocations;
}
//......省略部分代码
}
- 以上就是静态资源地址配置所涉及到的主要方法
3. 自定义静态资源地址
如果我们在系统中配置了
spring.web.resources.static-locations
来自定义静态资源的访问,那么就会覆盖掉 SpringBoot 提供的默认静态资源配置。
如果希望我们的配置和系统的默认配置都有效,那么需要把系统的默认配置也带上。
spring:
web:
resources:
static-locations: [classpath:/abc/, classpath:/META-INF/resources/,classpath:/resources/, classpath:/static/, classpath:/public/]
SpringBoot 请求参数处理
1. 请求映射
1.1 RestFul 风格请求
所谓 RESTFull 风格是使用 HTTP 请求方式的动词来表示对资源的操作。有以下几种常用请求方式:
- GET:用于获取信息
- POST:用于添加信息
- PUT:用于修改信息
- DELETE:用于删除信息
<form method="get" action="/rest">
<input type="submit" value="Rest-Get">
</form>
<form method="post" action="/rest">
<input type="submit" value="Rest-Post">
</form>
<form method="post" action="/rest">
<input type="hidden" name="_method" value="put">
<input type="submit" value="Rest-Put">
</form>
<form method="post" action="/rest">
<input type="hidden" name="_method" value="delete">
<input type="submit" value="Rest-Delete">
</form>
- 在配置文件中开启对 RestFull 风格的支持,配置的参数为:spring.mvc.hiddenmethod.filter.enabled=true
- 对象put和delete请求,我们需要在它的 form 表单中定义一个参数名为
_method
,值为 put 或 delete- 对于put和delete请求,它的请求方式必须是 post
2. 参数接收
2.1 简单类型参数
- 它一般用于接收基本数据类型或字符串类型
@GetMapping("/simpleParameters")
public String simple(String parameter){
return parameter;
}
- 对于不是必须的参数,可以添加如下注解,设定默认值
@GetMapping("/simpleParameters")
public String simple(@RequestParam(required = false,defaultValue = "默认值") String parameter){
return parameter;
}
2.2 路径变量
- 要接收路径变量,需要使用 @PathVarable注解
@GetMapping("/{parameter}")
public String pathParameter(@PathVariable("parameter") String parameter){
return parameter;
}
2.3 接受请求头参数
- 需要使用 @RequestHeader 注解
@RequestHeader(“Accept-Language”) String acceptLanguage 获取具体参数
@RequestHeader Map<String, String> headers 获取整个请求头信息
@GetMapping("/headerParameters")
public Map<String,String> getHeaderParameters(@RequestHeader("Accept-Language") String acceptLanguage,Map<String,String> map){
return map;
}
2.4 获取Cookie
- 使用@CookieValue注解
@GetMapping("/getCookie")
public String getCookie(@CookieValue("cookie") String cookie){
return cookie ;
}
2.5 获取对象参数
- 创建对应的JavaBean 记录类,或者普通JavaBean
public record User(String name ,Integer age) {}
- 编写Html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对象参数</title>
</head>
<body>
<form action="/param/getObject" method="post">
<input type="text" placeholder="name" name="name"><br>
<input type="text" placeholder="age" name="age"><br>
<input type="submit" value="提交"><br>
</form>
</body>
</html>
- 编写Controller
@PostMapping("/getObject")
public User getObject(User user){
return user ;
}
2.6 Json格式数据接收
- 需要使用@RequestBody注解
@PostMapping("/json")
public User getJson(@RequestBody User user){
return user ;
}
2.7 原生数据接收方式 HttpRequest
- 注入HttpServletRequest属性
@Resource
HttpServletRequest httpServletRequest ;
@GetMapping("/native")
public String getParameterByNative(){
return httpServletRequest.getParameter("name");
}
- 或者控制方法携带HttpServletRequest
@GetMapping("/native2")
public String getParameterByNative2(HttpServletRequest httpServletRequest){
return httpServletRequest.getParameter("name");
}
3. 参数校验
-
对于表单提交数据不符合要求或为空等等我们可以在后台进行判断并抛出自定义错误。
-
除了自定义错误信息的方式,可以通过JSR-303 规范来优雅的展示数据错误信息
3.1 JSR303 常用注解
注解 | 作用 |
---|---|
@Null | 被注解的元素必须为 null |
@NotNull | 被注解的元素必须不为 null |
@AssertTrue | 被注解的元素必须为 true |
@AssertFalse | 被注解的元素必须为 false |
@Min(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 |
@Max(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 |
@DecimalMin(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 |
@DecimalMax(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 |
@Size(max, min) | 被注解的元素的大小必须在指定的范围内 |
@Digits(integer, fraction) | 被注解的元素必须是一个数字,其值必须在可接受的范围内 |
@Past | 被注释的元素必须是一个过去的日期 |
@Future | 被注释的元素必须是一个将来的日期 |
@Pattern(value) | 被注解的元素必须符合指定的正则表达式 |
被注解的元素必须是电子邮箱地下 | |
@NotEmpty | 被注解的字符串必须非空 |
Hibernate 提供的部分注解:
注解 | 作用 |
---|---|
@URL | 被注解的字符为 URL |
@Length | 被注解的字符串的大小必须在指定的范围内 |
@Range | 被注解的元素必须在合适的范围内 |
3.2 上手示例
- 引入JSR303依赖
<!--引入validation的场景启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
- 在实体类属性上使用JSR303注解
@Data
public class Student {
@Length(min = 2,max = 8,message = "name 参数错误")
private String name ;
@Range(min = 18,max = 35,message = "年龄不符合规定")
private Integer age ;
}
- 在控制器方法的参数上使用 @Validated 注解 + BindingResult 类型参数
@PostMapping("/student")
public Map<String, Object> getStudent(@Validated Student student , BindingResult bindingResult){
Map<String, Object> result = new HashMap<>();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fieldError : fieldErrors) {
result.put(fieldError.getField(), fieldError.getDefaultMessage());
}
result.put("student", student);
return result;
}