配置文件与web开发
参考博客:
https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247488811&idx=2&sn=0d054027651bef114ae6bec5a8f62359 >SpringBoot内容聚合
https://zhuanlan.zhihu.com/p/57693064 >SpringBoot配置文件详解
配置文件
当我们构建完Spring Boot项目后,会在resources目录下给我们一个默认的全局配置文件;
application.properties,这是一个空文件,因为Spring Boot在底层已经把配置都给我们自动配置好了,当在配置文件进行配置时,会修改SpringBoot自动配置的默认值。
配置文件名是固定的:application.properties,但我们可以修改为:application.yml
这两个文件本质是一样的,区别只是其中的语法略微不同。
值的写法
application.properties 配置文件比较简单,形式如下
key = value
application.yml 配置文件使用YMAL语言,YMAL不是如XML般的标记语言,更适合作为配置文件。
数字,字符串,布尔
- 直接写
name=zhangsan
- 双引号
不会转义字符串里面的特殊字符,特殊字符会作为本身想表示的意思
name: "zhangsan n lisi"
输出:
zhangsan
lisi
- 单引号
会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name: ‘zhangsan n lisi’
输出:
zhangsan n lisi
对象、Map(属性和值)(键值对)
例如配置类中的字段为
Map<String,String> maps;
在yml配置文件中,行内写法
person.maps: {key1: value1,key2: value2}
需要注意:号后的空格,或者
person:
maps:
key: value
在properties配置文件中
person.maps.key=value
数组(List、Set)
在yml配置文件中
person:
list:
- 1
- 2
- 3
行内写法
person:
list: [1,2,3]
在properties配置文件中
person.list[0]=1
person.list[1]=2
person.list[2]=3
自定义配置属性
Spring Boot提供自定义配置组件,拿前面举例的属性来写一个规范的配置文件
@Component // 或者@Configuration
@ConfigurationProperties(prefix = "person")
public class Person {
private Map<String,String> maps;
private List<String> list;
private String name;
public Map<String, String> getMaps() {
return maps;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@ConfigurationProperties 注解向Spring Boot声明该类中的所有属性和配置文件中相关的配置进行绑定。
prefix = “person”:声明配置前戳,将该前戳下的所有属性进行映射。
@Component 或者@Configuration:将该组件加入Spring Boot容器,只有这个组件是容器中的组件,配置才生效。
配置自动提示
在配置自定义属性时,如果想要获得和配置Spring Boot属性自动提示一样的功能,则需要加入下面的依赖:
<!--导入配置文件处理器,配置文件进行绑定就会有提示-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
若是依旧无法自动提示,可以尝试开启IDE的Annonation Processing
开发Web应用程序
Spring Boot 适合于 Web 应用程序开发。可以使用嵌入式Tomcat,Jetty,Undertow 或 Netty 创建独立的 HTTP 服务器。大多数 Web 应用程序都使用 spring-boot-starter-web 来快速启动和运行。还可以选择使用spring-boot-starter-webflux来构建响应式Web应用程序。
静态资源
默认情况下,Spring Boot从类路径中名为/static(/public或/resources或/META-INF/resources)
的目录中或从的根中提供静态内容ServletContext。使用ResourceHttpRequestHandler
读取文件。可以通过添加自己WebMvcConfigurer
和addResourceHandlers
方法并覆盖该方法来修改该行为。
默认情况下,资源映射到 / * * ,可以使用 spring.mvc.static-path-pattern属性对其进行调整。例如,将所有资源重新定位到以下位置 / resources / * * 可以实现:
spring.mvc.static-path-pattern=/resources/**
路径中名为/static(/public或/resources或/META-INF/resources)可以访问。
路径优先级排序:/META-INF/resources > /resources > /static > /public
欢迎页支持
url输入,会先将输入的信息定义为字符串,去controller寻找。没有找到后再去静态资源目录下寻找。
静态资源路径下index.html
- 可以配置静态资源路径
- 但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问
spring:
mvc:
static-path-pattern: /res/** 这个会导致welcome page功能失效
resources:
static-locations: [classpath:/haha/]
- controller能处理/index
自定义 Favicon.ico
介绍
这里指的favicon是指在这里插入图片描述(就是在 页面搜索栏和最上面标头显示图标)
步骤:
- 百度favicon制作所需要的favicon
- 将制作的favicon放置于项目中,有两个可放位置:
resource/
、resource/static/
,static下的优先级高于resource
<link href="/facicon.ico" />
静态资源配置原理
https://blog.csdn.net/MrYushiwen/article/details/112478441 >SpringBoot静态资源配置原理
WebMvcAutoConfigurationAdapter静态内部类
一.配置文件前缀
WebMvcAutoConfiguration类中的WebMvcAutoConfigurationAdapter静态内部类:
这是一个配置类,配置文件的属性和xxx进行了绑定。
再看@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})
我们来看当中的WebMvcProperties、ResourceProperties和WebProperties的字节码文件
分别点进这三个类的字节码文件中:
可以看到WebMvcProperties它是与配置文件前缀spring.mvc相关联的。
ResourceProperties它是与配置文件前缀spring.resources相关联。
WebProperties它是与配置文件前缀spring.web相关联。
二.只有一个有参构造器
WebMvcAutoConfigurationAdapter静态内部配置类只有一个有参数的构造器,那它会带来什么特性呢?
它的有参构造器中所有参数的值都会从容器中确定
//有参构造器所有参数的值都会从容器中确定
//ResourceProperties resourceProperties;获取和spring.resources绑定的所有的值的对象
//WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象
//ListableBeanFactory beanFactory Spring的beanFactory
//HttpMessageConverters 找到所有的HttpMessageConverters
//ResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。=========
//DispatcherServletPath
//ServletRegistrationBean 给应用注册Servlet、Filter....
public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebMvcProperties mvcProperties,
ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider,
ObjectProvider<ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,
ObjectProvider<DispatcherServletPath> dispatcherServletPath,
ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) {
this.resourceProperties = resourceProperties;
this.mvcProperties = mvcProperties;
this.beanFactory = beanFactory;
this.messageConvertersProvider = messageConvertersProvider;
this.resourceHandlerRegistrationCustomizer = resourceHandlerRegistrationCustomizerProvider.getIfAvailable();
this.dispatcherServletPath = dispatcherServletPath;
this.servletRegistrations = servletRegistrations;
}
- 第一个参数是ResourceProperties resourceProperties 就是上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注册开启的第二个类,获取和spring.resources绑定的所有的值的对象
- 第二个参数是WebProperties webProperties 就是上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注册开启的第三个类,获取和spring.web绑定的所有的值的对象
- 第三个参数是WebMvcProperties mvcProperties 就是上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注册开启的第一个类,获取和spring.mvc绑定的所有的值的对象
- 第四个参数是ListableBeanFactory beanFactory ,这个是Spring的beanFactory,也就是我们的容器。
- 第五个参数是ObjectProvider messageConvertersProvider,找到所有的HttpMessageConverters
- 第六个参数是ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider,找到资源处理器的自定义器
- 第七个参数是ObjectProvider dispatcherServletPath,相当与找dispatcherServlet能处理的路径
- 第八个参数是ObjectProvider<ServletRegistrationBean<?>> servletRegistrations ,给应用注册原生的Servlet、Filter等等
三.addResourceHandlers方法
所有的资源处理默认规则都在addResourceHandlers方法中
public void addResourceHandlers(ResourceHandlerRegistry registry) {
if (!this.resourceProperties.isAddMappings()) {
logger.debug("Default resource handling disabled");
} else {
Duration cachePeriod = this.resourceProperties.getCache().getPeriod();
CacheControl cacheControl = this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl();
if (!registry.hasMappingForPattern("/webjars/**")) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{"/webjars/**"}).addResourceLocations(new String[]{"classpath:/META-INF/resources/webjars/"}).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
}
String staticPathPattern = this.mvcProperties.getStaticPathPattern();
if (!registry.hasMappingForPattern(staticPathPattern)) {
this.customizeResourceHandlerRegistration(registry.addResourceHandler(new String[]{staticPathPattern}).addResourceLocations(WebMvcAutoConfiguration.getResourceLocations(this.resourceProperties.getStaticLocations())).setCachePeriod(this.getSeconds(cachePeriod)).setCacheControl(cacheControl).setUseLastModified(this.resourceProperties.getCache().isUseLastModified()));
}
}
}
禁用掉静态资源的路径映射
我们打上断点看它的默认规则是怎么起作用的,首先调用resourcePropertoes的isAddMappings()方法:
判断this.resourcePropertoes的isAddMappings()方法是不是不为true,
this.resourcePropertoes我们刚才在2中讲构造器时讲到的ResourceProperties resourceProperties 就是我们上面提到的@EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class})中注册开启的第二个类,获取和spring.resources绑定的所有的值的对象
isAddMappings()方法返回的是this.addMappings的值,如下:
也就是说我们可以通过设置addMappings的值是false还是true来让这个if语句是否执行
我们可以在配置文件中进行设置:
默认它是true,如果是false,那么他就进入if语句中,执行logger.debug(“Default resource handling disabled”);后结束该方法,else中的所有配置都不生效
else中的什么配置/webjars/**去哪找等等一些规则都不生效了。
也就是说我们通过设置add-mappings: false 来禁用掉了静态资源的路径映射。
禁用后所有的静态资源都访问不了了。
addMappings的值如果是true,那么他就不会进入if语句中,而是进入到else语句中,那么else语句的内容都得到了执行。
请求参数处理
https://blog.csdn.net/T_james/article/details/80322414 >Http请求之GET,POST,PUT,DELETE方法详解
请求映射
rest使用与原理
- @xxxMapping;
- Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
• 以前:/getUser 获取用户 /deleteUser 删除用户 /editUser 修改用户 /saveUser 保存用户
• 现在: /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
• 核心Filter:HiddenHttpMethodFilter
• 用法: 表单method=post
,隐藏域_method=put
• SpringBoot中手动开启
• 扩展:如何把_method 这个名字换成我们自己喜欢的。
@RequestMapping(value = "/user",method = RequestMethod.GET)
可以改成@GetMapping(value="/user")
,两者效果是相同的。
同样POST、PUT、DELETE也一样@PostMapping
、@PutMapping
、DeleteMapping
@RequestMapping(value = "/user",method = RequestMethod.GET)
public String getUser(){
return "GET-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.POST)
public String saveUser(){
return "POST-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.PUT)
public String putUser(){
return "PUT-张三";
}
@RequestMapping(value = "/user",method = RequestMethod.DELETE)
public String deleteUser(){
return "DELETE-张三";
}
@Bean
@ConditionalOnMissingBean(HiddenHttpMethodFilter.class)
@ConditionalOnProperty(prefix = "spring.mvc.hiddenmethod.filter", name = "enabled", matchIfMissing = false)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
//发现PUT和DELETE无法访问到
//自定义filter(不定义的话就是_method)
@Bean
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
Rest原理(表单提交要使用REST的时候)
- 表单提交会带上
_method=PUT
- 请求过来被
HiddenHttpMethodFilter
拦截
– 请求是否正常,并且是POST
– 获取到_method
的值。
– 兼容以下请求:PUT.DELETE.PATCH
– 原生request(post),包装模式requesWrapper重写了getMethod方法,返回的是传入的值。
– 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requesWrapper的。
Rest使用客户端工具:
- 如PostMan直接发送Put、delete等方式请求,无需Filter。(PostMan需要去官网下载安装)
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能
请求映射原理
https://blog.csdn.net/wokewoke/article/details/114991289 >SpringBoot --请求映射原理分析
SpringMVC功能分析都从 org.springframework.web.servlet.DispatcherServlet -> doDispatch()
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 找到当前请求使用哪个Handler(Controller的方法)处理
mappedHandler = getHandler(processedRequest);
//HandlerMapping:处理器映射。/xxx->>xxxx
RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则。
所有的请求映射都在HandlerMapping中。
• SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.html;
• SpringBoot自动配置了默认 的 RequestMappingHandlerMapping
• 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息。
- 如果有就找到这个请求对应的handler
- 如果没有就是下一个 HandlerMapping
• 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping。自定义 HandlerMapping
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
for (HandlerMapping mapping : this.handlerMappings) {
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}