【体系-单体架构】10-Web架构升级之SpringMVC

本文详细介绍了Spring MVC的架构,包括DispatcherServlet、Controller、视图解析器的配置与工作流程,以及如何整合Spring MVC。接着,通过创建第一个Controller展示了如何将Servlet转化为Controller。还探讨了Spring MVC中的拦截器使用,以及模块化开发的重要性。最后,讨论了Spring MVC的表单处理和@ModelAttribute、@ResponseBody的作用。
摘要由CSDN通过智能技术生成

01 Spring MVC 简介

概述:Spring MVC( Spring Web MVC ) ,属于展示层框架,SpringMVC 是 Spring 框架的一部分。Spring Web MVC 框架提供了 MVC (模型 - 视图 - 控制器) 架构和用于开发灵活和松散耦合的 Web 应用程序的组件, MVC 模式导致应用程序的不同方面(输入逻辑,业务逻辑和 UI 逻辑)分离,同时提供这些元素之间的松散耦合
MVC

  • 模型 (Model):封装了应用程序数据,通常它们将由 POJO 类组成
  • 视图 (View):负责渲染模型数据,一般来说它生成客户端浏览器可以解释 HTML 输出
  • 控制器 (Controller):负责处理用户请求并构建适当的模型,并将其传递给视图进行渲染

02 DispatcherServlet 组件类

原理:Spring Web MVC 框架是围绕 DispatcherServlet 设计的,它处理所有的 HTTP 请求和响应。 Spring Web MVC DispatcherServlet 的请求处理工作流如下图所:
在这里插入图片描述
以下是对应于到 DispatcherServlet 的传入 HTTP 请求的事件顺序:

  • 在接收到 HTTP 请求后,DispatcherServlet 会查询 HandlerMapping 以调用相应的 Controller
  • Controller 接受请求并根据使用的 GET 或 POST 方法调用相应的服务方法。 服务方法将基于定义的业务逻辑设置模型数据,并将视图名称返回给 DispatcherServlet
  • DispatcherServlet 将从 ViewResolver 获取请求的定义视图
  • 当视图完成,DispatcherServlet 将模型数据传递到最终的视图,并在浏览器上呈现
    所有上述组件,即: HandlerMapping,Controller 和 ViewResolver 是 WebApplicationContext 的一部分,它是普通 ApplicationContext 的扩展,带有 Web 应用程序所需的一些额外功能

03 Spring 整合 Spring MVC

  • 在 pom.xml 配置文件中增加 org.springframework:spring-webmvc 依赖<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>4.3.17.RELEASE</version> </dependency>
    在这里插入图片描述
    由于spring-webmvc依赖spring-web所以pom.xml里面的spring-web依赖可以去掉(其实spring-context也可以删除)
  • 在web.xml中配置字符集过滤器(CharacterEncodingFilter),用于解决中文编码问题
    在这里插入图片描述
  • 在web.xml中配置 Spring 的 Servlet 分发器处理所有 HTTP 的请求和响应
    在这里插入图片描述
  • spring-mvc.xml 文件来配置 MVC
  • 相关配置说明:context:property-placeholder(动态加载属性配置文件以变量的方式引用需要的值)、context:component-scan(当前配置文件为 MVC 相关,故只需要扫描包含 @Controller 的注解即可,由于 spring-context.xml 配置文件中也配置了包扫描,所以还需要排除 @Controller 的注解扫描)、InternalResourceViewResolver(视图文件解析器的一种,用于配置视图资源的路径和需要解释的视图资源文件类型,这里有两个需要配置的属性 prefix[前缀,配置视图资源路径]以及 suffix[后缀,配置视图资源类型]),mvc:resources(静态资源映射,主要用于配置静态资源文件存放路径,如:JS、CSS、Image 等)
    在这里插入图片描述
  • 系统相关配置:在 spring-mvc.xnl 中,我们配置了 <context:property-placeholder ignore-unresolvable=“true” location=“classpath:myshop.properties”/> 用于动态加载属性配置文件,实际开发中我们会将系统所需的一些配置信息封装到 .properties 配置文件中便于统一的管理
    在这里插入图片描述
  • 去掉 Spring 配置的重复扫描:由于 spring-mvc.xml 中已经配置了 @Controller 注解的扫描而 spring-context.xml 中配置的是扫描全部注解,故在这里需要将 @Controller 注解的扫描配置排除,修改 spring-context.xml 配置
    在这里插入图片描述

