SSM04-SpringMVC框架

SpringMVC框架

一、概述

1.1 MVC三层架构:

表现层(Web层):负责接收客户端请求,并向客户端响应结果;

业务层(Service层):负责业务逻辑处理,和项目需求息息相关;

持久层(Dao层):负责和数据库交互,对数据库表进行增删改查。

1.2 定义

Spring MVC是Spring提供的一个实现了Web MVC设计模式的轻量级Web框架。Spring MVC提供了对MVC模式的全面支持,它可以将表现层解耦,同时Spring MVC是基于请求-响应处理模型的请求驱动框架,简化了表现层的实现。

image-20241219185910791

Spring MVC作用于三层架构中的表现层,用于接收客户端的请求并进行响应。

Spring MVC中包含了控制器和视图,控制器接收到客户端的请求后对请求数据进行解析和封装,接着将请求交给业务层处理。业务层会对请求进行处理,最后将处理结果返回给表现层。表现层接收到业务层的处理结果后,再由视图对处理结果进行渲染,渲染完成后响应给客户端。

1.3 Spring MVC工作原理

image-20241219190432184

(1)用户通过浏览器向服务器发送请求,请求会被Spring MVC的前端控制器DispatcherServlet拦截。

(2)DispatcherServlet拦截到请求后,会调用HandlerMapping(处理器映射器)。

(3)处理器映射器根据请求URL找到具体的处理器,生成处理器对象及处理器拦截器(如果有则生成)一并返回给DispatcherServlet。

(4)DispatcherServlet会通过返回信息选择合适的HandlerAdapter(处理器适配器)。

(5) HandlerAdapter会调用并执行Handler(处理器),这里的处理器指的就是程序中编写的Controller类,也被称之为后端控制器。

(6)Controller执行完成后,会返回一个ModelAndView对象,该对象中会包含视图名或包含模型和视图名。

(7)HandlerAdapter将ModelAndView对象返回给DispatcherServlet。

(8)前端控制器请求视图解析器根据逻辑视图名解析真正的视图。(9)ViewResolver解析后,会向DispatcherServlet中返回具体的View(视图)。

(10)DispatcherServlet对View进行渲染(即将模型数据填充至视图中)。

(11)前端控制器向用户响应结果。

二、Spring MVC的实现

2.1 前端控制器DispatcherServlet

DispatcherServlet是Spring MVC的核心类,也是Spring MVC的流程控制中心,也称为Spring MVC的前端控制器,它可以拦截客户端的请求。拦截客户端请求之后,DispatcherServlet会根据具体规则将请求交给其他组件处理。所有请求都要经过DispatcherServlet进行转发处理,这样就降低了Spring MVC组件之间的耦合性。

  • 代码实现(web.xml)
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">
    <!-- 配置前端控制器   -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <!-- 配置初始化参数  -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.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>
</web-app>
  • 细节解释
  1. 前端控制器实质上是一个Servlet类,即org.springframework.web.servlet.DispatcherServlet

  2. 初始化参数是指在DispatcherServlet类加载时,加载spring-mvc核心配置文件,若没有指定,应用程序会在WEB-INF中找DispatcherServlet-servlet.xml的配置文件。

  3. <load-on-startup>中未0或正整数时表示项目启动时才加载此Servlet,此值越小Servlet越早被加载。若此值为负数或不设置,则Servlet在请求时才会被加载。

  4. servlet-mapping中指定url-pattern为/,表面所有的请求均会被拦截到此Servlet中

2.2 spring-mvc.xml核心配置

  • 当使用注解开发时,此配置需要开启对处理器的扫描

<context:component-scan base-package="com.tyut.controller"/>

  • 同时需要配置视图处理器

下面视图处理器实际上将访问视图的路径均改为

/WEB-INF/pages/视图逻辑名.jsp

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">


    <!--配置Spring MVC要扫描的包-->
    <context:component-scan base-package="com.tyut.controller"/>

    <!-- 配置视图解析器   -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
