SpringMVC详解(四)----深入了解Spring MVC

深入了解Spring MVC

配置DispatcherServlet

DispatcherServlet初始化参数

DispatcherServlet支持以下几个初始化参数(通过<servlet>标签下的<init-params>标签配置)


  • contextClass
    指定WebApplicationContext的具体实现类,默认是XmlWebApplicationContext
  • contextConfigLocation
    指定用于创建WebApplicationContext上下文的配置文件路径,可以支持多个(多个之间用,隔开),也支持spring通配符写法。 多个配置文件中如果有相同的bean,后面配置文件中的bean会覆盖前面定义的。
  • namespace
    指定DispatcherServlet对应的WebApplicationContext的命名空间,默认是[servlet-name]-servlet
  • throwExceptionIfNoHandlerFound
    当无法找到合适的Handler处理请求时,是否抛出异常
主流方式(web.xml配置)
单个DispatcherServlet

web.xml中:

<servlet>
        <servlet-name>dispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/DispatcherServlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
多个DispatcherServlet

在绝大部分应用中,我们只需要配置一个DisptacherServlet就够了,这往往也是最明智的选择,但在某些特殊的场景下,如果你的业务需要配置不同的DispatcherServlet分别处理不同的请求, 也是可以的。SpringMVC提供了这个支持,这种情况下你可以配置多个不同的DispatcherServlet,分别拦截不同的请求pattern。而有些bean是应该在所有的DispatcherServlet实例中共享的(比如service、dao、数据源这些bean)我们就需要有一个可以在多个DispatcherServlet中共享的WebApplicationContext,通常这时候的架构如下所示:

层级结构图

我们通过ContextLoaderListener接口来初始化全局的WebApplicationContext
web.xml

<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>/WEB-INF/DispatcherServlet.xml</param-value>
    </context-param>

    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

然后,不同的DispatcherServlet加载自己的配置文件,形成Servlet级别的WebApplicatoinContext
web.xml

<!-- 处理订单相关 -->
<servlet>
        <servlet-name>order</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/order-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>order</servlet-name>
        <url-pattern>/order/*</url-pattern>
    </servlet-mapping>

<!-- 处理商品相关 -->
<servlet>
        <servlet-name>goods</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/goods-servlet.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>goods</servlet-name>
        <url-pattern>/goods/*</url-pattern>
    </servlet-mapping>
编码方式配置(Servlet3.0以上)
/**
 * 使用编程方式初始化WebApplicationContext、动态注册DispatcherServlet
 */
@Slf4j
public class MyWebInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {

        XmlWebApplicationContext ctx = new XmlWebApplicationContext();
        ctx.setConfigLocations("classpath:/applicationContext.xml", "WEB-INF/DispatcherServlet.xml");

        DispatcherServlet dispatcherServlet = new DispatcherServlet(ctx);
        ServletRegistration.Dynamic servletRegistration = servletContext.addServlet("Dispatcher", dispatcherServlet);
        servletRegistration.setLoadOnStartup(1);
        servletRegistration.addMapping("/");
    }
}

WebApplicationInitializer接口是SpringMVC提供的用于用户自定义初始化操作的回调接口,实现该接口的类会自动被SpringServletContainerInitializer类调用,而SpringServletContainerInitializer类本身实现了Serlvet3.0的ServletContainerInitializer接口,会在容器启动时自动被调用

Spring MVC中特殊的Bean

HandlerMapping

用于根据前端请求地址,查找能够处理请求的Handler

  • RequestMappingHandlerMapping:用于查找通过@RequestMapping注解方法形式定义的Handler

  • BeanNameUrlHandlerMapping

  • SimpleUrlHandlerMapping

HandlerAdapter

负责调用具体的Handler

  • RequestMappingHandlerAdapter:用于执行通过@RequestMapping注解方法形式定义的Handler
  • HttpRequestHandlerAdapter:用于处理HttpRequestHandler这种类型的Handler
  • SimpleControllerHandlerAdapter:用于处理Controller类型的Handler,比如典型的<mvc:view-controller>的实现类ParameterizableViewController就是派生自Controller接口
ViewResolver

视图解析器,负责将Handler中返回的视图名称解析成实际的视图(页面、或其他格式数据返回)

  • ContentNegotiatingViewResolver:一个特殊的视图解析器,实现了ViewResolver。 自己不负责实际解析视图,只负责在众多视图解析其中寻找最匹配的请求类型的视图解析器(如果不用ContentNegotiatingViewResolver,默认找到一个可以解析视图的解析器就直接返回,不再继续找其他视图解析器)
View

具体的视图对象。 通过render方法将数据和页面结合后返回给调用方

MultipartResolver

负责处理文件上传

HandlerExceptionResolver

处理异常

LocalResolver

语言国际化相关支持

ThemeResolver

多主题样式支持

Spring MVC配置<mvc:xxx>

启用Spring MVC配置
xml方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <mvc:annotation-driven/>

