做网站要分几部分完成百度推广合作

当前位置: 首页 > news >正文

做网站要分几部分完成,百度推广合作,主流的自助建站网站,服装定制行业市场分析核心功能
1、配置文件 application.properties 同基础入门篇的application.properties用法一样 Spring Boot 2 入门基础 application.yaml#xff08;或application.yml#xff09; 基本语法 key: value#xff1b;kv之间有空格大小写敏感使用缩进表示层级关系缩进不允…核心功能
1、配置文件 application.properties 同基础入门篇的application.properties用法一样 Spring Boot 2 入门基础 application.yaml或application.yml 基本语法 key: valuekv之间有空格大小写敏感使用缩进表示层级关系缩进不允许使用tab只允许空格缩进的空格数不重要只要相同层级的元素左对齐即可#表示注释字符串无需加引号如果要加与表示字符串内容 会被 转义/不转义 数据类型 datebooleanstringnumbernullk: vmaphashobject#行内写法
k: {k1:v1,k2:v2,k3:v3} #或 k: k1: v1k2: v2k3: v3setarraylistqueue#行内写法
k: [v1,v2,v3] #或者 k:- v1- v2- v3示例 Person.java package com.atguigu.boot.bean;import lombok.; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component;import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set;Data AllArgsConstructor NoArgsConstructor ToString EqualsAndHashCodeComponent ConfigurationProperties(prefix person) public class Person {private String userName;private Boolean boss;private Date birth;private Integer age;private Pet pet;private String[] interests;private ListString animal;private MapString, Object score;private SetDouble salarys;private MapString, ListPet allPets; } Pet.java package com.atguigu.boot.bean;import lombok.;Data AllArgsConstructor NoArgsConstructor ToString EqualsAndHashCode public class Pet {private String name;private Double weight; } hello.java package com.atguigu.boot.controller;import com.atguigu.boot.bean.Person; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController;RestController public class Hello {AutowiredPerson person;RequestMapping(/person)public Person handle00(){return person;}} application.yml person:userName: zhangsanboss: truebirth: 2020/01/01age: 4pet:name: luckyweight: 12#interests: [台球,足球,篮球] #行内写法interests:- 台球- 足球- 篮球animal: [阿猫,阿狗,熊猫,老虎,狮子]#score: {English:99,Math:98}score:English: 99Math: 98salarys:- 99999.99- 88888.88allPets:cat:- {name: xixi,weight: 6}- {name: dongdong,weight: 5}dog:- name: nannanweight: 10- name: beibeiweight: 13字符串中有双引号 双引号中有转移字符 双引号时转移字符被认为是字符串所以在控制台输出时换行了 单引号时转移字符又增加了一次转移所以在控制台输出时被认为是字符串输出了 person:userName: zhangsan \n lisiperson:userName: zhangsan \n lisi配置提示 在引入了spring-boot-configuration-processor依赖后编写application.yml文件时自定义的bean就会自动提示方便开发使用。 dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactIdoptionaltrue/optional/dependencybuildpluginsplugingroupIdorg.springframework.boot/groupIdartifactIdspring-boot-maven-plugin/artifactIdconfigurationexcludesexcludegroupIdorg.springframework.boot/groupIdartifactIdspring-boot-configuration-processor/artifactId/exclude/excludes/configuration/plugin/plugins/build2、Web开发 2.1、SpringMVC自动配置概览 Spring Boot provides auto-configuration for Spring MVC that works well with most applications. (大多场景我们都无需自定义配置) The auto-configuration adds the following features on top of Spring’s defaults: Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans. (内容协商视图解析器和BeanName视图解析器) Support for serving static resources, including support for WebJars (covered later in this document)). (静态资源包括webjars) Automatic registration of Converter, GenericConverter, and Formatter beans. (自动注册 ConverterGenericConverterFormatter ) Support for HttpMessageConverters (covered later in this document). (支持 HttpMessageConverters 后来我们配合内容协商理解原理) Automatic registration of MessageCodesResolver (covered later in this document). (自动注册 MessageCodesResolver 国际化用) Static index.html support. (静态index.html 页支持) Custom Favicon support (covered later in this document). (自定义 Favicon ) Automatic use of a ConfigurableWebBindingInitializer bean (covered later in this document). (自动使用 ConfigurableWebBindingInitializerDataBinder负责将请求数据绑定到JavaBean上) If you want to keep those Spring Boot MVC customizations and make more MVC customizations (interceptors, formatters, view controllers, and other features), you can add your own Configuration class of type WebMvcConfigurer but without EnableWebMvc. (不用EnableWebMvc注解。使用 Configuration WebMvcConfigurer 自定义规则) If you want to provide custom instances of RequestMappingHandlerMapping, RequestMappingHandlerAdapter, or ExceptionHandlerExceptionResolver, and still keep the Spring Boot MVC customizations, you can declare a bean of type WebMvcRegistrations and use it to provide custom instances of those components. 声明 WebMvcRegistrations 改变默认底层组件 If you want to take complete control of Spring MVC, you can add your own Configuration annotated with EnableWebMvc, or alternatively add your own Configuration-annotated DelegatingWebMvcConfiguration as described in the Javadoc of EnableWebMvc. 使用 EnableWebMvcConfigurationDelegatingWebMvcConfiguration 全面接管SpringMVC
2.2、简单功能分析 2.2.1、静态资源访问 简介 Static Content By default, Spring Boot serves static content from a directory called /static (or /public or /resources or /META-INF/resources) in the classpath or from the root of the ServletContext. It uses the ResourceHttpRequestHandler from Spring MVC so that you can modify that behavior by adding your own WebMvcConfigurer and overriding the addResourceHandlers method. You can also customize the static resource locations by using the spring.web.resources.static-locations property (replacing the default values with a list of directory locations). The root servlet context path, “/”, is automatically added as a location as well. In addition to the “standard” static resource locations mentioned earlier, a special case is made for Webjars content. By default, any resources with a path in /webjars/** are served from jar files if they are packaged in the Webjars format. The path can be customized with the spring.mvc.webjars-path-pattern property. 只要静态资源放在类路径下 called /static (or /public or /resources or /META-INF/resources 访问 当前项目根路径/ 静态资源名 原理 静态映射/。 请求进来先去找Controller看能不能处理。不能处理的所有请求又都交给静态资源处理器。静态资源也找不到则响应404页面。 也可以改变默认的静态资源路径/static/public,/resources, /META-INF/resources失效 Web场景静态资源规则与定制化 spring:mvc:static-path-pattern: /res/ #静态资源访问前缀web:resources:static-locations: [classpath:/Image] #静态资源访问目录当前项目 static-path-pattern 静态资源名 静态资源文件夹下找 经测试除了Image目录下的静态资源可以访问/META-INF/resources/目录下的静态资源也可以进行访问不清楚是不是bug webjar 可用jar方式添加cssjs等资源文件 https://www.webjars.org/ 例如添加jquery dependencygroupIdorg.webjars/groupIdartifactIdjquery/artifactIdversion3.5.1/version /dependency访问地址http://localhost:8080/webjars/jquery/3.5.1/jquery.js http://localhost:8080/webjars/后面地址要按照依赖里面的包路径。
2.2.2、欢迎页支持 静态资源路径下 index.html。 可以配置静态资源路径但是不可以配置静态资源的访问前缀。否则导致 index.html不能被默认访问 controller能处理/index。 2.2.3、自定义Favicon 指网页标签上的小图标。 favicon.ico 放在静态资源目录下即可。 spring:

mvc:

static-path-pattern: /res/** 这个会导致 Favicon 功能失效2.2.4、静态资源配置原理

SpringBoot启动默认加载 xxxAutoConfiguration 类自动配置类SpringMVC功能的自动配置类WebMvcAutoConfiguration生效Configuration(proxyBeanMethods false) ConditionalOnWebApplication(type Type.SERVLET) ConditionalOnClass({ Servlet.class, DispatcherServlet.class, WebMvcConfigurer.class }) ConditionalOnMissingBean(WebMvcConfigurationSupport.class) AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE 10) AutoConfigureAfter({ DispatcherServletAutoConfiguration.class, TaskExecutionAutoConfiguration.class,ValidationAutoConfiguration.class }) public class WebMvcAutoConfiguration {… }给容器中配置的内容 配置文件的相关属性的绑定WebMvcPropertiesspring.mvc、ResourcePropertiesspring.resourcesConfiguration(proxyBeanMethods false) Import(EnableWebMvcConfiguration.class) EnableConfigurationProperties({ WebMvcProperties.class, ResourceProperties.class }) Order(0) public static class WebMvcAutoConfigurationAdapter implements WebMvcConfigurer {… }配置类只有一个有参构造器 有参构造器所有参数的值都会从容器中确定 public WebMvcAutoConfigurationAdapter(WebProperties webProperties, WebMvcProperties mvcProperties,ListableBeanFactory beanFactory, ObjectProviderHttpMessageConverters messageConvertersProvider,ObjectProviderResourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizerProvider,ObjectProviderDispatcherServletPath dispatcherServletPath,ObjectProviderServletRegistrationBean? servletRegistrations) {this.mvcProperties mvcProperties;this.beanFactory beanFactory;this.messageConvertersProvider messageConvertersProvider;this.resourceHandlerRegistrationCustomizer resourceHandlerRegistrationCustomizerProvider.getIfAvailable();this.dispatcherServletPath dispatcherServletPath;this.servletRegistrations servletRegistrations;this.mvcProperties.checkConfiguration(); }ResourceProperties resourceProperties获取和spring.resources绑定的所有的值的对象WebMvcProperties mvcProperties 获取和spring.mvc绑定的所有的值的对象ListableBeanFactory beanFactory Spring的beanFactoryHttpMessageConverters 找到所有的HttpMessageConvertersResourceHandlerRegistrationCustomizer 找到 资源处理器的自定义器。DispatcherServletPathServletRegistrationBean 给应用注册Servlet、Filter… 资源处理的默认规则 … public class WebMvcAutoConfiguration {…public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {…Overrideprotected void addResourceHandlers(ResourceHandlerRegistry registry) {super.addResourceHandlers(registry);if (!this.resourceProperties.isAddMappings()) {logger.debug(Default resource handling disabled);return;}ServletContext servletContext getServletContext();addResourceHandler(registry, /webjars/, classpath:/META-INF/resources/webjars/);addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(), (registration) - {registration.addResourceLocations(this.resourceProperties.getStaticLocations());if (servletContext ! null) {registration.addResourceLocations(new ServletContextResource(servletContext, SERVLET_LOCATION));}});}…}… }根据上述代码我们可以同过配置禁止所有静态资源规则。 并且/webjars/, classpath:/META-INF/resources/webjars/也解释了为什么在指定了静态资源目录后/META-INF/resources/目录下的静态资源依然可以访问而且他目录下的静态资源无法访问了 spring:resources:add-mappings: false #禁用所有静态资源规则静态资源规则 ConfigurationProperties(prefix spring.resources, ignoreUnknownFields false) public class ResourceProperties {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 class WebMvcAutoConfiguration {…public static class EnableWebMvcConfiguration extends DelegatingWebMvcConfiguration implements ResourceLoaderAware {…Beanpublic WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {WelcomePageHandlerMapping welcomePageHandlerMapping new WelcomePageHandlerMapping(new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),this.mvcProperties.getStaticPathPattern());welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());return welcomePageHandlerMapping;}WelcomePageHandlerMapping的构造方法如下 WelcomePageHandlerMapping(TemplateAvailabilityProviders templateAvailabilityProviders,ApplicationContext applicationContext, Resource welcomePage, String staticPathPattern) {if (welcomePage ! null /.equals(staticPathPattern)) {//要用欢迎页功能必须是/logger.info(Adding welcome page: welcomePage);setRootViewName(forward:index.html);}else if (welcomeTemplateExists(templateAvailabilityProviders, applicationContext)) {//调用Controller /indexlogger.info(Adding welcome page template: index);setRootViewName(index);} }这构造方法内的代码也解释了web场景-welcome与favicon功能中配置static-path-pattern了welcome页面和小图标失效的问题。 favicon 由于favicon.ico图标是由浏览器自动发送请求/favicon.ico获取并保存在session域中的。因此如果我们在配置文件中设置了静态资源访问前缀那么浏览器发送的/favicon.ico由于不符合访问前缀要求就会获取不到相对应的图标了(图标也是静态资源的一种)。
2.3、请求参数处理 !DOCTYPE html html langen headmeta charsetUTF-8titleTitle/title /head body h1atguigu欢迎您/h1 测试REST风格 form action/user methodgetinput valueREST-GET 提交 typesubmit/ /form form action/user methodpostinput valueREST-POST 提交 typesubmit/ /form form action/user methodpostinput name_method typehidden valuedelete/ !– input name_m typehidden valuedelete/–input valueREST-DELETE 提交 typesubmit/ /form form action/user methodpostinput name_method typehidden valuePUT/input valueREST-PUT 提交 typesubmit/ /form hr/ 测试基本注解 ula hrefcar/3/owner/lisi?age18intersbasketballintersgamecar/{id}/owner/{username}/aliPathVariable路径变量/liliRequestHeader获取请求头/liliRequestParam获取请求参数/liliCookieValue获取cookie值/liliRequestBody获取请求体[POST]/liliRequestAttribute获取request域属性/liliMatrixVariable矩阵变量/li /ul/cars/{path}?xxxxxxaaaccc queryString 查询字符串。RequestParambr/ /cars/sell;low34;brandbyd,audi,yd 矩阵变量 br/ 页面开发cookie禁用了session里面的内容怎么使用 session.set(a,b)— jsessionid — cookie —- 每次发请求携带。 url重写/abc;jsesssionidxxxx 把cookie的值使用矩阵变量的方式进行传递./boss/1/2/boss/1;age20/2;age20a href/cars/sell;low34;brandbyd,audi,ydMatrixVariable矩阵变量/a a href/cars/sell;low34;brandbyd;brandaudi;brandydMatrixVariable矩阵变量/a a href/boss/1;age20/2;age10MatrixVariable矩阵变量/boss/{bossId}/{empId}/a br/ form action/save methodpost测试RequestBody获取数据 br/用户名input nameuserName/ br邮箱input nameemail/input typesubmit value提交/ /form olli矩阵变量需要在SpringBoot中手动开启/lili根据RFC3986的规范矩阵变量应当绑定在路径变量中/lili若是有多个矩阵变量应当使用英文符号;进行分隔。/lili若是一个矩阵变量有多个值应当使用英文符号,进行分隔或之命名多个重复的key即可。/lili如/cars/sell;low34;brandbyd,audi,yd/li /ol hr/ 测试原生API a href/testapi测试原生API/a hr/ 测试复杂类型hr/ 测试封装POJO form action/saveuser methodpost姓名 input nameuserName valuezhangsan/ br/年龄 input nameage value18/ br/生日 input namebirth value2019/12/10/ br/!– 宠物姓名input namepet.name value阿猫/br/–!– 宠物年龄input namepet.age value5/–宠物 input namepet value啊猫,3/input typesubmit value保存/ /formbr /body /htmlpackage com.atguigu.boot.controller;import org.springframework.web.bind.annotation.
;RestController public class HelloController {RequestMapping(/Hello)public String handler00() {return 你好;}// RequestMapping(value /user, method RequestMethod.GET) 使用注解代替GetMapping(/user)public String getUser() {return getUser1;}// RequestMapping(value /user, method RequestMethod.POST) 使用注解代替PostMapping(/user)public String saveUser() {return saveUser1;}// RequestMapping(value /user, method RequestMethod.PUT) 使用注解代替PutMapping(/user)public String putUser() {return putUser1;}// RequestMapping(value /user, method RequestMethod.DELETE) 使用注解代替DeleteMapping(/user)public String deleteUser() {return deleteUser1;} }2.3.1、请求映射 2.3.1.1、 Rest使用及原理 xxxMapping;Rest风格支持使用HTTP请求方式动词来表示对资源的操作 以前“/getUser” 获取用户“/deleteUser” 删除用户“/editUser” 修改用户“/saveUser” 保存用户现在“/user”MethodGET-获取用户、MethodDELETE-获取用户、MethodPUT-修改用户、MethodPOST-保存用户核心FilterHiddenHttpMethodFilter 用法表单methodpost隐藏域_methodput、_methoddeleteSpringBoot中手动开启spring.mvc.hiddenmethod.filter.enabledtrue; 扩展如果把_method这个名字进行定制化
spring:mvc:hiddenmethod:filter:enabled: true #开启页面表单的Rest功能// 开启表单拦截器 Bean ConditionalOnMissingBean(HiddenHttpMethodFilter.class) ConditionalOnProperty(prefix spring.mvc.hiddenmethod.filter, name enabled, matchIfMissing false)public OrderedHiddenHttpMethodFilter hiddenHttpMethodFilter() {return new OrderedHiddenHttpMethodFilter(); }//—————————————————————————————————————- //自定义filter package com.atguigu.boot.config;import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.HiddenHttpMethodFilter;package com.atguigu.boot.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.HiddenHttpMethodFilter;Configuration(proxyBeanMethods false) public class WebConfig {Beanpublic HiddenHttpMethodFilter hiddenHttpMethodFilter() {HiddenHttpMethodFilter hiddenHttpMethodFilter new HiddenHttpMethodFilter();hiddenHttpMethodFilter.setMethodParam(_m);return hiddenHttpMethodFilter;} }}Rest原理表单提交要使用Rest的时候 request使用表单表单提交会带上_methodPUT 请求过来会被HiddenHttpMethodFilter拦截请求是否正常并且请求方法为POST获取_method的值兼容以下请求PUT、DELETE、PATCH包装模式requestWrapper继承原生requestHttpServletRequestWrapper重写了方法getMethod方法返回的是传入的值。过滤器filter放行的时候使用wrapper以后的方法调用getMethod是调用了requestWrapper类中的。 request使用客户端工具 入PostMan工具可以直接发送PUT、DELETE等请求方式无需filter。
2.3.1.2、 请求映射原理 javax.servlet.http.HttpServlet#doGet   →org.springframework.web.servlet.FrameworkServlet#doGet (重写)    →org.springframework.web.servlet.FrameworkServlet#processRequest (doGet调用)     →org.springframework.web.servlet.FrameworkServlet#doService (processRequest 调用 抽象)      →org.springframework.web.servlet.DispatcherServlet#doService (实现) SpringMVC功能分析 都要从 org.springframework.web.servlet.DispatcherServlet#doDispatch 开始 /*** Process the actual dispatching to the handler.* pThe handler will be obtained by applying the servlets HandlerMappings in order.* The HandlerAdapter will be obtained by querying the servlets installed HandlerAdapters* to find the first that supports the handler class.* pAll HTTP methods are handled by this method. Its up to HandlerAdapters or handlers* themselves to decide which methods are acceptable.* param request current HTTP request* param response current HTTP response* throws Exception in case of any kind of processing failure/SuppressWarnings(deprecation)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);// Determine handler for the current request.mappedHandler getHandler(processedRequest);if (mappedHandler null) {noHandlerFound(processedRequest, response);return;}// Determine handler adapter for the current request.HandlerAdapter ha getHandlerAdapter(mappedHandler.getHandler());// Process last-modified header, if supported by the handler.String method request.getMethod();boolean isGet HttpMethod.GET.matches(method);if (isGet || HttpMethod.HEAD.matches(method)) {long lastModified ha.getLastModified(request, mappedHandler.getHandler());if (new ServletWebRequest(request, response).checkNotModified(lastModified) isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// Actually invoke the handler.mv ha.handle(processedRequest, response, mappedHandler.getHandler());if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);mappedHandler.applyPostHandle(processedRequest, response, mv);}catch (Exception ex) {dispatchException ex;}catch (Throwable err) {// As of 4.3, were processing Errors thrown from handler methods as well,// making them available for ExceptionHandler methods and other scenarios.dispatchException new NestedServletException(Handler dispatch failed, err);}processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}catch (Exception ex) {triggerAfterCompletion(processedRequest, response, mappedHandler, ex);}catch (Throwable err) {triggerAfterCompletion(processedRequest, response, mappedHandler,new NestedServletException(Handler processing failed, err));}finally {if (asyncManager.isConcurrentHandlingStarted()) {// Instead of postHandle and afterCompletionif (mappedHandler ! null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}doDispatch的大致业务流程可以使用debug模式来一步一步跟踪查看一个request请求是怎么找到对应的requestmapping的。 RequestMappingHandlerMapping保存了所有RequestMapping 和handler的映射规则。所有的请求映射都在HandlerMapping中。 SpringBoot自动配置欢迎页的 WelcomePageHandlerMapping 。访问 /能访问到index.htmlSpringBoot自动配置了默认 的 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;}2.3.2、普通参数与基本注解 2.3.2.1、注解 PathVariable 路径变量RequestHeader 获取请求头RequestParam 获取请求参数指问号后的参数url?a1b2CookieValue 获取Cookie值RequestAttribute 获取request域属性RequestBody 获取请求体[POST]MatrixVariable 矩阵变量ModelAttribute ParameterTestController.java package com.atguigu.boot.controller;import org.springframework.web.bind.annotation.;import javax.servlet.http.Cookie; import java.util.HashMap; import java.util.List; import java.util.Map;RestController public class ParameterTestController {GetMapping(/car/{id}/owner/{username})public MapString, Object getCar(PathVariable(id) Integer id,PathVariable(username) String name,PathVariable MapString, String pv,RequestHeader(User-Agent) String UserAgent,RequestHeader MapString, String header,RequestParam(age) Integer age,RequestParam(inters) ListString inters,RequestParam MapString, String params,CookieValue(Idea-b0252624) String cook,CookieValue(Idea-b0252624) Cookie cookie) {MapString, Object map new HashMap();map.put(id, id);map.put(name, name);map.put(pv, pv);map.put(User-Agent, UserAgent);map.put(header, header);map.put(age, age);map.put(inters, inters);map.put(params, params);map.put(cook, cook);map.put(cookie, cookie);return map;}PostMapping(/save)public MapString, Object postMethod(RequestBody String body) {MapString, Object map new HashMap();map.put(body, body);return map;}//1、语法 请求路径/cars/sell;low34;brandbyd,audi,yd//2、SpringBoot默认是禁用了矩阵变量的功能// 手动开启原理。对于路径的处理。UrlPathHelper进行解析。// removeSemicolonContent移除分号内容支持矩阵变量的//3、矩阵变量必须有url路径变量才能被解析GetMapping(/cars/{path})public Map carsSell(MatrixVariable(low) Integer low,MatrixVariable(brand) ListString brand,PathVariable(path) String path){MapString,Object map new HashMap();map.put(low,low);map.put(brand,brand);map.put(path,path);return map;} } RequestController.java package com.atguigu.boot.controller;import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestAttribute; import org.springframework.web.bind.annotation.ResponseBody;import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map;Controller public class RequestController {GetMapping(goto)public String goToPage(HttpServletRequest httpServletRequest) {httpServletRequest.setAttribute(msg, 成功了…);httpServletRequest.setAttribute(code, 200);return forward:/success;}ResponseBodyGetMapping(/success)public Map success(RequestAttribute(msg) String msg,RequestAttribute(code) Integer code,HttpServletRequest httpServletRequest) {MapString, Object map new HashMap();map.put(msg, msg);map.put(code, code);Object msg1 httpServletRequest.getAttribute(msg);Object code1 httpServletRequest.getAttribute(code);map.put(httpgetmsg, msg1);map.put(httpgetcode, code1);return map;}} WebConfig.java package com.atguigu.boot.config;import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.filter.HiddenHttpMethodFilter; import org.springframework.web.servlet.config.annotation.PathMatchConfigurer; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; import org.springframework.web.util.UrlPathHelper;Configuration(proxyBeanMethods false) public class WebConfig /implements WebMvcConfigurer/ {// Bean // public HiddenHttpMethodFilter hiddenHttpMethodFilter() { // HiddenHttpMethodFilter hiddenHttpMethodFilter new HiddenHttpMethodFilter(); // hiddenHttpMethodFilter.setMethodParam(_m); // return hiddenHttpMethodFilter; // } // Override // public void configurePathMatch(PathMatchConfigurer configurer) { // // UrlPathHelper urlPathHelper new UrlPathHelper(); // urlPathHelper.setRemoveSemicolonContent(false); // 不移除;后面的内容 // configurer.setUrlPathHelper(urlPathHelper); // // }// SpringBoot默认是禁用了矩阵变量的功能// 手动开启原理。对于路径的处理。UrlPathHelper进行解析。// removeSemicolonContent移除分号内容支持矩阵变量的// 可以使用重写方法的模式也可以使用增加组件的方式来修改Beanpublic WebMvcConfigurer webMvcConfigurer() {return new WebMvcConfigurer() {Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {UrlPathHelper urlPathHelper new UrlPathHelper();urlPathHelper.setRemoveSemicolonContent(false);configurer.setUrlPathHelper(urlPathHelper);}};} } 测试结果 2.3.2.2、Servlet API WebRequest、ServletRequest、MultipartRequest、 HttpSession、javax.servlet.http.PushBuilder、Principal、InputStream、Reader、HttpMethod、Locale、TimeZone、ZoneId ServletRequestMethodArgumentResolver 以上的部分参数 Overridepublic boolean supportsParameter(MethodParameter parameter) {Class? paramType parameter.getParameterType();return (WebRequest.class.isAssignableFrom(paramType) ||ServletRequest.class.isAssignableFrom(paramType) ||MultipartRequest.class.isAssignableFrom(paramType) ||HttpSession.class.isAssignableFrom(paramType) ||(pushBuilder ! null pushBuilder.isAssignableFrom(paramType)) ||Principal.class.isAssignableFrom(paramType) ||InputStream.class.isAssignableFrom(paramType) ||Reader.class.isAssignableFrom(paramType) ||HttpMethod.class paramType ||Locale.class paramType ||TimeZone.class paramType ||ZoneId.class paramType);}2.4.2.3、复杂参数 Map、Modelmap、model里面的数据会被放在request的请求域 request.setAttribute、Errors/BindingResult、RedirectAttributes 重定向携带数据、ServletResponseresponse、SessionStatus、UriComponentsBuilder、ServletUriComponentsBuilder MapString,Object map, Model model, HttpServletRequest request 都是可以给request域中放数据 request.getAttribute();Map、Model类型的参数会返回 mavContainer.getModel— BindingAwareModelMap 是Model 也是Map mavContainer.getModel(); 获取到值的 2.4.2.4、自定义对象参数 可以自动类型转换与格式化可以级联封装。 /*** 姓名 input nameuserName/ br/* 年龄 input nameage/ br/* 生日 input namebirth/ br/* 宠物姓名input namepet.name/br/* 宠物年龄input namepet.age// Data public class Person {private String userName;private Integer age;private Date birth;private Pet pet;}Data public class Pet {private String name;private String age;} 2.3.3、POJO封装过程 ServletModelAttributeMethodProcessor 2.3.4、参数处理原理 HandlerMapping中找到能处理请求的HandlerController.method()为当前Handler 找一个适配器 HandlerAdapter RequestMappingHandlerAdapter适配器执行目标方法并确定方法参数的每一个值 2.3.4.1、HandlerAdapter 0 - 支持方法上标注RequestMapping 1 - 支持函数式编程的 … 2.3.4.2、执行目标方法 // Actually invoke the handler. //DispatcherServlet – doDispatch mv ha.handle(processedRequest, response, mappedHandler.getHandler());mav invokeHandlerMethod(request, response, handlerMethod); //执行目标方法//ServletInvocableHandlerMethod Object returnValue invokeForRequest(webRequest, mavContainer, providedArgs); //获取方法的参数值 Object[] args getMethodArgumentValues(request, mavContainer, providedArgs); 2.3.4.3、参数解析器-HandlerMethodArgumentResolver 确定将要执行的目标方法的每一个参数的值是什么; SpringMVC目标方法能写多少种参数类型。取决于参数解析器。
当前解析器是否支持解析这种参数支持就调用 resolveArgument 2.3.4.4、返回值处理器 2.3.4.5、如何确定目标方法每一个参数的值 InvocableHandlerMethod.java protected Object[] getMethodArgumentValues(NativeWebRequest request, Nullable ModelAndViewContainer mavContainer,Object… providedArgs) throws Exception {MethodParameter[] parameters getMethodParameters();if (ObjectUtils.isEmpty(parameters)) {return EMPTY_ARGS;}Object[] args new Object[parameters.length];for (int i 0; i parameters.length; i) {MethodParameter parameter parameters[i];parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);args[i] findProvidedArgument(parameter, providedArgs);if (args[i] ! null) {continue;}if (!this.resolvers.supportsParameter(parameter)) {throw new IllegalStateException(formatArgumentError(parameter, No suitable resolver));}try {args[i] this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);}catch (Exception ex) {// Leave stack trace for later, exception may actually be resolved and handled…if (logger.isDebugEnabled()) {String exMsg ex.getMessage();if (exMsg ! null !exMsg.contains(parameter.getExecutable().toGenericString())) {logger.debug(formatArgumentError(parameter, exMsg));}}throw ex;}}return args;}挨个判断所有参数解析器那个支持解析这个参数 Nullableprivate HandlerMethodArgumentResolver getArgumentResolver(MethodParameter parameter) {HandlerMethodArgumentResolver result this.argumentResolverCache.get(parameter);if (result null) {for (HandlerMethodArgumentResolver resolver : this.argumentResolvers) {if (resolver.supportsParameter(parameter)) {result resolver;this.argumentResolverCache.put(parameter, result);break;}}}return result;}解析这个参数的值 调用各自 HandlerMethodArgumentResolver 的 resolveArgument 方法即可自定义类型参数 封装POJO ServletModelAttributeMethodProcessor 这个参数处理器支持 是否为简单类型。 public static boolean isSimpleValueType(Class? type) {return (Void.class ! type void.class ! type (ClassUtils.isPrimitiveOrWrapper(type) ||Enum.class.isAssignableFrom(type) ||CharSequence.class.isAssignableFrom(type) ||Number.class.isAssignableFrom(type) ||Date.class.isAssignableFrom(type) ||Temporal.class.isAssignableFrom(type) ||URI.class type ||URL.class type ||Locale.class type ||Class.class type));}OverrideNullablepublic final Object resolveArgument(MethodParameter parameter, Nullable ModelAndViewContainer mavContainer,NativeWebRequest webRequest, Nullable WebDataBinderFactory binderFactory) throws Exception {Assert.state(mavContainer ! null, ModelAttributeMethodProcessor requires ModelAndViewContainer);Assert.state(binderFactory ! null, ModelAttributeMethodProcessor requires WebDataBinderFactory);String name ModelFactory.getNameForParameter(parameter);ModelAttribute ann parameter.getParameterAnnotation(ModelAttribute.class);if (ann ! null) {mavContainer.setBinding(name, ann.binding());}Object attribute null;BindingResult bindingResult null;if (mavContainer.containsAttribute(name)) {attribute mavContainer.getModel().get(name);}else {// Create attribute instancetry {attribute createAttribute(name, parameter, binderFactory, webRequest);}catch (BindException ex) {if (isBindExceptionRequired(parameter)) {// No BindingResult parameter - fail with BindExceptionthrow ex;}// Otherwise, expose null/empty value and associated BindingResultif (parameter.getParameterType() Optional.class) {attribute Optional.empty();}bindingResult ex.getBindingResult();}}if (bindingResult null) {// Bean property binding and validation;// skipped in case of binding failure on construction.WebDataBinder binder binderFactory.createBinder(webRequest, attribute, name);if (binder.getTarget() ! null) {if (!mavContainer.isBindingDisabled(name)) {bindRequestParameters(binder, webRequest);}validateIfApplicable(binder, parameter);if (binder.getBindingResult().hasErrors() isBindExceptionRequired(binder, parameter)) {throw new BindException(binder.getBindingResult());}}// Value type adaptation, also covering java.util.Optionalif (!parameter.getParameterType().isInstance(attribute)) {attribute binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);}bindingResult binder.getBindingResult();}// Add resolved attribute and BindingResult at the end of the modelMapString, Object bindingResultModel bindingResult.getModel();mavContainer.removeAttributes(bindingResultModel);mavContainer.addAllAttributes(bindingResultModel);return attribute;}WebDataBinder binder binderFactory.createBinder(webRequest, attribute, name); WebDataBinder :web数据绑定器将请求参数的值绑定到指定的JavaBean里面 WebDataBinder 利用它里面的 Converters 将请求数据转成指定的数据类型。再次封装到JavaBean中 GenericConversionService在设置每一个值的时候找它里面的所有converter那个可以将这个数据类型request带来参数的字符串转换到指定的类型JavaBean – Integer byte – file FunctionalInterfacepublic interface ConverterS, T 未来我们可以给WebDataBinder里面放自己的Converter private static final class StringToNumber implements ConverterString, T 自定义 Converter //1、WebMvcConfigurer定制化SpringMVC的功能Beanpublic WebMvcConfigurer webMvcConfigurer(){return new WebMvcConfigurer() {Overridepublic void configurePathMatch(PathMatchConfigurer configurer) {UrlPathHelper urlPathHelper new UrlPathHelper();// 不移除后面的内容。矩阵变量功能就可以生效urlPathHelper.setRemoveSemicolonContent(false);configurer.setUrlPathHelper(urlPathHelper);}Overridepublic void addFormatters(FormatterRegistry registry) {registry.addConverter(new ConverterString, Pet() {Overridepublic Pet convert(String source) {// 啊猫,3if(!StringUtils.isEmpty(source)){Pet pet new Pet();String[] split source.split(,);pet.setName(split[0]);pet.setAge(Integer.parseInt(split[1]));return pet;}return null;}});}};}2.3.4.6、目标方法执行完成 将所有的数据都放在 ModelAndViewContainer包含要去的页面地址View。还包含Model数据。
2.3.4.7、处理派发结果 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); renderMergedOutputModel(mergedModel, getRequestToExpose(request), response); InternalResourceView Overrideprotected void renderMergedOutputModel(MapString, Object model, HttpServletRequest request, HttpServletResponse response) throws Exception {// Expose the model object as request attributes.exposeModelAsRequestAttributes(model, request);// Expose helpers as request attributes, if any.exposeHelpers(request);// Determine the path for the request dispatcher.String dispatcherPath prepareForRendering(request, response);// Obtain a RequestDispatcher for the target resource (typically a JSP).RequestDispatcher rd getRequestDispatcher(request, dispatcherPath);if (rd null) {throw new ServletException(Could not get RequestDispatcher for [ getUrl() ]: Check that the corresponding file exists within your web application archive!);}// If already included or response already committed, perform include, else forward.if (useInclude(request, response)) {response.setContentType(getContentType());if (logger.isDebugEnabled()) {logger.debug(Including [ getUrl() ]);}rd.include(request, response);}else {// Note: The forwarded resource is supposed to determine the content type itself.if (logger.isDebugEnabled()) {logger.debug(Forwarding to [ getUrl() ]);}rd.forward(request, response);}}暴露模型作为请求域属性 // Expose the model object as request attributes.exposeModelAsRequestAttributes(model, request);protected void exposeModelAsRequestAttributes(MapString, Object model,HttpServletRequest request) throws Exception {//model中的所有数据遍历挨个放在请求域中model.forEach((name, value) - {if (value ! null) {request.setAttribute(name, value);}else {request.removeAttribute(name);}});}2.4、响应数据与内容协商 2.4.1、响应JSON 2.4.1.1、jackson.jarResponseBody dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId/dependency!–web场景自动引入了json场景–dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-json/artifactIdversion2.3.4.RELEASE/versionscopecompile/scope/dependency给前端自动返回json数据 返回值解析器 try {this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);}Overridepublic void handleReturnValue(Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {HandlerMethodReturnValueHandler handler selectHandler(returnValue, returnType);if (handler null) {throw new IllegalArgumentException(Unknown return value type: returnType.getParameterType().getName());}handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);}RequestResponseBodyMethodProcessor Overridepublic void handleReturnValue(Nullable Object returnValue, MethodParameter returnType,ModelAndViewContainer mavContainer, NativeWebRequest webRequest)throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {mavContainer.setRequestHandled(true);ServletServerHttpRequest inputMessage createInputMessage(webRequest);ServletServerHttpResponse outputMessage createOutputMessage(webRequest);// Try even with null return value. ResponseBodyAdvice could get involved.// 使用消息转换器进行写出操作writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);}返回值解析器原理 1、返回值处理器判断是否支持这种类型返回值 supportsReturnType 2、返回值处理器调用 handleReturnValue 进行处理 3、RequestResponseBodyMethodProcessor 可以处理返回值标了ResponseBody 注解的。 利用 MessageConverters 进行处理 将数据写为json 1、内容协商浏览器默认会以请求头的方式告诉服务器他能接受什么样的内容类型2、服务器最终根据自己自身的能力决定服务器能生产出什么样内容类型的数据3、SpringMVC会挨个遍历所有容器底层的 HttpMessageConverter 看谁能处理 1、得到MappingJackson2HttpMessageConverter可以将对象写为json2、利用MappingJackson2HttpMessageConverter将对象转为json再写出去。 2.4.1.2、SpringMVC到底支持哪些返回值 可以查看对应类中方法判断了哪些类型的返回值
2.4.1.3、HTTPMessageConverter原理 MessageConverter规范 HttpMessageConverter: 看是否支持将 此 Class类型的对象转为MediaType类型的数据。 例子Person对象转为JSON。或者 JSON转为Person 默认的MessageConverter 0 - 只支持Byte类型的 1 - String 2 - String 3 - Resource 4 - ResourceRegion 5 - DOMSource.class \ SAXSource.class) \ StAXSource.class \StreamSource.class \Source.class 6 - MultiValueMap 7 - true 8 - true 9 - 支持注解方式xml处理的。 最终 MappingJackson2HttpMessageConverter 把对象转为JSON利用底层的jackson的objectMapper转换的
2.4.2、内容协商 根据客户端接收能力的不同返回不同没提类型的数据。 2.4.2.1、引入依赖 dependencygroupIdcom.fasterxml.jackson.dataformat/groupIdartifactIdjackson-dataformat-xml/artifactId /dependency测试结果
注意导入依赖后一定要让依赖生效 2.4.2.2、postman分别测试返回json和xml 只需要改变请求头中Accept字段。Http协议中规定的告诉服务器本客户端可以接收的数据类型。
2.4.2.3、开启浏览器参数方式内容协商功能 spring:contentnegotiation:favor-parameter: true #开启请求参数内容协商模式发请求 http://localhost:8080/test/person?formatjson http://localhost:8080/test/person?formatxml 确定客户端接收什么样的内容类型 1、Parameter策略优先确定是要返回json数据获取请求头中的format的值 2、最终进行内容协商返回给客户端json即可。 2.4.2.4、内容协商原理 1、判断当前响应头中是否已经有确定的媒体类型。MediaType 2、获取客户端PostMan、浏览器支持接收的内容类型。获取客户端Accept请求头字段 【application/xml】 contentNegotiationManager 内容协商管理器 默认使用基于请求头的策略 HeaderContentNegotiationStrategy 确定客户端可以接收的内容类型 3、遍历循环所有当前系统的 MessageConverter看谁支持操作这个对象Person 4、找到支持操作Person的converter把converter支持的媒体类型统计出来。 5、客户端需要【application/xml】。服务端能力【10种、json、xml】 6、进行内容协商的最佳匹配媒体类型 7、用 支持 将对象转为 最佳匹配媒体类型 的converter。调用它进行转化 。 导入了jackson处理xml的包xml的converter就会自动进来 //WebMvcConfigurationSupport jackson2XmlPresent ClassUtils.isPresent(com.fasterxml.jackson.dataformat.xml.XmlMapper, classLoader);if (jackson2XmlPresent) {Jackson2ObjectMapperBuilder builder Jackson2ObjectMapperBuilder.xml();if (this.applicationContext ! null) {builder.applicationContext(this.applicationContext);}messageConverters.add(new MappingJackson2XmlHttpMessageConverter(builder.build()));}2.4.2.5、自定义MessageConverter 实现多协议数据兼容。json、xml、x-guigu 0、ResponseBody 响应数据出去 调用 RequestResponseBodyMethodProcessor 处理 1、Processor 处理方法返回值。通过 MessageConverter 处理 2、所有 MessageConverter 合起来可以支持各种媒体类型数据的操作读、写 3、内容协商找到最终的 messageConverter 要改变SpringMVC的什么功能。都要从一个入口添加给容器中添加一个 WebMvcConfigurer Beanpublic WebMvcConfigurer webMvcConfigurer(){return new WebMvcConfigurer() {Overridepublic void extendMessageConverters(ListHttpMessageConverter? converters) {converters.add(new GuiguMessageConverter());}}}package com.atguigu.boot.converter;import com.atguigu.boot.bean.Person; import org.springframework.http.HttpInputMessage; import org.springframework.http.HttpOutputMessage; import org.springframework.http.MediaType; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotWritableException;import java.io.IOException; import java.io.OutputStream; import java.util.List;/**
自定义的Converter/ public class GuiguMessageConverter implements HttpMessageConverterPerson {Overridepublic boolean canRead(Class? clazz, MediaType mediaType) {return false;}Overridepublic boolean canWrite(Class? clazz, MediaType mediaType) {return clazz.isAssignableFrom(Person.class);}/** 服务器要统计所有MessageConverter都能写出哪些内容类型** application/x-guigu* return/Overridepublic ListMediaType getSupportedMediaTypes() {return MediaType.parseMediaTypes(application/x-guigu);}Overridepublic Person read(Class? extends Person clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {return null;}Overridepublic void write(Person person, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException {//自定义协议数据的写出String data person.getUserName();person.getAge();person.getBirth();//写出去OutputStream body outputMessage.getBody();body.write(data.getBytes());} } 有可能我们添加的自定义的功能会覆盖默认很多功能导致一些默认的功能失效。 大家考虑上述功能除了我们完全自定义外SpringBoot有没有为我们提供基于配置文件的快速修改媒体类型功能怎么配置呢【提示参照SpringBoot官方文档web开发内容协商章节】 看官方文档描述只需要进行配置即可。 2.5、视图解析与模板引擎 视图解析SpringBoot默认不支持 JSP需要引入第三方模板引擎技术实现页面渲染。 2.5.1、视图解析 2.5.1.1、视图解析原理流程 1、目标方法处理的过程中所有数据都会被放在 ModelAndViewContainer 里面。包括数据和视图地址 2、方法的参数是一个自定义类型对象从请求参数中确定的把他重新放在 ModelAndViewContainer 3、任何目标方法执行完成以后都会返回 ModelAndView数据和视图地址。 4、processDispatchResult 处理派发结果页面改如何响应 1、render(mv, request, response); 进行页面渲染逻辑 1、根据方法的String返回值得到 View 对象【定义了页面的渲染逻辑】 1、所有的视图解析器尝试是否能根据当前返回值得到View对象2、得到了 redirect:/main.html – Thymeleaf new RedirectView()3、ContentNegotiationViewResolver 里面包含了下面所有的视图解析器内部还是利用下面所有视图解析器得到视图对象。4、view.render(mv.getModelInternal(), request, response); 视图对象调用自定义的render进行页面渲染工作 RedirectView 如何渲染【重定向到一个页面】1、获取目标url地址2、response.sendRedirect(encodedURL);
视图解析 返回值以 forward: 开始 new InternalResourceView(forwardUrl); – 转发 request.getRequestDispatcher(path).forward(request, response);返回值以 redirect: 开始 new RedirectView() –》 render就是重定向返回值是普通字符串 new ThymeleafView— 自定义视图解析器自定义视图 大厂学院。 2.5.2、模板引擎-Thymeleaf 2.5.2.1、Thymeleaf简介 Thymeleaf is a modern server-side Java template engine for both web and standalone environments, capable of processing HTML, XML, JavaScript, CSS and even plain text. 现代化、服务端Java模板引擎 2.5.2.2、基本语法 1.表达式 表达式名字语法用途变量取值${…}获取请求域、session域、对象等值选择变量
{…}获取上下文对象值消息#{…}获取国际化等值链接{…}生成链接片段表达式~{…}jsp:include 作用引入公共页面片段 2.字面量 文本值: ‘one text’ , ‘Another one!’ ,…数字: 0 , 34 , 3.0 , 12.3 ,…布尔值: true , false 空值: null 变量 onetwo… 变量不能有空格 3.文本操作 字符串拼接: 变量替换: |The name is \({name}| 4.数学运算 运算符: , - , * , / , % 5.布尔运算 运算符: and , or 一元运算: ! , not 6.比较运算 比较: , , , ( gt , lt , ge , le )等式: , ! ( eq , ne ) 7.条件运算 If-then: (if) ? (then) If-then-else: (if) ? (then) : (else) Default: (value) ?: (defaultvalue) 8.特殊操作 无操作 _ 2.5.2.3、设置属性值-th:attr 设置单个值 form actionsubscribe.html th:attraction{/subscribe}fieldsetinput typetext nameemail /input typesubmit valueSubscribe! th:attrvalue#{subscribe.submit}//fieldset /form设置多个值 img src../../images/gtvglogo.png th:attrsrc{/images/gtvglogo.png},title#{logo},alt#{logo} /以上两个的代替写法 input typesubmit valueSubscribe! th:value#{subscribe.submit}/ form actionsubscribe.html th:action{/subscribe}所有h5兼容的标签写法 https://www.thymeleaf.org/doc/tutorials/3.0/usingthymeleaf.html#setting-value-to-specific-attributes 2.5.2.4、迭代 tr th:eachprod : \){prods}td th:text\({prod.name}Onions/tdtd th:text\){prod.price}2.41/tdtd th:text\({prod.inStock}? #{true} : #{false}yes/td /trtr th:eachprod,iterStat : \){prods} th:class\({iterStat.odd}? oddtd th:text\){prod.name}Onions/tdtd th:text\({prod.price}2.41/tdtd th:text\){prod.inStock}? #{true} : #{false}yes/td /tr2.5.2.5、条件运算 a hrefcomments.html th:href{/product/comments(prodId\({prod.id})} th:if\){not #lists.isEmpty(prod.comments)}view/adiv th:switch\({user.role}p th:caseadminUser is an administrator/pp th:case#{roles.manager}User is a manager/pp th:case*User is some other thing/p /div2.5.2.6、属性优先级 2.5.3、Thymeleaf的使用 2.5.3.1、引入Starter dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-thymeleaf/artifactId/dependency2.5.3.2、自动配置Thymeleaf Configuration(proxyBeanMethods false) EnableConfigurationProperties(ThymeleafProperties.class) ConditionalOnClass({ TemplateMode.class, SpringTemplateEngine.class }) AutoConfigureAfter({ WebMvcAutoConfiguration.class, WebFluxAutoConfiguration.class }) public class ThymeleafAutoConfiguration { }自动配好的策略 1、所有thymeleaf的配置值都在 ThymeleafProperties2、配置好了 SpringTemplateEngine3、配好了 ThymeleafViewResolver4、我们只需要直接开发页面 public static final String DEFAULT_PREFIX classpath:/templates/;public static final String DEFAULT_SUFFIX .html; //xxx.html2.5.3.3、页面开发 !DOCTYPE html html langen xmlns:thhttp://www.thymeleaf.org headmeta charsetUTF-8titleTitle/title /head body h1 th:text\){msg}哈哈/h1 h2a hrefwww.atguigu.com th:href\({link}去百度/a br/a hrefwww.atguigu.com th:href{link}去百度2/a /h2 /body /html2.5.4、构建后台管理系统 2.5.4.1、项目创建 thymeleaf、web-starter、devtools、lombok 2.5.4.2、静态资源处理 自动配置好我们只需要把所有静态资源放到 static 文件夹下 2.5.4.3、路径构建 th:action“{/login}” 2.5.4.4、模板抽取 th:insert/replace/include 2.5.4.5、页面跳转 PostMapping(/login)public String main(User user, HttpSession session, Model model){if(StringUtils.hasLength(user.getUserName()) 123456.equals(user.getPassword())){//把登陆成功的用户保存起来session.setAttribute(loginUser,user);//登录成功重定向到main.html; 重定向防止表单重复提交return redirect:/main.html;}else {model.addAttribute(msg,账号密码错误);//回到登录页面return login;}}2.5.4.6、数据渲染 GetMapping(/dynamic_table)public String dynamic_table(Model model){//表格内容的遍历ListUser users Arrays.asList(new User(zhangsan, 123456),new User(lisi, 123444),new User(haha, aaaaa),new User(hehe , aaddd));model.addAttribute(users,users);return table/dynamic_table;}table classdisplay table table-bordered idhidden-table-infotheadtrth#/thth用户名/thth密码/th/tr/theadtbodytr classgradeX th:eachuser,stats:\){users}td th:text\({stats.count}Trident/tdtd th:text\){user.userName}Internet/tdtd [[${user.password}]]/td/tr/tbody/table2.6、拦截器 2.6.1、HandlerInterceptor 接口 /*** 登录检查* 1、配置好拦截器要拦截哪些请求* 2、把这些配置放在容器中/ Slf4j public class LoginInterceptor implements HandlerInterceptor {/** 目标方法执行之前* param request* param response* param handler* return* throws Exception/Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String requestURI request.getRequestURI();log.info(preHandle拦截的请求路径是{},requestURI);//登录检查逻辑HttpSession session request.getSession();Object loginUser session.getAttribute(loginUser);if(loginUser ! null){//放行return true;}//拦截住。未登录。跳转到登录页request.setAttribute(msg,请先登录); // re.sendRedirect(/);request.getRequestDispatcher(/).forward(request,response);return false;}/** 目标方法执行完成以后* param request* param response* param handler* param modelAndView* throws Exception/Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {log.info(postHandle执行{},modelAndView);}/** 页面渲染以后* param request* param response* param handler* param ex* throws Exception/Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {log.info(afterCompletion执行异常{},ex);} }2.6.2、配置拦截器 /** 1、编写一个拦截器实现HandlerInterceptor接口* 2、拦截器注册到容器中实现WebMvcConfigurer的addInterceptors* 3、指定拦截规则【如果是拦截所有静态资源也会被拦截】/ Configuration public class AdminWebConfig implements WebMvcConfigurer {Overridepublic void addInterceptors(InterceptorRegistry registry) {registry.addInterceptor(new LoginInterceptor()).addPathPatterns(/) //所有请求都被拦截包括静态资源.excludePathPatterns(/,/login,/css/,/fonts/,/images/,/js/); //放行的请求} }2.6.3、拦截器原理 1、根据当前请求找到HandlerExecutionChain【可以处理请求的handler以及handler的所有 拦截器】 2、先来顺序执行 所有拦截器的 preHandle方法 2.1、如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle2.2、如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion 3、如果任何一个拦截器返回false。直接跳出不执行目标方法 4、所有拦截器都返回True。执行目标方法 5、倒序执行所有拦截器的postHandle方法。 6、前面的步骤有任何异常都会直接倒序触发 afterCompletion 7、页面成功渲染完成以后也会倒序触发 afterCompletion ’
2.7、文件上传 2.7.1、页面表单 form methodpost action/upload enctypemultipart/form-datainput typefile namefilebrinput typesubmit value提交 /form2.7.2、文件上传代码 /
MultipartFile 自动封装上传过来的文件* param email* param username* param headerImg* param photos* return/PostMapping(/upload)public String upload(RequestParam(email) String email,RequestParam(username) String username,RequestPart(headerImg) MultipartFile headerImg,RequestPart(photos) MultipartFile[] photos) throws IOException {log.info(上传的信息email{}username{}headerImg{}photos{},email,username,headerImg.getSize(),photos.length);if(!headerImg.isEmpty()){//保存到文件服务器OSS服务器String originalFilename headerImg.getOriginalFilename();headerImg.transferTo(new File(H:\cache\originalFilename));}if(photos.length 0){for (MultipartFile photo : photos) {if(!photo.isEmpty()){String originalFilename photo.getOriginalFilename();photo.transferTo(new File(H:\cache\originalFilename));}}}return main;} 2.7.3、自动配置原理 文件上传自动配置类-MultipartAutoConfiguration-MultipartProperties 自动配置好了 StandardServletMultipartResolver 【文件上传解析器】原理步骤 1、请求进来使用文件上传解析器判断isMultipart并封装resolveMultipart返回MultipartHttpServletRequest文件上传请求2、参数解析器来解析请求中的文件内容封装成MultipartFile3、将request中文件信息封装为一个MapMultiValueMapString, MultipartFile
FileCopyUtils。实现文件流的拷贝 PostMapping(/upload)public String upload(RequestParam(email) String email,RequestParam(username) String username,RequestPart(headerImg) MultipartFile headerImg,RequestPart(photos) MultipartFile[] photos)2.8、异常处理 2.8.1、错误处理 1.默认规则 默认情况下Spring Boot提供/error处理所有错误的映射对于机器客户端它将生成JSON响应其中包含错误HTTP状态和异常消息的详细信息。对于浏览器客户端响应一个“ whitelabel”错误视图以HTML格式呈现相同的数据 要对其进行自定义添加View解析为error要完全替换默认行为可以实现 ErrorController 并注册该类型的Bean定义或添加ErrorAttributes类型的组件以使用现有机制但替换其内容error/下的4xx5xx页面会被自动解析
2.定制错误处理逻辑 自定义错误页 error/404.html error/5xx.html有精确的错误状态码页面就匹配精确没有就找 4xx.html如果都没有就触发白页 ControllerAdviceExceptionHandler处理全局异常底层是 ExceptionHandlerExceptionResolver 支持的ResponseStatus自定义异常 底层是 ResponseStatusExceptionResolver 把responsestatus注解的信息底层调用 response.sendError(statusCode, resolvedReason)tomcat发送的/errorSpring底层的异常如 参数类型转换异常DefaultHandlerExceptionResolver 处理框架底层的异常 response.sendError(HttpServletResponse.SC_BAD_REQUEST, ex.getMessage()); 自定义实现 HandlerExceptionResolver 处理异常可以作为默认的全局异常处理规则 ErrorViewResolver 实现自定义处理异常 response.sendError 。error请求就会转给controller你的异常没有任何人能处理。tomcat底层 response.sendError。error请求就会转给controllerbasicErrorController 要去的页面地址是 ErrorViewResolver
3.异常处理自动配置原理 ErrorMvcAutoConfiguration 自动配置异常处理规则 容器中的组件类型DefaultErrorAttributes - iderrorAttributes public class DefaultErrorAttributes implements ErrorAttributes, HandlerExceptionResolverDefaultErrorAttributes定义错误页面中可以包含哪些数据 容器中的组件类型BasicErrorController – idbasicErrorControllerjson白页 适配响应 处理默认 /error 路径的请求页面响应 new ModelAndView(“error”, model)容器中有组件 View-id是error响应默认错误页容器中放组件 BeanNameViewResolver视图解析器按照返回的视图名作为组件的id去容器中找View对象。 容器中的组件类型DefaultErrorViewResolver - idconventionErrorViewResolver 如果发生错误会以HTTP的状态码 作为视图页地址viewName找到真正的页面error/404、5xx.html 如果想要返回页面就会找error视图【StaticView】。(默认是一个白页) 错误页 4.异常处理步骤流程 执行目标方法目标方法运行期间有任何异常都会被catch、而且标志当前请求结束并且用 dispatchException进入视图解析流程页面渲染 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);mv processHandlerException处理handler发生的异常处理完成返回ModelAndView 遍历所有的 handlerExceptionResolvers看谁能处理当前异常【HandlerExceptionResolver处理器异常解析器】系统默认的 异常解析器 DefaultErrorAttributes先来处理异常。把异常信息保存到rrequest域并且返回null默认没有任何人能处理异常所以异常会被抛出 如果没有任何人能处理最终底层就会发送 /error 请求。会被底层的BasicErrorController处理解析错误视图遍历所有的 ErrorViewResolver 看谁能解析 默认的 DefaultErrorViewResolver ,作用是把响应状态码作为错误页的地址error/500.html模板引擎最终响应这个页面 error/500.html
2.9、原生组件注入Servlet、Filter、Listener 2.9.1、使用Servlet API ServletComponentScan(basePackages “com.atguigu.admin”) :指定原生Servlet组件都放在那里 WebServlet(urlPatterns “/my”)效果直接响应没有经过Spring的拦截器 WebFilter(urlPatterns{“/css/“,”/images/”}) WebListener 推荐可以这种方式 扩展DispatchServlet 如何注册进来 容器中自动配置了 DispatcherServlet 属性绑定到 WebMvcProperties对应的配置文件配置项是 spring.mvc。通过 ServletRegistrationBean 把 DispatcherServlet 配置进来。默认映射的是 / 路径。 Tomcat-Servlet 多个Servlet都能处理到同一层路径精确优选原则 2.9.1、使用RegistrationBean ServletRegistrationBean, FilterRegistrationBean, and ServletListenerRegistrationBean Configuration public class MyRegistConfig {Beanpublic ServletRegistrationBean myServlet(){MyServlet myServlet new MyServlet();return new ServletRegistrationBean(myServlet,/my,/my02);}Beanpublic FilterRegistrationBean myFilter(){MyFilter myFilter new MyFilter(); // return new FilterRegistrationBean(myFilter,myServlet());FilterRegistrationBean filterRegistrationBean new FilterRegistrationBean(myFilter);filterRegistrationBean.setUrlPatterns(Arrays.asList(/my,/css/
));return filterRegistrationBean;}Beanpublic ServletListenerRegistrationBean myListener(){MySwervletContextListener mySwervletContextListener new MySwervletContextListener();return new ServletListenerRegistrationBean(mySwervletContextListener);} }2.10、嵌入式Web容器 2.10.1、切换嵌入式Servlet容器 默认支持的webServer Tomcat, Jetty, or UndertowServletWebServerApplicationContext 容器启动寻找ServletWebServerFactory 并引导创建服务器 切换服务器
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactIdexclusionsexclusiongroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-tomcat/artifactId/exclusion/exclusions /dependency原理 SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcatweb应用会创建一个web版的ioc容器 ServletWebServerApplicationContextServletWebServerApplicationContext 启动的时候寻找 ServletWebServerFactoryServlet 的web服务器工厂— Servlet 的web服务器SpringBoot底层默认有很多的WebServer工厂TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory底层直接会有一个自动配置类。ServletWebServerFactoryAutoConfigurationServletWebServerFactoryAutoConfiguration导入了ServletWebServerFactoryConfiguration配置类ServletWebServerFactoryConfiguration 配置类 根据动态判断系统中到底导入了那个Web服务器的包。默认是web-starter导入tomcat包容器中就有 TomcatServletWebServerFactoryTomcatServletWebServerFactory 创建出Tomcat服务器并启动TomcatWebServer 的构造器拥有初始化方法initialize—this.tomcat.start();内嵌服务器就是手动把启动服务器的代码调用tomcat核心jar包存在
2.10.2、定制Servlet容器 实现 WebServerFactoryCustomizer 把配置文件的值和ServletWebServerFactory 进行绑定 修改配置文件 server.xxx直接自定义 ConfigurableServletWebServerFactory xxxxxCustomizer定制化器可以改变xxxx的默认规则 import org.springframework.boot.web.server.WebServerFactoryCustomizer; import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory; import org.springframework.stereotype.Component;Component public class CustomizationBean implements WebServerFactoryCustomizerConfigurableServletWebServerFactory {Overridepublic void customize(ConfigurableServletWebServerFactory server) {server.setPort(9000);}}2.11、定制化原理 2.11.1、定制化的常见方式 修改配置文件; xxxxxCustomizer; 编写自定义的配置类 xxxConfiguration Bean替换、增加容器中默认组件视图解析器 Web应用 编写一个配置类实现 WebMvcConfigurer 即可定制化web功能 Bean给容器中再扩展一些组件 Configuration public class AdminWebConfig implements WebMvcConfigurerEnableWebMvc WebMvcConfigurer —— Bean 可以全面接管SpringMVC所有规则全部自己重新配置 实现定制和扩展功能 原理 1、WebMvcAutoConfiguration 默认的SpringMVC的自动配置功能类。静态资源、欢迎页…2、一旦使用 EnableWebMvc 、。会 Import(DelegatingWebMvcConfiguration.class)3、DelegatingWebMvcConfiguration 的 作用只保证SpringMVC最基本的使用 把所有系统中的 WebMvcConfigurer 拿过来。所有功能的定制都是这些 WebMvcConfigurer 合起来一起生效自动配置了一些非常底层的组件。RequestMappingHandlerMapping、这些组件依赖的组件都是从容器中获取public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport 4、WebMvcAutoConfiguration 里面的配置要能生效 必须 ConditionalOnMissingBean(WebMvcConfigurationSupport.class)5、EnableWebMvc 导致了 WebMvcAutoConfiguration 没有生效。
2.11.2、原理分析套路 场景starter - xxxxAutoConfiguration - 导入xxx组件 - 绑定xxxProperties – 绑定配置文件项