</beans>

2.3 适配器类(@Controller注解)

Spring MVC框架提供了@Controller注解。使用@Controller注解,只需要将@Controller注解标注在普通Java类上,然后通过Spring的扫描机制找到标注了该注解的Java类,该Java类就成为了Spring MVC的处理器类。

@Controller
public class UserController {
    @RequestMapping("/helloSpring")
    public String sayHello() {
        System.out.println("访问到helloSpring页面");
        return "hello";
    }
}

//在spring-mvc.xml中配置了spring可以扫描的Controller,同时可定位到`/WEB-INF/pages/hello.jsp`

2.4 适配器(@RequestMapping注解)

@RequestMapping注解用于建立请求URL和Handler(处理器)之间的映射关系,该注解可以标注在方法上和类上。

  1. 适配器标注的位置
  • 标注到类上

当@RequestMapping注解标注在类上时,@RequestMapping的value属性值相当于本处理器类的命名空间,即访问该处理器类下的任意处理器都需要带上这个命名空间。

URL = 项目访问路径 + 处理器类的映射路径 + 处理器的映射路径
  • 标注到方法上

当@RequestMapping注解标注在方法上时,该方法就成了一个可以处理客户端请求的Handler(处理器),它会在Spring MVC接收到对应的URL请求时被执行。

URL = 项目访问路径 + 处理方法的映射路径
  1. @RequestMapping注解属性
  • 属性介绍
属性名类型描述
nameString可选属性,用于为映射地址指定别名。
valueString[]可选属性,也是默认属性,用于指定请求的URL。
1.当value属性为唯一属性时,此value可以省略不写。
2.映射单个的请求URL,也可以将多个请求映射到一个方法上:@RequestMapping(value = {“/addUser”,“/deleteUser”})
methodRequestMethod[]可选属性,用于指定该方法可以处理哪种类型的请求方式,method若不匹配则不能访问:RequestMethod.GET。
paramsString[]可选属性,用于指定客户端请求中参数的值必须包含哪些参数的值,才可以通过其标注的方法处理。
headersString[]可选属性,用于指定客户端请求中,必须包含哪些header的值,才可以通过其标注的方法处理。
consumesString[]可选属性,用于指定处理请求的提交内容类型(Content-type),如text/html,application/json。
producesString[]可选属性,用于指定返回的内容类型,仅当request请求头中的(Accept)类型中包含该指定类型才返回。
  • 请求映射方式

基于请求方式的URL路径映射

@GetMapping:匹配GET方式的请求。
@PostMapping:匹配POST方式的请求。
@PutMapping:匹配PUT方式的请求。
@DeleteMapping:匹配DELETE方式的请求。
@PatchMapping:匹配PATCH方式的请求。

基于Ant风格的URL路径映射(通配符风格)

?匹配任何单字符;
*匹配0或者任意数量的字符;
**匹配0或者多级目录。 
    
//最长匹配原则:当映射路径中同时使用多个通配符时,会有通配符冲突的情况。当多个通配符冲突时,如果一个请求路径同时满足两个或多个Ant风格的映射路径匹配规则,那么请求路径最终会匹配满足规则字符最多的路径。

基于REST风格的URL路径映射

RESTful就是把请求参数变成请求路径

http://.../findUserById?id=1
=》
http://.../user/id/1

​ RESTful风格在HTTP请求中,通过GET 、POST 、PUT和DELETE 4个动词对应四种基本请求操作,具体如下所示。

  • GET用于获取资源

  • POST用于新建资源

  • PUT用于更新资源

  • DELETE用于删除资源

使用RESTful风格的优势在于路径的书写比较简便,并且通过地址无法得知做的是何种操作,可以隐藏资源的访问行为

三、SpringMVC数据绑定与响应

3.1 数据绑定

**1.定义:**Spring MVC中将请求消息数据与处理器的形参建立连接的过程就是Spring MVC的数据绑定。

2.数据绑定的原理

