目录
学习springmvc和springboot的自动配置我们必须对springmvc的组件足够了解,起码知道怎么用。Springmvc的组件基本都被springboot来做了自动的配置。
1. Springmvc的自动解管理
- 中央转发器(DispatcherServlet)
- 控制器
- 视图解析器
- 静态资源访问
- 消息转换器
- 格式化
- 静态资源管理
1.1 中央转发器
Xml无需配置
<servlet> <servlet-name>chapter2</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>chapter2</servlet-name> <url-pattern>/</url-pattern> </servlet-mapping>
中央转发器被springboot自动接管,不再需要我们在web.xml中配置,我们现在的项目也不是web项目,也不存在web.xml,
org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration,\
(双击shift键即可查找)
1.2 控制器
控制器Controller在springboot的注解扫描范围内自动管理。
1.3 视图解析器自动管理
Inclusion of ContentNegotiatingViewResolver and BeanNameViewResolver beans.
ContentNegotiatingViewResolver:组合所有的视图解析器的;
曾经的配置文件无需再配
<bean id="de" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/jsp/"></property> <property name="suffix" value="*.jsp"></property> </bean>
源码:
当我们做文件上传的时候我们也会发现multipartResolver是自动被配置好的
实现文件上传
页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input name="pic" type="file">
<input type="submit">
</form>
</body>
</html>
Controller
@RequestMapping("/img")
public String upload(){
return "upload";
}
package com.qcby.controller;
import org.junit.platform.commons.logging.Logger;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.multipart.MultipartFile;
import java.util.logging.*;
import javax.servlet.http.HttpServletRequest;
import java.io.FileOutputStream;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.UUID;
import org.slf4j.LoggerFactory;
@Controller
public class UploadController {
private static final org.slf4j.Logger logger = LoggerFactory.getLogger(UploadController.class);
@RequestMapping("/upload")
public String upload(@RequestParam("pic") MultipartFile file, HttpServletRequest request) {
if (file.isEmpty()) {
logger.error("上传的文件为空");
return "upload";
}
String contentType = file.getContentType();
String originalFileName = file.getOriginalFilename();
logger.info("fileName--> {}", originalFileName);
logger.info("getContentType--> {}", contentType);
// 生成唯一文件名,避免文件覆盖
String uniqueFileName = generateUniqueFileName(originalFileName);
// 使用 Path 处理文件路径,提高兼容性
Path filePath = Paths.get("D:", "imgup");
try {
uploadFile(file.getBytes(), filePath, uniqueFileName);
} catch (IOException e) {
logger.error("文件上传失败", e);
}
return "success";
}
private static void uploadFile(byte[] file, Path filePath, String fileName) throws IOException {
File targetDir = filePath.toFile();
if (!targetDir.exists()) {
Files.createDirectories(filePath);
}
Path targetPath = filePath.resolve(fileName);
// 使用 try-with-resources 管理资源
try (FileOutputStream out = new FileOutputStream(targetPath.toFile())) {
out.write(file);
}
}
private static String generateUniqueFileName(String originalFileName) {
String extension = "";
int dotIndex = originalFileName.lastIndexOf('.');
if (dotIndex > 0) {
extension = originalFileName.substring(dotIndex);
}
return UUID.randomUUID().toString() + extension;
}
}
文件上传大小可以通过配置来修改
打开application.properties, 默认限制是10MB,我们可以任意修改
1.4 静态资源访问
1.5 消息转换和格式化
Springboot自动配置了消息转换器
格式化转换器的自动注册
时间类型我们可以在这里修改
在配置文件中指定好时间的模式我们就可以输入了
1.6 欢迎页面的自动配置
Springboot自动指定resources下的index.html
在resources下写一个index.html页面,在访问的时候只输入/访问的是index.html
2.springboot扩展SpringMVC
在实际开发中springboot并非完全自动化,很多跟业务相关我们需要自己扩展,springboot给我提供了接口。
我们可以来通过实现WebMvcConfigurer接口来扩展
public interface WebMvcConfigurer {
default void configurePathMatch(PathMatchConfigurer configurer) {
}
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
}
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {
}
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
}
default void addFormatters(FormatterRegistry registry) {
}
default void addInterceptors(InterceptorRegistry registry) {
}
default void addResourceHandlers(ResourceHandlerRegistry registry) {
}
default void addCorsMappings(CorsRegistry registry) {
}
default void addViewControllers(ViewControllerRegistry registry) {
}
default void configureViewResolvers(ViewResolverRegistry registry) {
}
default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
}
default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {
}
default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
}
default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {
}
@Nullable
default Validator getValidator() {
return null;
}
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
2.1 在容器中注册视图控制器(请求转发)
创建一个MyMVCConfig实现WebMvcConfigurer接口,实现一下addViewControllers方法,我们完成通过/ha访问,转发到success.html的工作
@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ha").setViewName("success");
}
2.2 注册格式化器
用来可以对请求过来的日期格式化的字符串来做定制化。当然通过application.properties配置也可以办到。
在配置文件里加上:
@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/ha").setViewName("success");
}
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new Formatter<Date>() {
@Override
public String print(Date date, Locale locale) {
return null;
}
@Override
public Date parse(String s, Locale locale) throws ParseException {
return new SimpleDateFormat("yyyy-MM-dd").parse(s);
}
});
2.3 消息转换器
作用:
在 Spring MVC 应用中,当客户端发送请求到服务器时,请求体可能包含各种格式的数据(如 JSON、XML 等),消息转换器可以将这些数据转换为 Java 对象供控制器方法使用;当服务器处理完请求后,需要将 Java 对象转换为特定格式的数据(如 JSON、XML 等)返回给客户端,这也依赖于消息转换器。
在pom.xml中引入fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
配置消息转换器,添加fastjson
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FastJsonHttpMessageConverter fc = new FastJsonHttpMessageConverter();
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat);
fc.setFastJsonConfig(fastJsonConfig);
converters.add(fc);
}
在实体类上可以继续控制
package com.qcby.entity;
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class User {
private String username;
private String password;
private int age;
private int score;
private int gender;
@JSONField(format = "yyyy-MM-dd")
private Date date;
}
2.4 拦截器注册
1.创建拦截器
package com.qcby.Interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前置拦截");
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("后置拦截");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("最终拦截");
}
}
拦截器注册
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/hello2");
}
除了hello2的其他的都拦截
示例:
在访问hello时