</beans>
注解方式
@Configuration
@EnableWebMvc
public class WebConfig {
}
配置类型转换器
配置数据校验器
配置拦截器

Spring MVC详解(三)-----拦截器

配置视图控制器

一般用于控制无逻辑视图的跳转,配置见下面的《配置无逻辑视图跳转控制器》章节

配置支持的mime类型
配置视图解析器

配置方法详解下面的《视图相关》章节:

在Spring IOC容器中配置一个ViewResolver类型的<bean>
在SpringMVC中视图解析器的作用是连接逻辑视图名和具体的视图页面。 具体来说就是用来解析RequestMapping方法返回的逻辑视图名,返回具体的视图给客户端(如:可以是一个页面、一个文件或JSON格式内容)

SpringMVC支持同时配置多个视图解析器(每个视图解析器就是在IOC中配置一个bean),它们会组成一个视图解析器链,可以通过指定order属性来设定他们的顺序,order属性值越大,在链中越靠后。

如果配置了多个视图解析器,必须确保InternalResourceViewResolver是最后一个

ViewResolver架构层级图
ViewResolver架构层级图

AbstractCachingViewResolver

扩展自该类的子类都支持缓存View的实例,可以通过设置cache属性为false禁止缓存

XmlViewResolver
UrlBasedViewResolver

该类是ViewResolver接口的一个简单实现,支持将一个逻辑视图名映射成一个具体的URL,而无需配置显示的映射定义。适用于逻辑视图名和视图资源有明确对应关系的情况。

  • InternalResourceViewResolver:扩展自UrlBasedViewResolver,支持解析InternalResourceView视图(比如:Servlet、JSP)
  • FreeMarkerViewResolver:扩展自UrlBasedViewResolver,支持解析FreeMarkerView视图
ResourceBundleViewResolver
ContentNegotiatingViewResolver

ViewResolver顶层接口的另一种实现,基于请求的文件名或AcceptHeader,来选择合适的ViewResolver解析视图(自己本身不负责解析视图)

配置无逻辑视图跳转控制器

无逻辑视图跳转即不经过Action,直接跳转页面

如果我们有些请求只是想跳转页面,不需要来后台处理什么逻辑,我们无法在Action中写一个空方法来跳转,直接在中配置一个如下的视图跳转控制器即可(不经过Action,直接跳转页面)

<mvc:view-controller path="/" view-name="home"/>
静态资源处理

配置示例:

<mvc:resources mapping="/resources/**"
    location="/public, classpath:/static/"
    cache-period="31556926" />
配置消息转换器

详见上一章的消息转换器

完全使用默认的配置

默认的配置在spring-webmvc包中的DispatcherServlet.properties文件中可以看到

支持的注解配置

这一部分的内容大多已经在第二章Spring MVC详解(二)讲过,就不再详细说明。

定义Controller
  • @Controller
  • @RestController
请求映射

获取请求地址映射参数

处理请求方法相关
方法注解
  • @RequestMapping:可以处理所有的请求,可以在Method属性中指明处理的请求方式,只处理某种请求
  • @GetMapping:只能处理Get请求
  • @PostMapping:只能处理Post请求
