基础入门
1.自动装配
spring-boot-starter-web中
-
自动配好tomcat
-
引入tomcat依赖
-
配置tomcat
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> <version>2.5.5</version> <scope>compile</scope> </dependency>
-
-
自动配好SpringMVC
- 引入SpringMVC全套组件
- 自动配好SpringMVC常用组件(功能 )
-
自动配好Web常见功能,如:字符编码问题
- SpringBoot帮我们配置好了所有web开发的常见场景
-
默认的包结构
-
主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来
-
无需以前的包扫描配置
-
想要改变扫描路径:@SpringBootApplication(scanBasePackages = “com.example”)
-
或者@ComponentScan 指定扫描路径、
@SpringBootApplication(scanBasePackages = "com.example") 等同于 @SpringBootConfiguration @EnableAutoConfiguration @ComponentScan("com.example")
-
-
-
各种配置拥有默认值
- 默认配置最终都是映射到某个类的
- 配置文件的值最终会绑定某个类上,这个类会在容器中创建对象
- 修改配置文件的值就行application.properties
-
按需加载所有自动配置项
- 非常多的starter(场景)
- 引入了那些场景这个场景的自动配置才会开启
- SpringBoot所有的自动配置功能都在spring-boot-autoconfigure包里面
-
……
2.注解的意思
java配置类
@Configuration
/**
1. 配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的
2. 配置类本身也是组件
3. ProxyBeanMethods:代理bean的方法(默认为true)
*/
@Configuration(proxyBeanMethods = true)//高数SpringBoot这是一个配置类 == 配置文件
/**
外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象
*/
@Bean//给容器中添加组件,以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
ConfigurableApplicationContext run = SpringApplication.run(SpringBootTestApplication.class, args);
类型 bean = run.getBean(MyConfig.class);
//如果@Configuration(proxyBeanMethods = true),那么代理对象调用方法。SpringBoot总会检查这个组件是否在容器中
//保持组件单实例
bean.user()//调用方法
proxyBeanMethods = true //Full全模式【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
proxyBeanMethods = false //Lite轻量级模式【每个@Bean方法被调用多少次返回的组件都是新创建的】
//类似Spring中设定scope的单例和原型(单例/多例)
/**
Full模式和Lite模式
最佳实战:
1. 配置 类组件之间无依赖关系用Lite模式加速容器启动过程,减少判断
2. 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式
*/
@import
@import({User.class......})
给容器中自动创建出这两个类型的组件,默认组件的名字就是全类名
@Conditional
条件装配:满足Conditional指定的条件,则进行组件注入
@ImportResource
在使用SpringBoot时,自定义的beans.xml等文件无法识别,这个时候,就需要@ImportResource(“classpath:***.xml”)来导入资源(Spring的配置文件)。
@ConfigurationProperties
//只有在容器中的组件,才会拥有SpringBoot提供的强大功能
@Component
@ConfigurationProperties(prefix = "mycar")//获取配置文件中的前缀为mycar的数据
public class Car(){//实体类
}
//或者
@Configuration
@EnableConfigurationProperties(Car.class)//这个时候实体类Car中可以不写@Component
//1. 开启Car配置绑定功能
//2. 把这个Car这个组件自动注册到容器中
public class MyConfig{
}
3.自动配置原理入门
3.1 引导加载自动配置类
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(
excludeFilters = {@Filter(
type = FilterType.CUSTOM,
classes = {TypeExcludeFilter.class}
), @Filter(
type = FilterType.CUSTOM,
classes = {AutoConfigurationExcludeFilter.class}
)}
)
public @interface SpringBootApplication{}
-
@SpringBootConfiguration
@configuration.代表当前是一个配置类
-
@ComponentScan
指定扫描哪些,Spring注解
-
@EnableAutoConfiguration
@AutoConfigurationPackage @Import({AutoConfigurationImportSelector.class}) public @interface EnableAutoConfiguration {}
-
@AutoConfigurationPackage
自动配置包?制定了默认的包规则
@Import({Registrar.class})//给容器中导入一个组件 public @interface AutoConfigurationPackage {} //利用Registrar给容器中导入一系列组件 //将指定的一个包下的所有组件导入进来?MainApplication所在包下。
-
@Import({AutoConfigurationImportSelector.class})
1. 利用this.getAutoConfigurationEntry(annotationMetadata);给容器中批量导入一些组件 2. 调用List<String> configurations = this.getCandidateConfigurations(annotationMetadata, attributes);获取到所有需要导入到容器中的配置类 3. 利用工厂加载Map<String, List<String>> loadSpringFactories(ClassLoader classLoader)得到所有的组件 4. 从META-INF/spring.factories位置来加载一个文件 默认扫描我们当前系统里面所有META-INF/spring.factories位置的文件 spring-boot-autoconfigure-2.5.5.jar包里面也有META-INF/spring.factories
文件里面写死了spring-boot一启动就要给容器中记载的所有配置类 都在spring-boot-autoconfigure-2.5.5.jar下的META-INF/spring.factories里
-
3.2 按需开启自动配置项
虽然我们131个场景的所有自动配置启动的时候默认全部加载。xxxxAutoConfiguration
按照条件装配规则(@Conditional),最终会按需配置
3.3 修改默认配置
@Bean
@ConditionalOnBean({MultipartResolver.class})//容器中有这个类型的组件
@ConditionalOnMissingBean(
name = {"multipartResolver"}
)//容器中没有这个名字的组件
public MultipartResolver multipartResolver(MultipartResolver resolver) {
//给@Bean标注的方法传入了对象参数,这个参数的值就会从容器中找。
//SpringMVC multipartResolver 防止有写用户配置的文件上传解析器不符合规范
return resolver;
}
//给容器中加入了文件上传解析器
SpringBoot默认会在底层配好所有的组件。但是如果用户自己配置了以用户的优先。
@Bean
@ConditionalOnMissingBean
public CharacterEncodingFilter characterEncodingFilter() {}
总结:
- SpringBoot先加载所有的自动配置类。 xxxxxAutoConfiguration
- 每个自动配置类按照条件进行生效,默认都会绑定配置文件指定的值。 xxxxProperties里面拿。xxxProperties和配置文件进行了绑定
- 生效的配置类就会给容器中装配很多组件
- 只要容器中有这些组件,相当于这些功能就有了
- 定制化配置(只要用户有自己配置的,就以用户的优先)
- 用户直接自己@Bean替换底层的组件
- 用户去看这个组件是获取的配置文件什么值就去修改
xxxxxAutoConfiguration —> 组件 —> xxxxProperties里面拿值 —> application.properties
3.4 最佳实践
- 引入场景依赖
- https://docs.spring.io/spring-boot/docs/current/reference/html/using.html#using.build-systems.starters
- 查看自动配置了哪些(选做)
- 自己分析,引入场景对应的自动配置一般都生效了
- 配置文件中debug=true开启自动配置报告。Negative(不生效)、Positive(生效)
- 是否需要定制化
- 参照文档修改配置项
- https://docs.spring.io/spring-boot/docs/current/reference/html/application-properties.html#application-properties
- 自己分析。xxxxProperties绑定了配置文件的哪些。(spring.banner.image.location = ……可以修改banner)
- 自定义加入或者替换组件
- @Bean、@Component……
- ……
- 参照文档修改配置项
4.开发小技巧
4.1 Lombok
导入依赖 —> 搜索安装lombok插件
4.2 dev-tools
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional>
</dependency>
Ctrl+F9
4.3 Spring Initailizr(项目初始化向导)
在创建SpringBoot项目时,把需要的都选好
static 静态资源
templates 页面
application.properties 配置文件
核心功能
1.配置文件
properties>yml>yaml
1.1 properties
同以前的properties用法
1.2 yaml
非常适合用来做以数据为中心的配置文件
需要在实体类里加上
@ConfigurationProperties(prefix = "name")
@Component
基本语法
- key:value; kv之间有空格
- 大小写敏感
- 使用缩进表示层级关系
- 缩进不允许使用tab,只允许空格
- 缩进的空格数不重要,只要相同层级的元素左对齐即可
- '#'表示注解
- ’ '与" " 表示字符串内容 会被转义/不转义
- 单引号会将\n作为字符串输出 双引号会将\n作为换行输出
- 双引号不会转义,单引号会转义
在写yml的时候,我们可以导入下面这个依赖,然后在写yml时就可以有提示了(譬如person类)
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-configuration-processor -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<version>2.5.5</version><!-- 可以不写,springboot里面有 -->
<optional>true</optional>
</dependency>
但是之后我们需要在pom.xml中加入如下,打包的时候我们需要将这个依赖去除(没用还占内存);新版本会自动添加并删除掉。
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupld>
<artifactId>spring-boot-maven-plugin</artifactId>
<!-- 从这开始 -->
<configuration>
<excludes>
<exclude>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configurationprocessor</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
2.Web开发
2.1 简单功能分析
静态资源访问
-
静态资源目录
只要静态资源放在类路径下: /static(或/public或/resources或/META-INF/resources)
访问:当前项目根路径/ + 静态资源名
原理:静态映射/**。
请求进来,先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源找不到就404了
修改静态资源路径
spring: web: resources: static-locations: [classpath:/haha/,……]
-
静态资源访问前缀
默认无前缀
spring: mvc: static-path-pattern: /res/** #就是访问的时候需要加/res/
当前项目 + static-path-pattern + 静态资源名 = 静态资源文件夹下找
-
webjar
自动映射
https://www.webjars.org/
例子:
<dependency> <groupId>org.webjars</groupId> <artifactId>jquery</artifactId> <version>3.6.0</version> </dependency>
访问地址:http://localhost:8080/webjars/jquery/3.6.0/jquery.js后面地址要按照依赖里面的包路径
欢迎页支持
- 静态资源路径下index.html(加了访问前缀就不是欢迎页了)
- 可以配置静态资源路径
- 但是不可以配置静态资源的访问前缀。否则导致index.html不能被默认访问
spring:
mvc:
static-path-pattern: /res/** 这个会导致welcome page功能失效
- controller能处理/index
自定义Favicon
Favicon放在静态资源目录下即可
spring:
mvc:
static-path-pattern: /res/** 这个会导致 Favicon 功能失效
静态资源配置原理
-
SpringBoot启动默认加载 xxxAutoConfiguration类(自动配置类)
-
SpringMVC功能的自动配置类 WebMvcAutoConfiguration,生效
@Configuration( proxyBeanMethods = false ) @ConditionalOnWebApplication( type = Type.SERVLET ) @ConditionalOnClass({Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class}) @ConditionalOnMissingBean({WebMvcConfigurationSupport.class}) @AutoConfigureOrder(-2147483638) @AutoConfigureAfter({DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class, ValidationAutoConfiguration.class}) public class WebMvcAutoConfiguration {}
-
给容器中配了什么
@Configuration( proxyBeanMethods = false ) @Import({WebMvcAutoConfiguration.EnableWebMvcConfiguration.class}) @EnableConfigurationProperties({WebMvcProperties.class, ResourceProperties.class, WebProperties.class}) @Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer, ServletContextAware {}
-
配置文件的相关属性和xxx进行了绑定。WebMvcProperties == spring.mvc、ResourceProperties == spring.resources
-
配置类只有一个有参构造器
//有参构造器所有参数的值都会从容器中确定 //ResourceProperties resourceProperties:获取和spring.resources绑定的所有的值的对象 //WebProperties webProperties:获取和spring.mvc绑定的所有的值的对象 //ListableBeanFactory beanFactory:Spring的beanFactory //HttpMessageConverters:找到所有的HttpMessageConverters //WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer:找到 资源处理器的自定义器 //DispatcherServletPath //ServletRegistrationBean:给应用注册Servlet、Filter…… public WebMvcAutoConfigurationAdapter(ResourceProperties resourceProperties, WebProperties webProperties, WebMvcProperties mvcProperties, ListableBeanFactory beanFactory, ObjectProvider<HttpMessageConverters> messageConvertersProvider, ObjectProvider<WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer> resourceHandlerRegistrationCustomizerProvider, ObjectProvider<DispatcherServletPath> dispatcherServletPath, ObjectProvider<ServletRegistrationBean<?>> servletRegistrations) { this.resourceProperties = (Resources)(resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources()); this.mvcProperties = mvcProperties; this.beanFactory = beanFactory; this.messageConvertersProvider = messageConvertersProvider; this.resourceHandlerRegistrationCustomizer = (WebMvcAutoConfiguration.ResourceHandlerRegistrationCustomizer)resourceHandlerRegistrationCustomizerProvider.getIfAvailable(); this.dispatcherServletPath = dispatcherServletPath; this.servletRegistrations = servletRegistrations; this.mvcProperties.checkConfiguration(); }
-
资源处理的默认规则
public void addResourceHandlers(ResourceHandlerRegistry registry) { if (!this.resourceProperties.isAddMappings()) { logger.debug("Default resource handling disabled"); } else { //webjars的规则 this.addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/"); //静态资源的规则 this.addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) -> { registration.addResourceLocations(this.resourceProperties.getStaticLocations()); if (this.servletContext != null) { ServletContextResource resource = new ServletContextResource(this.servletContext, "/"); registration.addResourceLocations(new Resource[]{resource}); } }); } } private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) { this.addResourceHandler(registry, pattern, (registration) -> { registration.addResourceLocations(locations); }); } private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, Consumer<ResourceHandlerRegistration> customizer) { if (!registry.hasMappingForPattern(pattern)) { ResourceHandlerRegistration registration = registry.addResourceHandler(new String[]{pattern}); customizer.accept(registration); registration.setCachePeriod(this.getSeconds(this.resourceProperties.getCache().getPeriod())); registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl()); registration.setUseLastModified(this.resourceProperties.getCache().isUseLastModified()); this.customizeResourceHandlerRegistration(registration); } }
spring: web: resources: add-mappings: false #禁用所有静态资源规则
public static class Resources { private static final String[] CLASSPATH_RESOURCE_LOCATIONS = new String[]{"classpath:/META-INF/resources/", "classpath:/resources/", "classpath:/static/", "classpath:/public/"}; private String[] staticLocations; public Resources() { this.staticLocations = CLASSPATH_RESOURCE_LOCATIONS; } }
-
欢迎页的处理规则
//HandlerMapping:处理器映射。保存了每一个Handler能处理哪些请求。 @Bean public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext, FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) { WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, this.getWelcomePage(), this.mvcProperties.getStaticPathPattern()); welcomePageHandlerMapping.setInterceptors(this.getInterceptors(mvcConversionService, mvcResourceUrlProvider)); welcomePageHandlerMapping.setCorsConfigurations(this.getCorsConfigurations()); return welcomePageHandlerMapping; } //在WelcomePageHandlerMapping类中 WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders, ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) { //要用欢迎页功能,必须是/** if (welcomePage != null && "/**".equals(staticPathPattern)) { logger.info("Adding welcome page: " + welcomePage); this.setRootViewName("forward:index.html"); } else if (this.welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) { // 调用Controller /index logger.info("Adding welcome page template: index"); this.setRootViewName("index"); } }
-
favicon
/favicon.ico
2.2 请求参数处理
1.请求映射
- @xxxMapping
- Rest风格支持(使用HTTP请求方式动词来表示对资源的操作)
- /user GET-获取用户 DELETE-删除用户 PUT-修改用户 POST-保存用户
- 核心Filter:HiddenHttpMethodFilter
- 用法:表单method=post,隐藏域_method=put
- SpringBoot中自动开启(3、4)
//例子
@RequestMapping(value = "/user" , method = RequestMethod.GET)
public String getUser(){
return "GET-例子";
}
<!-- get和post这么干 -->
<form action="/user" method="get">
<input value="提交" type=“submit/>
</form>
<form action="/user" method="post">
<input value="提交" type=“submit/>
</form>
<!-- delete和put这么干 -->
<form action="/user" method="post">
<input name="_method" type="hidden" value="DELETE"/>
<input value="提交" type=“submit/>
</form>
<form action="/user" method="post">
<input name="_method" type="hidden" value="PUT"/>
<input value="提交" type=“submit/>
</form>
@Bean
@ConditionalOnMissingBean({HiddenHttpMethodFilter.class})
@ConditionalOnProperty(
prefix = "spring.mvc.hiddenmethod.filter",
name = {"enabled"}
)
public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {
return new OrderedHiddenHttpMethodFilter();
}
spring:
mvc:
hiddenmethod:
filter:
enabled: true #开启页面表单的Rest功能
Rest原理(表单提交要使用REST的时候)
-
表单提交会带上_method=PUT
-
请求过来被HiddenHttpMethodFilter拦截
- 请求是否正常,并且是POST
- 获取到_method的值
- 兼容以下请求;PUT。DELETE。PATCH
- 原生request(post),包装模式requestWrapper重写了getMethod方法,返回的是传入的值。
- 过滤器链放行的时候用wrapper。以后的方法调用getMethod是调用requestWrapper的。
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; if ("POST".equals(request.getMethod()) && request.getAttribute("javax.servlet.error.exception") == null) { String paramValue = request.getParameter(this.methodParam); if (StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); if (ALLOWED_METHODS.contains(method)) { requestToUse = new HiddenHttpMethodFilter.HttpMethodRequestWrapper(request, method); } } } filterChain.doFilter((ServletRequest)requestToUse, response); }
- 请求是否正常,并且是POST
Rest使用客户端工具
- 如PostMan直接发送PUT、DELETE等方式请求,无需Filter
@Configuration(proxyBeanMethods = false)
public class MyConfig {
public HiddenHttpMethodFilter hiddenHttpMethodFilter(){
HiddenHttpMethodFilter methodFilter = new HiddenHttpMethodFilter();
methodFilter.setMethodParam("_m");
return methodFilter;
}
}
以上代码可以改变表单中用的_method,上面改成了 _m。
请求映射原理
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 {
try {
ModelAndView mv = null;
Object dispatchException = null;
try {
processedRequest = this.checkMultipart(request);
multipartRequestParsed = processedRequest != request;
//找到当前请求使用哪个Handler(Controller的方法)处理
mappedHandler = this.getHandler(processedRequest);
//…………………………
**HandlerMapping:**处理器映射。 /xxx --> xxxx【这里面保存了所有的请求映射,然后会在之后遍历这五个,判断查询路径对应的映射有木有】
//DispatcherServlet中的
@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
if (this.handlerMappings != null) {
Iterator var2 = this.handlerMappings.iterator();
while(var2.hasNext()) {
HandlerMapping mapping = (HandlerMapping)var2.next();
HandlerExecutionChain handler = mapping.getHandler(request);
if (handler != null) {
return handler;
}
}
}
return null;
}
RequestMapperingHandlerMapping:保存了所有@RequestMapping和handler的映射规则
- SpringBoot自动配置欢迎页的WelcomePageHandlerMapping。访问/能访问到index.html
- SpringBoot自动配置了磨人的RequestMappingHandlerMapping
- 请求进来,挨个尝试所有的HandlerMapping看是否有请求信息
- 如果有就找到这个请求对应的Handler
- 如果没有就是下一个HandlerMapping
- 我们需要一些自定义的映射处理,我们也可以自己给容器中放HandlerMapping。自定义HandlerMapping
2.普通参数与基本注解
-
注解:
@PathVariable、@RequestHeader、@ModelAttribute、@RequestParam、@MatrixVariable、@CookieValue、@RequestBody
// car/2/owner/zhangsan
@GetMapping("/car/{id}/owner/{username}")
public Map<String, Object> getCar(
// 路径变量id
@PathVariable("id") Integer id,
// 路径变量username
@PathVariable("username") String name,
// 获取所有的路径变量
@PathVariable Map<String,String> pv,
//获取请求头中User-Agent
@RequestHeader("User-Agent") String userAgent,
//获取所有请求头
@RequestHeader Map<String,String> header,
// 获取请求参数age ?age=18
@RequestParam("age") Integer age,
// 获取请求参数inters
@RequestParam("inters") List<String> inters,
// 获取所有的请求参数
@RequestParam Map<String,String> params,
// 获取cookie中的_ga的值
@CookieValue("_ga") String _ga,
// 获取cookie中所有信息
@CookieValue("_ga") Cookie cookie){
Map<String, Object> map = new HashMap<>();
// map.put("id",id);
// map.put("name",name);
// map.put("pv",pv);
// map.put("userAgent",userAgent);
// map.put("headers",header);
map.put("age",age);
map.put("inters",inters);
map.put("params",params);
map.put("_ga",_ga);
System.out.println(cookie.getName()+"===>"+cookie.getValue());
return map;
}
// 获取请求体中的值, 只有Post方式有请求体
@PostMapping("/save")
public Map postMethod(@RequestBody String content){
Map<String,Object> map = new HashMap<>();
map.put("content",content);
return map;
}
@RequestAttribute(大概可以认为:就是直接给形参传一个已经设置过的值)
@Controller // 普通的控制器,方法的返回 是要进行跳转的
public class RequestController {
@GetMapping("/goto")
public String goToPage(HttpServletRequest request){
request.setAttribute("msg","成功了...");
request.setAttribute("code",200);
return "forward:/success"; //转发到 /success请求
}
@GetMapping("/params")
public String testParam(Map<String,Object> map,
Model model,
HttpServletRequest request,
HttpServletResponse response){
map.put("hello","world666");
model.addAttribute("world","hello666");
request.setAttribute("message","HelloWorld");
Cookie cookie = new Cookie("c1","v1");
response.addCookie(cookie);
return "forward:/success";
}
@ResponseBody
@GetMapping("/success")
public Map success(
// 获取请求域中的msg 上面转发的时设置的属性 required = false请求域中这个属性不是必须的
@RequestAttribute(value = "msg",required = false) String msg,
// 这个没写可以获取全部属性 点进去看看
@RequestAttribute(value = "code",required = false)Integer code,
// 通过原生请求获取request
HttpServletRequest request){
Object msg1 = request.getAttribute("msg");
Map<String,Object> map = new HashMap<>();
Object hello = request.getAttribute("hello");
Object world = request.getAttribute("world");
Object message = request.getAttribute("message");
map.put("reqMethod_msg",msg1);
map.put("annotation_msg",msg);
map.put("hello",hello);
map.put("world",world);
map.put("message",message);
return map;
}
}
@MatrixVariable矩阵变量
-
矩阵变量@MatrixVariable使用
- 语法: 请求路径:/cars/sell;low=34;brand=byd,audi,yd
- 面试题:页面开发,cookie禁用了,session里面的内容怎么使用;
- 默认:session.set(a,b)—> jsessionid —> cookie ----> 每次发请求携带。
- 可以使用url重写:/abc;jsesssionid=xxxx 把cookie的值使用矩阵变量的方式进行传递.
- SpringBoot默认是禁用了矩阵变量的功能.
- 自动配置类中configurePathMatch这个进行处理。
- 手动开启:原理。对于路径的处理。UrlPathHelper进行解析,点进去发现。removeSemicolonContent = true;(移除分号内容)支持矩阵变量。
<a href="/cars/sell;low=34;brand=byd,audi,yd">@MatrixVariable(矩阵变量)</a> <a href="/cars/sell;low=34;brand=byd;brand=audi;brand=yd">@MatrixVariable(矩阵变量)</a> <a href="/boss/1;age=20/2;age=10">@MatrixVariable(矩阵变量)/boss/{bossId}/{empId}</a>
-
手动开启矩阵变量的功能,两种方式
-
第一种写法:@Bean 给容器中直接放入WebMvcConfigurer组件
-
第二种写法:实现WebMvcConfigurer,因为有默认实现只用修改需要修改的方法。
// 第一种写法: 给容器中放入WebMvcConfigurer组件 @Configuration(proxyBeanMethods = false) public class WebConfig { @Bean public WebMvcConfigurer webMvcConfigurer(){ return new WebMvcConfigurer() { @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(urlPathHelper); } }; } } // 第二种写法 实现WebMvcConfigurer @Configuration(proxyBeanMethods = false) public class WebConfig implements WebMvcConfigurer { @Override public void configurePathMatch(PathMatchConfigurer configurer) { UrlPathHelper urlPathHelper = new UrlPathHelper(); urlPathHelper.setRemoveSemicolonContent(false); configurer.setUrlPathHelper(urlPathHelper); } }
-
矩阵变量必须有url路径变量才能被解析:要写成路径变量的表示方法{path}
@GetMapping("/cars/{path}") public Map carsSell(@MatrixVariable("low") Integer low, @MatrixVariable("brand") List<String> brand, // 获取真正的访问路径就是sell @PathVariable("path") String path){ Map<String,Object> map = new HashMap<>(); map.put("low",low); map.put("brand",brand); map.put("path",path); return map; } // /boss/1;age=20/2;age=10 两个路径变量 每个路径变量上有相同的变量名称 @GetMapping("/boss/{bossId}/{empId}") public Map boss(@MatrixVariable(value = "age",pathVar = "bossId") Integer bossAge, @MatrixVariable(value = "age",pathVar = "empId") Integer empAge){ Map<String,Object> map = new HashMap<>(); map.put("bossAge",bossAge); map.put("empAge",empAge); return map; }
-
-
Servlet API:
WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId
-
复杂参数:
Map、Model(map、model里面的数据会被放在request的请求域 request.setAttribute)、Errors/BindingResult、RedirectAttributes( 重定向携带数据)、ServletResponse(response)、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder
-
自定义对象参数:
- 可以自动类型转换与格式化,可以级联封装。
2.3 响应数据与内容协商
2.4 视图解析与模板引擎
2.5 拦截器
2.6 跨域
最后:遇到的坑积累
-
<build> <!-- 打jar包插件--> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>
artifactId爆红。
**解决方法:**加入版本号
<version>2.5.5</version>
-
打包时出现错误
com.example:SpringBootTest:jar:0.0.1-SNAPSHOT :
Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test (default-test) on project SpringBootTest: There are test failures.
**解决方法:**在pom.xml中的build中加入以下代码
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <version>2.22.2</version> <configuration> <skipTests>true</skipTests> </configuration> </plugin>