04 第一个 Controller 控制器

目的:将之前的servlet改造为controller
编码:@Controller 用于标记在一个类上,使用它标记的类就是一个 Spring MVC Controller 对象。分发处理器将会扫描使用了该注解的类的方法,并检测该方法是否使用了@RequestMapping 注解。@Controller 只是定义了一个控制器类,而使用 @RequestMapping 注解的方法才是真正处理请求的处理器;@Controller(在 Spring MVC 中,控制器 Controller 负责处理由 DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个 Model ,然后再把该 Model 返回给对应的 View 进行展示。在 Spring MVC 中提供了一个非常简便的定义 Controller 的方法,你无需继承特定的类或实现特定的接口,只需使用 @Controller 标记一个类是 Controller ,然后使用 @RequestMapping 和 @RequestParam 等一些注解用以定义 URL 请求和 Controller 方法之间的映射,这样的 Controller 就能被外界访问到。此外 Controller 不会直接依赖于 HttpServletRequest 和 HttpServletResponse 等 HttpServlet 对象,它们可以通过 Controller 的方法参数灵活的获取到)、@RequestMapping(RequestMapping 是一个用来处理请求地址映射的注解,可用于类或方法上。用于类上,表示类中的所有响应请求的方法都是以该地址作为父路径。RequestMapping 注解有六个属性:value-指定请求的实际地址,指定的地址可以是 URI Template 模式;method-指定请求的method类型, GET、POST、PUT、DELETE 等;consumes-指定处理请求的提交内容类型(Content-Type),例如 application/json, text/html;produces-指定返回的内容类型,仅当 request 请求头中的(Accept)类型中包含该指定类型才返回;params-指定 request 中必须包含某些参数值是,才让该方法处理;headers-指定 request 中必须包含某些指定的 header 值,才能让该方法处理请求)

package com.demo.my.shop.web.controller;

import com.demo.my.shop.entity.User;
import com.demo.my.shop.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;

@Controller
public class LoginController {
   

    //根据类来自动装配
    @Autowired
    private UserService userService;

    /**
     * 跳转登录页面
     * @return
     */
    @RequestMapping(value = {
   "", "login"}, method = RequestMethod.GET)
    public String login() {
   
        //跳转
        return "login";
    }

    /**
     * 登录逻辑
     * @param email
     * @param password
     * @return
     */
    @RequestMapping(value = "login", method = RequestMethod.POST)
    //请求参数是必须的(默认)
    public String login(@RequestParam(required = true) String email, @RequestParam(required = true) String password) {
   
        User user = userService.login(email, password);

        //登录失败
        if(user == null) {
   
            return login();
        }
        //登录成功
        else {
   
            //重定向
            return "redirect:/main";
        }
    }
}
package com.demo.my.shop.web.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class MainController {
   

    /**
     * 跳转到首页
     * @return
     */
    @RequestMapping(value="main", method = RequestMethod.GET)
    public String main(){
   
        return "main";
    }
}

05 Spring MVC 拦截器的使用