方法参数
  • @RequestHeader

  • @RequestParam

  • @CookieValue

  • @SessionAttribute

  • @RequestAttribute

  • @PathVariable:获取URI中的参数

  • @RequestBody

    • 获取请求体内容。
    • 如果该注解标注的参数是一个自定义类型SpringMVC会自动调用MessageConterver将请求体中的数据转成对应的Object对象。(比如客户端提交的JSON格式数据会自动直接转成方法参数中对应的Object类型
  • @RequestPart

  • Part、MultiPartFile

  • HttpMethod

  • 原生javax对象

    • javax.servlet.ServletRequest
    • javax.servlet.ServletResponse
    • javax.servlet.http.HttpSession
  • org.springframework.ui.Model、ModelAndView、ModelMap、java.util.Map:用于将后台数据传递到视图中

    示例:
    Controller代码:

    public String queryGoods(Model model) {
        List<Goods> goodsList = goodsService.queryGoods(...);
        model.addAttribute("goods", goodsList);
        return "goods_list";
    }
    

    goods_list.jsp代码:

    <body>
       ${goods}
    </body>
    
  • InputStream、OutputStream

    • InputStream参数用于获取request的请求体
    • OutputStream参数用于获取response.getOutputStream对象
方法返回值
  • String视图名称

  • View视图名称

  • @RequestBody:将返回的内容本身写入响应体中,而不是以视图的方式渲染

  • ResponseEntity

    和@ResponseBody类似,不过增加了响应状态和响应头。
    示例:

    @RequestMapping("/test/resp_entity")
        public ResponseEntity<String> testRespEntity() {
            System.out.println("testRespEntity");
            return ResponseEntity.ok().header("Content-Type", "application/json;charset=UTF-8").body("{\"name\": \"张三\", \"age\": 21}");
    }
    
  • Map、Model、ModelAndView

  • void:适合于方法中带有HttpResponseOutputStream或者通过@ResponseStatus注解标注的方法

异常处理

可以通过在一个Controller中的一个方法上添加@ExceptionHandler注解来处理全局的异常

/**
 * 处理全局异常
 *
 * @author 召
 */

@Slf4j
@ControllerAdvice
public class ExceptionControllerAdvice {

    /**
     * 定义全局异常处理
     *
     * @param ex 异常栈信息
     * @return
     */
    @ExceptionHandler
    public ResponseEntity<String> handle(Exception ex) {
        log.error("出错了", ex);
        return new ResponseEntity(HttpStatus.BAD_REQUEST);
    }
}

数据绑定

默认数据绑定器

SpringMVC提供了一个默认的数据绑定器WebDataBinder负责将请求中的参数封装到JavaBean的同名属性中,大大减少了我们的代码量。

@RequestMapping("/test/bind_obj")
public String testBindObject(Student student, Model model) {
    System.out.println("testBindObject, student: " + student);
    model.addAttribute("msg", student);
    return "main";
}

访问地址:

http://localhost:8080/test/bind_obj?sname=张三&age=34&id=2
更改默认数据绑定器行为

所有通过@Controller@ControllerAdvice注解标注的类都可以定义一个用@InitBinder注解标注的方法来自定义数据绑定器的行为,如:

@Controller
public class FormController {

    @InitBinder 
    public void initBinder(WebDataBinder binder) {
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        dateFormat.setLenient(false);
        binder.registerCustomEditor(Date.class, new CustomDateEditor(dateFormat, false));
    }

    // ...
}

自定义Formatter

@Controller
public class FormController {

    @InitBinder 
    protected void initBinder(WebDataBinder binder) {
        binder.addCustomFormatter(new DateFormatter("yyyy-MM-dd"));
    }

    // ...
}

视图相关

都是通过视图控制器来处理

Thymeleaf
FreeMarker

xml中配置:

<mvc:view-resolvers>
    <mvc:freemarker/>
</mvc:view-resolvers>

<!-- Configure FreeMarker... -->
<mvc:freemarker-configurer>
    <mvc:template-loader-path location="/WEB-INF/freemarker"/>
</mvc:freemarker-configurer>
JSP&JSTL

配置示例:

<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>
JSON

详见第三章的返回JSON数据

跨多个Controller共享配置

我们在Controller中配置的@ExceptionHandler@InitBinder@ModelAttribute(下面简称:配置项)都只在当前Controller类中有效,如果想让他们可以在多个Controller中共享(全局有效),则需要将其定义到通过@ControllerAdvice或者@RestControllerAdvice注解的类中

用法如下:

// 此类中的配置项在所有通过@RestController注解的Controller中共享
@ControllerAdvice(annotations = RestController.class)
public class ExampleAdvice1 {}

// 此类中的配置项在指定包的Controller类中共享
@ControllerAdvice("org.example.controllers")
public class ExampleAdvice2 {}

// // 此类中的配置项在所有扩展自指定类的Controller中共享
@ControllerAdvice(assignableTypes = {ControllerInterface.class, AbstractController.class})
public class ExampleAdvice3 {}

异步请求

处理跨域请求

全局跨域请求配置

配置示例:

<mvc:cors>

    <mvc:mapping path="/api/**"
        allowed-origins="https://domain1.com, https://domain2.com"
        allowed-methods="GET, PUT"
        allowed-headers="header1, header2, header3"
        exposed-headers="header1, header2" allow-credentials="true"
        max-age="123" />

    <mvc:mapping path="/resources/**"
        allowed-origins="https://domain1.com" />

</mvc:cors>
在类级别和方法级别启用跨域请求支持

SpringMVC支持类级别和方法级别的跨域请求配置

方法级别,示例:

@CrossOrigin
@GetMapping("/{id}")
public Account retrieve(@PathVariable Long id) {
        // ...
}

类级别,示例:

@CrossOrigin(origins = "https://domain2.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {

    @GetMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }

    @DeleteMapping("/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}

缓存相关

异常处理链

SpringMVC支持我们配置多个异常处理器, 他们会像过滤器一样,以chain的方式依次调用,下面是SpringMVC内置的四个异常处理实现类:

  • SimpleMappingExceptionResolver
  • DefaultHandlerExceptionResolver
  • ResponseStatusExceptionResolver
  • ExceptionHandlerExceptionResolver

通用的异常处理约定如下:

  • 在请求处理方法中返回一个指向错误页面的ModelAndView对象

  • 如果某个一个异常解析器中已经处理了异常则返回一个空的ModelAndView对象

  • 如果当前异常解析器不能处理异常,则返回null, 这样下一个异常解析器就会尝试处理异常,一直往下直到某个异常解析器处理掉异常,如果所有异常解析器都无法处理,则将异常抛给Servlet容器

REST客户端工具

  • RestTemplate
  • WebClient
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值