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

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是自动被配置好的

multipartResolver  Spring 框架中是用于处理文件上传的关键组件

页面(一个文件上传的测试)

<!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");
    }

在这里我发现页面从/connect进去不会触发thymleaf

这是携带thymeleaf的界面)

 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;
}

补充一个小tips:

我们可以搜索这个配置文件,然后去看,不用一层一层找

 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容器;


http://www.kler.cn/a/589777.html

相关文章:

  • 量子计算 × 虚拟现实:未来科技的双剑合璧
  • 遥感数据处理
  • Linux:信号的生命周期分析,以及捕捉信号时中断触发的内核态拦截与用户态处理时机
  • 下拉菜单+DoTween插件
  • Houdini :《哪吒2》神话与科技碰撞的创新之旅
  • C语言经典代码题
  • 从 YOLOv1 到 YOLOv2:目标检测的进化之路
  • 轨迹规划:基于查找的(search-based)路径规划算法
  • C#特性和反射
  • MySQL高频八股——事务过程中Undo log、Redo log、Binlog的写入顺序(涉及两阶段提交)
  • 异常(11)
  • Linux 日志与时间同步指南
  • 2024浙江大学计算机考研上机真题
  • 【蓝桥杯】省赛:神奇闹钟
  • 自然语言处理(2)—— NLP之百年风雨路
  • Android第三次面试(Java基础)
  • 蓝牙系统的核心组成解析
  • Secs/Gem第一讲 · 总结精华版(基于secs4net项目的ChatGpt介绍)
  • TypeScript类型兼容性 vs JavaScript动态类型:深入对比解析
  • redis分片集群如何解决高并发写问题的?