简介:Spring Web MVC 的处理器拦截器,类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理
应用场景:日志记录(记录请求信息的日志,以便进行信息监控、信息统计、计算 PV[Page View]等)、权限检查(如登录检测,进入处理器检测检测是否登录,如果没有直接返回到登录页面)、性能监控(有时候系统在某段时间莫名其妙的慢,可以通过拦截器在进入处理器之前记录开始时间,在处理完后记录结束时间,从而得到该请求的处理时间)、通用行为(读取 Cookie 得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有如提取 Locale、Theme 信息等,只要是多个处理器都需要的即可使用拦截器实现)
详解:Spring MVC 拦截器需要实现 HandlerInterceptor 接口,该接口定义了 3 个方法,分别为 preHandle()、postHandle() 和 afterCompletion(),咱们就是通过重写这 3 个方法来对用户的请求进行拦截处理的

  • preHandle(HttpServletRequest request, HttpServletResponse response, Object handle):该方法在请求处理之前进行调用。Spring MVC 中的 Interceptor 是链式调用的,在一个应用中或者说是在一个请求中可以同时存在多个 Interceptor 。每个 Interceptor 的调用会依据它的声明顺序依次执行,而且最先执行的都是 Interceptor 中的 preHandle 方法,所以可以在这个方法中进行一些前置初始化操作或者是对当前请求做一个预处理,也可以在这个方法中进行一些判断来决定请求是否要继续进行下去。该方法的返回值是布尔值 Boolean 类型的,当它返回为 false 时,表示请求结束,后续的 Interceptor 和 Controller 都不会再执行;当返回值为 true 时,就会继续调用下一个 Interceptor 的 preHandle 方法,如果已经是最后一个 Interceptor 的时候,就会是调用当前请求的 Controller 中的方法
  • postHandle(HttpServletRequest request, HttpServletResponse response, Object handle, ModelAndView modelAndView):通过 preHandle 方法的解释咱们知道这个方法包括后面要说到的 afterCompletion 方法都只能在当前所属的 Interceptor 的 preHandle 方法的返回值为 true 的时候,才能被调用。postHandle 方法在当前请求进行处理之后,也就是在 Controller 中的方法调用之后执行,但是它会在 DispatcherServlet 进行视图返回渲染之前被调用,所以咱们可以在这个方法中对 Controller 处理之后的 ModelAndView 对象进行操作。postHandle 方法被调用的方向跟 preHandle 是相反的,也就是说,先声明的 Interceptor 的 postHandle 方法反而会后执行
  • afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handle, Exception ex):也是需要当前对应的 Interceptor 的 preHandle 方法的返回值为 true 时才会执行。因此,该方法将在整个请求结束之后,也就是在 DispatcherServlet 渲染了对应的视图之后执行,这个方法的主要作用是用于进行资源清理的工作

编码:我们知道对系统的相关操作是需要登录后才可以使用的,当未登录时是无法直接访问需要登录权限的操作的,为了做到这个效果,我们使用登录拦截器来判断用户是否登录,如果用户已登录则放行让用户继续操作,否则就将其跳转到登录页(mvc:interceptor-定义一个拦截器、mvc:mapping-映射路径,需要拦截的请求路径、mvc:exclude-mapping-需要排除的请求路径,比如登录页本身是不需要拦截的,这里还包括了静态资源路径也是不需要拦截的、bean class-配置指定的拦截器对象)

//LoginInterceptor.java
package com.demo.my.shop.web.interceptor;

import com.demo.my.shop.commons.constant.ConstantUtils;
import com.demo.my.shop.entity.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 登录拦截器
 */
public class LoginInterceptor implements HandlerInterceptor {
   
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
   
        User user = (User) httpServletRequest.getSession().getAttribute(ConstantUtils.SESSION_USER);

        //未登录
        if(user == null){
   
            httpServletResponse.sendRedirect("/login");
        }

        //放行
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
   

    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
   

    }
}
//PermissionInterceptor.java
package com.demo.my.shop.web.interceptor;

import com.demo.my.shop.commons.constant.ConstantUtils;
import com.demo.my.shop.entity.User;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 权限控制器
 */
public class PermissionInterceptor implements HandlerInterceptor {
   
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
   
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
   
        //以login结尾的请求
        if(modelAndView.getViewName().endsWith("login")) {
   
            User user = (User) httpServletRequest.getSession().getAttribute(ConstantUtils.SESSION_USER);
            if (user != null) {
   
                httpServletResponse
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值