image-20241220192116300(1)Spring MVC将ServletRequest对象传递给DataBinder。

(2)将处理器方法的形参对象传递给DataBinder。

(3)DataBinder调用ConversionService组件进行数据类型转换、数据格式化等工作,并将ServletRequest对象中的消息填充到参数对象中。

(4)调用Validator组件对已经绑定了请求消息数据的参数对象进行数据合法性校验。

(5)校验完成后会生成数据绑定结果BindingResult对象,Spring MVC会将BindingResult对象中的内容赋给处理方法的相应参数。

3.2 简单数据绑定

简单数据是指请求中的参数不是基于列表或多层级的数据,参数直接和服务器端的形参或形参属性进行绑定。

  1. 默认类型的数据绑定
默认类型说明
HttpServletRequest获取请求信息
HttpServletResponse处理响应信息
HttpSession获取session中存放的对象
Model/ModelMap可以设置model数据,model数据会填充到request域。

案例:

@RequestMapping("/getUserId")
public void getUserId(HttpServletRequest request) {
    String id = request.getParameter("id");
    System.out.println("用户的id为:" + id);
}
  1. 简单数据类型的绑定
  • 定义:简单数据类型的绑定,就是指Java中基本类型(如int、double、String等)的数据绑定。
  • 要求:只需客户端请求参数的名称和处理器的形参名称一致即可,请求参数会自动映射并匹配到处理器的形参完成数据绑定。
  • 案例:
@RequestMapping("/getUserName")
public void getUserName(String username) {
    System.out.println(username);
}
  • @RequestParam注解

作用:处理客户端参数与处理器形参名称不一致

属性:

属性说明
valuename属性的别名,这里指参数的名称,即入参的请求参数名称,如value="name"表示请求的参数中,名称为name的参数的值将传入。如果当前@RequestParam注解只使用vaule属性,则可以省略value属性名,如@RequestParam(“name”)
name绑定的请求参数名称
required用于指定参数是否必须,默认是true,表示请求中一定要有相应的参数
default Value形参的默认值,表示如果请求中没有同名参数时的默认值

案例:

@RequestMapping("/getUserName")
public void getUserName(@RequestParam(value = "name", defaultValue = "xyx") String username) {
    System.out.println(username);
}
  • @PathVariable注解

作用:当请求的映射方式是REST风格时,,Spring MVC提供了@PathVariable注解,通过 @PathVariable注解可以将URL中占位符参数绑定到处理器的形参中。

属性:

属性说明
value用于指定URL中占位符名称。
required是否必须提供占位符,默认值为true

案例:

@RequestMapping("/getUserName/{name}")
public void getUserNameByREST(@PathVariable(value = "name") String username) {
    System.out.println(username);
}

如果请求路径中占位符的参数名称和方法形参名称一致,那么@PathVariable注解的value属性可以省略。

  1. POJO绑定
  • 定义:将所有关联的请求参数封装在一个POJO中,然后在方法中直接使用该POJO作为形参来完成数据绑定

案例:

@RequestMapping("/login")
public void login(User user) {
    System.out.println("用户名为" + user.getUsername());
    System.out.println("密码为" + user.getPassword());
}

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>登录</title>
</head>
<body>
<form method="post" action="${pageContext.request.contextPath}/login">
    用户名:<input name="username" type="text"><br>&nbsp;&nbsp;码:<input name="password" type="password"><br>
    <input name="submit" type="submit" value="提交"><br>
</form>
</body>
</html>
  • 解决请求参数的中文乱码

原因:由于html或者jsp中指定了请求的编码为utf-8,而Tomcat的解码会以ISO-8859-1解码,所以会出现乱码。

解决方法(POST请求):在前端控制器中(web.xml)添加如下过滤器

<filter>	
    <filter-name>CharacterEncodingFilter</filter-name>	  <filter-class> 		org.springframework.web.filter.CharacterEncodingFilter
    </filter-class>
	<init-param>
       <param-name>encoding</param-name>
       <param-value>UTF-8</param-value>
    </init-param>
