SpringBoot(6)——Springboot整合springmvc
系列文章
1、SpringBoot(1)——创建SpringBoot项目的方式_基于注解方式开发aspectj springboot下载-CSDN博客
2、SpringBoot(2)——SpringBoot入门:微服务-CSDN博客
3、SpringBoot(3)——SpringBoot入门程序及解析-CSDN博客
4、SpringBoot(4)——SpringBoot自动配置原理-CSDN博客
5、SpringBoot(5)——SpringBoot配置文件-CSDN博客
目录
1.Springmvc的自动解管理
1.1 中央转发器
1.2 控制器
1.3 视图解析器自动管理
1.4 消息转换和格式化
1.5 欢迎页面的自动配置
2.Springboot扩展springmvc
2.1 在容器中注册视图控制器(请求转发)
2.2 注册格式化器
2.3 消息转换器扩展fastjson
2.4 拦截器注册
3.配置嵌入式服务器
3.1 如何定制和修改Servlet容器的相关配置;
3.2 注册Servlet三大组件【Servlet、Filter、Listener】
3.2.1 servlet
3.2.2 FilterRegistrationBean
3.2.3 ServletListenerRegistrationBean
4.使用外置的Servlet容器
步骤
原理
学习springmvc和springboot的自动配置,我们必须对springmvc的组件足够了解,起码知道怎么用。Springmvc的组件基本都被springboot来做了自动的配置。
这篇博客总结springboot如何整合,扩展springmvc
Spring Boot Reference Guidehttps://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/htmlsingle/#boot-features-spring-mvc
1.Springmvc的自动解管理
中央转发器(DispatcherServlet)
控制器
视图解析器
静态资源访问
消息转换器
格式化
静态资源管理
1.1 中央转发器
Xml无需配置(web.xml文件中的内容,springboot自己框架已经自带了)
<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.
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>
<!--multipartResolver测试-->
<form action="/upload" method="post" enctype="multipart/form-data">
<input name="pic" type="file">
<input type="submit">
</form>
</body>
</html>
Controller
package com.qcby.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
@Controller
public class Test1Controller {
@ResponseBody
@RequestMapping("/upload")
public String upload(@RequestParam("pic") MultipartFile file, HttpServletRequest request){
String contentType = file.getContentType();
String fileName = file.getOriginalFilename();
System.out.println("fileName-->" + fileName);
System.out.println("getContentType-->" + contentType);
//String filePath = request.getSession().getServletContext().getRealPath("imgupload/");
String filePath = "D:/imgs/";
try {
this.uploadFile(file.getBytes(), filePath, fileName);
} catch (Exception e) {
// TODO: handle exception
}
return "success";
}
public static void uploadFile(byte[] file, String filePath, String fileName) throws Exception {
File targetFile = new File(filePath);
if(!targetFile.exists()){
targetFile.mkdirs();
}
FileOutputStream out = new FileOutputStream(filePath+fileName);
out.write(file);
out.flush();
out.close();
}
}
写一个管理页面跳转的PageController
package com.qcby.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class PageController {
@GetMapping("/test1")
public String showUploadPage1() {
return "test1";
}
@GetMapping("/test2")
public String showUploadPage2() {
return "test2";
}
}
进入界面,并上传文件
上传成功
文件上传大小可以通过配置来修改
打开application.properties, 默认限制是10MB,我们可以任意修改
1.4 消息转换和格式化
Springboot自动配置了消息转换器
格式化转换器的自动注册
时间类型我们可以在这里修改:
老版本
新版本
spring.mvc.date-format 曾经用于全局配置日期格式,但这种方式存在一定局限性,比如它只能处理 java.util.Date 类型,对于 Java 8 引入的新日期时间 API(如 LocalDate、LocalDateTime 等)支持不够灵活。
为了更好地适配新的日期时间 API 以及提供更强大的日期格式化功能,Spring Boot 对日期格式化的配置方式进行了调整。
1.5 欢迎页面的自动配置
Springboot自动指定resources下的index.html
默认自动寻找index
2.Springboot扩展springmvc
在实际开发中springboot并非完全自动化,很多跟业务相关我们需要自己扩展,
SpringBoot给我们提供了接口:我们可以来通过实现WebMvcConfigurer接口来扩展
WebMvcConfigurer 是 Spring MVC 框架中的一个重要接口,它提供了一系列的方法,允许开发者对 Spring MVC 的默认配置进行自定义和扩展
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 在容器中注册视图控制器(请求转发)
创建一个MyMVCCofnig实现WebMvcConfigurer接口,实现一下addViewControllers方法,我们完成通过/connect访问,转发到success.html的工作
/**
* 在容器中注册视图控制器(请求转发)
* */
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/connect").setViewName("success");
}
2.2 注册格式化器
用来可以对请求过来的日期格式化的字符串来做定制化 。当然通过application.properties配置也可以办到。
注意!!依赖不要导错,Formatter这个很容易导错
/**
* 注册格式化器
* */
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new Formatter<Date>() {
@Override
public String print(Date date, Locale locale) {
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
@Override
public Date parse(String s, Locale locale) throws ParseException {
return new SimpleDateFormat("yyyy-MM-dd").parse(s);
}
});
}
2.3 消息转换器扩展fastjson
两种方式,但依赖导入是实现之后两种方式的前提
在pom.xml中引入fastjson
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
配置消息转换器,添加fastjson
/**
*消息转换器扩展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);
}
在实体类上可以继续控制
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 拦截器注册
首先!我们需要自己创建一个拦截器类
package com.qcby.extend;
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("最终拦截");
}
}
在MyMVCConfig中实现注册——本例子中/test2不会被拦截
/**
* 拦截器注册
* */
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/test2");
}
/test2测试
其他界面测试,在本例子中会输出拦截器内容
3.配置嵌入式服务器
3.1 如何定制和修改Servlet容器的相关配置;
修改和server有关的配置(ServerProperties)
server.port=8080
server.context?path=/aa
server.tomcat.uri?encoding=UTF-8
server.port=8080
:指定 Spring Boot 应用启动时监听的端口号为 8080。也就是说,应用启动后,你可以通过http://localhost:8080
来访问该应用。server.context-path=/aa
:设置应用的上下文路径为/aa
。这样,访问应用内的具体接口时,URL 就需要加上这个上下文路径,比如原本访问某个接口的 URL 是http://localhost:8080/test
,配置上下文路径后就变成了http://localhost:8080/aa/test
。server.tomcat.uri-encoding=UTF-8
:设置 Tomcat 服务器在处理 URI 时使用的字符编码为 UTF - 8。这有助于正确处理包含中文或其他非 ASCII 字符的 URL,避免出现乱码问题。
3.2 注册Servlet三大组件【Servlet、Filter、Listener】
由于SpringBoot默认是以jar包的方式启动嵌入式的Servlet容器来启动SpringBoot的web应用,没有web.xml文件。
3.2.1 servlet
需要自己写一个MyServlet类
package com.qcby.entity;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.getWriter().println("Hello from MyServlet!");
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doGet(req, resp);
}
}
在MyMVCConfig里配置:
//servlet
@Bean
public ServletRegistrationBean myServlet(){
ServletRegistrationBean registrationBean = new ServletRegistrationBean(new MyServlet(),"/myServlet");
return registrationBean;
}
测试结果如下:
3.2.2 FilterRegistrationBean
需要自己定义一个MyFilter类
package com.qcby.entity;
import javax.servlet.*;
import java.io.IOException;
/**
* 自定义过滤器类
*/
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 在请求处理之前执行的逻辑
System.out.println("Before request processing");
// 继续执行请求链
chain.doFilter(request, response);
// 在请求处理之后执行的逻辑
System.out.println("After request processing");
}
}
实现对应的接口
@Bean
public FilterRegistrationBean myFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new MyFilter());
//设置过滤器的拦截路径
registrationBean.setUrlPatterns(Arrays.asList("/hello","/myServlet"));
return registrationBean;
}
测试结果如下:
3.2.3 ServletListenerRegistrationBean
需要自己定义一个MyFilter类
package com.qcby.entity;
import javax.servlet.*;
import java.io.IOException;
/**
* 自定义过滤器类
*/
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 在请求处理之前执行的逻辑
System.out.println("Before request processing");
// 继续执行请求链
chain.doFilter(request, response);
// 在请求处理之后执行的逻辑
System.out.println("After request processing");
}
}
配置文件中:
/**
* 监听器注册
* */
@Bean
public ServletListenerRegistrationBean myListener(){
ServletListenerRegistrationBean<MyListener> registrationBean = new
ServletListenerRegistrationBean<>(new MyListener());
return registrationBean;
}
结果如下:
SpringBoot帮我们自动SpringMVC的时候,自动的注册SpringMVC的前端控制器;ServletListenerRegistrationBean DispatcherServlet;
DispatcherServletAutoConfiguration中:
@Bean(name = DEFAULT_DISPATCHER_SERVLET_REGISTRATION_BEAN_NAME)
@ConditionalOnBean(value = DispatcherServlet.class, name =
DEFAULT_DISPATCHER_SERVLET_BEAN_NAME)
public ServletRegistrationBean dispatcherServletRegistration(
DispatcherServlet dispatcherServlet) {
ServletRegistrationBean registration = new ServletRegistrationBean(
dispatcherServlet, this.serverProperties.getServletMapping());
//默认拦截: / 所有请求;包静态资源,但是不拦截jsp请求; /*会拦截jsp
//可以通过server.servletPath来修改SpringMVC前端控制器默认拦截的请求路径
registration.setName(DEFAULT_DISPATCHER_SERVLET_BEAN_NAME);
registration.setLoadOnStartup(
this.webMvcProperties.getServlet().getLoadOnStartup());
if (this.multipartConfig != null) {
registration.setMultipartConfig(this.multipartConfig);
}
return registration;
}
4.使用外置的Servlet容器
嵌入式Servlet容器:应用打成可执行的jar
优点:简单、便携;
缺点:默认不支持JSP、优化定制比较复杂.;
外置的Servlet容器:外面安装Tomcat---应用war包的方式打包;
步骤
1)必须创建一个war项目;(利用idea创建好目录结构)
2)将嵌入式的Tomcat指定为provided;
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring‐boot‐starter‐tomcat</artifactId>
<scope>provided</scope>
</dependency>
3)配置项目的目录结构
部署本地tomcat
4)必须编写一个SpringBootServletInitializer的子类,并调用configure方法
package com.example.demo0316.demos;
import com.example.demo0316.Demo0316Application;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
public class ServletInitializer extends SpringBootServletInitializer {
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
//传入SpringBoot应用的主程序
return application.sources(Demo0316Application.class);
}
}
5)启动服务器就可以使用;
原理
jar包:执行SpringBoot主类的main方法,启动ioc容器,创建嵌入式的Servlet容器;
war包:启动服务器,服务器启动SpringBoot应用【SpringBootServletInitializer】,启动ioc容器;