文章目录
二 Web开发
(接上文)
2.7 文件上传
- 页面
<form method="post" action="/upload" enctype="multipart/form-data">
<input type="file" name="file"><br>
<input type="submit" value="提交">
</form>
- java
/**
* MultipartFile 自动封装上传过来的文件
*/
@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服务器; 使用SpringBoot之后,上传功能也如此精简了
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";
}
- 自动配置原理
文件上传自动配置类-MultipartAutoConfiguration-MultipartProperties
- 自动配置好了
StandardServletMultipartResolver
【文件上传解析器】 - 原理步骤
- 1.请求进来使用文件上传解析器判断(
isMultipart
)并封装(resolveMultipart
,返回MultipartHttpServletRequest
)文件上传请求 - 2.参数解析器解析请求中的文件内容封装成
MultipartFile
- 3.将request中文件信息封装为一个Map;MultiValueMap<String, MultipartFile>
- 4.使用
FileCopyUtils
实现文件流的拷贝
- 1.请求进来使用文件上传解析器判断(
@PostMapping("/upload")
public String upload(@RequestParam("email") String email,
@RequestParam("username") String username,
@RequestPart("headerImg") MultipartFile headerImg,
@RequestPart("photos") MultipartFile[] photos)
2.8 错误处理 (TODO)
1、默认规则
- 默认情况下,Spring Boot提供/error处理所有错误的映射
- 对于机器客户端,它将生成JSON响应,其中包含错误,HTTP状态和异常消息的详细信息。
- 对于浏览器客户端,响应一个“ whitelabel”错误视图,以HTML格式呈现相同的数据
2.9 Web原生组件注入(Servlet、Filter、Listener)
第一种方式: 使用Servlet API (推荐)
@ServletComponentScan(basePackages = "com.atguigu.admin")
:指定原生Servlet组件都放在那里@WebServlet(urlPatterns = "/my")
:效果:直接响应,没有经过Spring的拦截器?@WebFilter(urlPatterns={"/css/*","/images/*"})
@WebListener
第二种方式: 使用XXRegistrationBean
//注意:保证依赖的组件始终是单实例的!!!
// 十分重要!!!
@Configuration(proxyBeanMethods = true)
public class ServletConfiguration {
@Bean
public ServletRegistrationBean<MyServlet> servletRegistrationBean() {
return new ServletRegistrationBean<>(new MyServlet(), "/myServlet2");
}
@Bean
public FilterRegistrationBean<MyFilter> filterFilterRegistrationBean() {
MyFilter myFilter = new MyFilter();
FilterRegistrationBean<MyFilter> bean = new FilterRegistrationBean<MyFilter>();
bean.setFilter(myFilter);
bean.setUrlPatterns(Collections.singletonList("/myFilter2"));
return bean;
}
@Bean
public ServletListenerRegistrationBean<MyListener> servletListenerRegistrationBean() {
return new ServletListenerRegistrationBean<>(new MyListener());
}
}
扩展: DispatchServlet 如何注册进来
- 容器中自动配置了
DispatcherServlet
属性绑定到WebMvcProperties
;对应的配置文件配置项是spring.mvc
。 - 通过
ServletRegistrationBean<DispatcherServlet>
把DispatcherServlet
配置进来。 - 默认映射的是 / 路径
Tomcat-Servlet
多个Servlet都能处理到同一层路径,精确匹配原则,比如
A: /my/
B: /my/1
因此, 当同时存在 /my 和 /my/1 的URL 时, /my1 会首先命中; 这就意味着 下图中的 /my 会由Tomcat处理, 而 不会经过 dispatcherServlet, 这会让 /my不能被Spring捕获,那些拦截器可能会不起作用
2.10 servlet web server
2.10.1 如何切换
- 默认支持的webServer
- Tomcat, Jetty, or Undertow
ServletWebServerApplicationContext
容器启动寻找ServletWebServerFactory
并引导创建服务器
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
2.10.2 嵌入式servlet web server启动原理
- SpringBoot应用启动发现当前是Web应用。web场景包-导入tomcat starter
- web应用会创建一个web版的ioc容器
ServletWebServerApplicationContext
ServletWebServerApplicationContext
启动的时候寻找ServletWebServerFactory
(Servlet 的web服务器工厂—> Servlet 的web服务器)- SpringBoot底层默认有很多的WebServer工厂:
TomcatServletWebServerFactory, JettyServletWebServerFactory, or UndertowServletWebServerFactory
- 底层直接会有一个自动配置类:
ServletWebServerFactoryAutoConfiguration
ServletWebServerFactoryAutoConfiguration
导入了ServletWebServerFactoryConfiguration
(配置类)ServletWebServerFactoryConfiguration
配置类 根据动态判断系统中到底导入了那个Web服务器的包。(默认是web-starter导入tomcat包),容器中就有TomcatServletWebServerFactory
TomcatServletWebServerFactory
创建出Tomcat服务器并启动;TomcatWebServer
的构造器拥有初始化方法initialize
—this.tomcat.start()
;- 内嵌服务器,就是手动把启动服务器的代码调用(tomcat核心jar包存在)
2.10.3 如何定制自己的Servlet Web
- 实现
WebServerFactoryCustomizer<ConfigurableServletWebServerFactory>
- 把配置文件的值和
ServletWebServerFactory
进行绑定
- 把配置文件的值和
- 修改配置文件 server.xxx
- 直接自定义
ConfigurableServletWebServerFactory
xxxxxCustomizer
:定制化器,可以改变xxxx的默认规则.
@Component
public class CustomizationBean implements WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> {
@Override
public void customize(ConfigurableServletWebServerFactory server) {
server.setPort(9000);
}
}
2.11 ServletWebServer
定制原理
2.11.1 定制化的常见方式
- 方式一:修改配置文件
- 方式二:
xxxxxCustomizer
- 方式三: 编写自定义的配置类
xxxConfiguration
+@Bean
替换、增加容器中默认组件;视图解析器 - Web应用 编写一个配置类实现
WebMvcConfigurer
即可定制化web功能 +@Bean
给容器中再扩展一些组件
@Configuration
public class AdminWebConfig implements WebMvcConfigurer
@EnableWebMvc + WebMvcConfigurer
——@Bean
可以全面接管SpringMVC,所有规则全部自己重新配置;实现定制和扩展功能; 原理如下:- 1、
WebMvcAutoConfiguration
默认的SpringMVC的自动配置功能类。静态资源、欢迎页… - 2、一旦使用
@EnableWebMvc
会@Import(DelegatingWebMvcConfiguration.class)
- 3、
DelegatingWebMvcConfiguration
的只保证SpringMVC最基本的使用, 不会把静态资源的处理也加上. 它会:- 把系统所有的
WebMvcConfigurer
(不管是一个类多个@Bean, 还是多个类)拿过来。所有功能的定制都是这些WebMvcConfigurer
合起来一起生效 - 自动配置了一些非常底层的组件,
RequestMappingHandlerMapping
这些组件依赖的组件都是从容器中获取 public class DelegatingWebMvcConfiguration extends WebMvcConfigurationSupport
- 把系统所有的
- 4、WebMvcAutoConfiguration 里面的配置要能生效 必须
@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)
- 5、
@EnableWebMvc
会导致WebMvcAutoConfiguration
不生效。
- 1、
2.11.2 原理分析套路
场景starter - xxxxAutoConfiguration
- 导入xxx组件 - 绑定xxxProperties
– 绑定配置文件项