</filter>
<filter-mapping>
   <filter-name>CharacterEncodingFilter</filter-name>
   <url-pattern>/*</url-pattern>	
</filter-mapping>

解决方法(GET请求):Tomcat 8后无需配置

String username = new String(user.getUsername().getBytes(ISO8859-1),UTF-8);

3.3复杂数据绑定

在开发基于 Spring MVC 的 Web 应用程序时,数据绑定和页面跳转是非常重要的功能。本篇博客将通过一个简单的示例,介绍如何在 Spring MVC 中进行简单和复杂的数据绑定,以及如何在控制器中进行页面跳转。

1. 简单数据绑定

Spring MVC 支持多种方式的数据绑定,最常见的包括:

  • 默认数据类型绑定:Spring 自动根据请求参数与方法参数类型进行匹配。
  • 简单数据类型绑定:支持直接将表单参数绑定到方法参数。
  • 简单POJO的绑定:支持将表单提交的数据绑定到 POJO 对象。
1.1 默认数据类型的绑定
java@RequestMapping("/getUserId")
public void getUserId(HttpServletRequest request) {
    String id = request.getParameter("id");
    System.out.println(id);
}

在上面的代码中,getUserId 方法通过 HttpServletRequest 获取请求中的参数。

1.2 简单数据类型绑定
java@RequestMapping("/getUserIdAndName1")
public void getUserIdAndName1(String username, int id) {
    System.out.println("id为" + id + "的用户名为:" + username);
}

Spring 会自动将请求参数绑定到方法的参数 usernameid 上。

1.3 简单数据类型与请求参数不一致
java@RequestMapping("/getUserIdAndName2")
public void getUserIdAndName2(@RequestParam(value = "name", defaultValue = "xyx") String username, int id) {
    System.out.println("id为" + id + "的用户名为:" + username);
}

通过 @RequestParam 注解,可以将请求中的 name 参数绑定到 username 上,如果请求中没有该参数,则使用默认值 "xyx"

1.4 REST 风格的路径变量绑定
java@RequestMapping("/getUserIdAndName3/{name}")
public void getUserIdAndName3(@PathVariable("name") String username) {
    System.out.println("用户名为:" + username);
}

使用 @PathVariable 注解,可以将 URL 中的变量 name 绑定到方法的参数 username 上。

2. 复杂数据绑定

Spring MVC 还支持复杂的数据绑定,包括数组、集合、以及复杂的 POJO 对象。

2.1 数组绑定
java@RequestMapping("/getUserArray")
public void getUserArray(String[] nameList) {
    for (String name : nameList) {
        System.out.println(name);
    }
}

通过简单地定义一个 String[] 类型的参数,可以自动绑定请求中的数组数据。

2.2 集合绑定
java@RequestMapping("/getUserList")
public void getUserList(@RequestParam("name") List<String> nameList) {
    for (String name : nameList) {
        System.out.println(name);
    }
}

使用 @RequestParam 可以将请求参数绑定到 List 集合中,Spring 会根据请求的多个参数自动填充集合。

2.3 复杂POJO绑定
java@RequestMapping("/showOrder")
public void showOrder(User user) {
    List<Order> orderList = user.getOrderList();
    List<String> address = user.getAddress();
    for (int i = 0; i < orderList.size(); i++) {
        System.out.println("订单号为:" + orderList.get(i).getOrderId() + ",派送地址为:" + address.get(i));
    }
}

Spring 会自动将请求中的数据绑定到 User 对象中的 orderListaddress 字段。

3. 页面跳转

Spring MVC 提供了多种方式进行页面跳转,常见的方式包括:

  • 返回值为 void:在没有视图解析器配置时,跳转到请求路径名对应的视图。
  • 返回值为 String:通过视图解析器配置,跳转到特定的页面。
  • 返回值为 ModelAndView:可以同时设置模型数据和视图。
3.1 返回 void 类型
java@RequestMapping("/register")
public void register1(User user) {
    System.out.println("用户名为:" + user.getUsername());
    System.out.println("密码为:" + user.getPassword());
}

如果视图解析器配置正确,Spring 会根据请求路径来解析视图名称。如果没有配置视图解析器,会报 500 错误。

3.2 返回 String 类型
java@RequestMapping("/register")
public String register2(User user) {
    System.out.println("用户名为:" + user.getUsername());
    System.out.println("密码为:" + user.getPassword());
    return "login";  // 跳转到 login.jsp 页面
}

如果配置了视图解析器,返回值 "login" 会被解析为 login.jsp 页面。

3.3 请求转发
java@RequestMapping("/register")
public String register3(User user) {
    System.out.println("用户名为:" + user.getUsername());
    System.out.println("密码为:" + user.getPassword());
    return "forward:Jsp/login.jsp";  // 请求转发到 login.jsp 页面
}

forward: 前缀表示请求转发,Spring 会将请求转发到指定的 JSP 页面。

3.4 重定向
java@RequestMapping("/login")
public String login(User user) {
    System.out.println("用户名为:" + user.getUsername());
    System.out.println("密码为:" + user.getPassword());
    return "redirect:https://cat.chatavx.com/#/home";  // 重定向到外部页面
}

redirect: 前缀表示重定向,Spring 会将请求重定向到指定的 URL。

4. 携带数据到页面

4.1 使用 HttpServletRequest 携带数据
java@RequestMapping("/showPageByRequest")
public String showPageByRequest(HttpServletRequest request) {
    request.setAttribute("username", "解耀轩");
    return "showPage";
}

通过 HttpServletRequest,可以将数据添加到请求范围,然后在 JSP 页面中使用该数据。

4.2 使用 Model 携带数据
java@RequestMapping("/showPageByModel")
public String showPageByModel(Model model) {
    model.addAttribute("username", "杨浩文");
    return "showPage";
}

通过 Model 对象可以将数据添加到模型中,并且在视图页面中访问。

4.3 使用 ModelAndView 携带数据
java@RequestMapping("/showPageByModelAndView")
public ModelAndView showPage() {
    ModelAndView modelAndView = new ModelAndView();
    modelAndView.addObject("username", "太原理工大学");
    modelAndView.setViewName("showPage");
    return modelAndView;
}

ModelAndView 可以同时设置数据和视图,常用于需要返回数据和视图的场景。

pojo层

package com.tyut.pojo;

import java.util.Map;

public class Order {
    private int orderId;
    private Map<String, String> orderMap;

    public Map<String, String> getOrderMap() {
        return orderMap;
    }

    public void setOrderMap(Map<String, String> orderMap) {
        this.orderMap = orderMap;
    }

    public int getOrderId() {
        return orderId;
    }

    public void setOrderId(int orderId) {
        this.orderId = orderId;
    }
}
package com.tyut.pojo;

import java.util.List;

public class User {
    private String username;
    private String password;
    private List<Order> orderList;
    private List<String> address;

    public List<Order> getOrderList() {
        return orderList;
    }

    public void setOrderList(List<Order> orderList) {
        this.orderList = orderList;
    }

    public List<String> getAddress() {
        return address;
    }

    public void setAddress(List<String> address) {
        this.address = address;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置Spring MVC要扫描的包  -->
    <context:component-scan base-package="com.tyut.controller"/>

    <!-- 开启视图解析器   -->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>

</beans>
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 配置DispatcherServlet   -->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!-- 设置初始化参数,使得可以在此Servlet加载的时候便可以假造到spring-mvc配置 -->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:spring-mvc.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <!--设置DispatcherServlet要拦截的路径-->
    <servlet-mapping>
        <servlet-name>DispatcherServlet</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
    <!-- 解决中文乱码   -->
    <filter>
        <filter-name>CharacterEncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>CharacterEncodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
</web-app>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值