SpringMVC之请求与响应

简单入门

概述

SpringMVC是一种基于Java的实现MVC设计模型的请求驱动类型的轻量级Web框架,属于SpringFrameWork的后续产品,已经融合在Spring Web Flow中。

SpringMVC 已经成为目前最主流的MVC框架之一,并且随着Spring3.0 的发布,全面超越 Struts2,成为最优 秀的 MVC 框架。它通过一套注解,让一个简单的 Java 类成为处理请求的控制器,而无须实现任何接口。同时 它还支持 RESTful 编程风格的请求。

快速入门

SpringMVC基本逻辑:客户端发起请求,服务器接收请求,执行逻辑并进行视图跳转

Spring MVC中的前端控制器就是 DispatcherServlet,它继承了HttpServlet这个抽象类。前端控制器是Spring MVC的集中访问点,主要职责是调度、流程控制。为了给整个Web项目配置一个前端控制器,需要在web.xml文件中进行如下配置:

<!--配置SpringMVC的前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--        加载spring-mvc.xml-->
        <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>
<!--        默认参数,所有请求都会通过此servlet-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

基本步骤

  1. 导入SpringMVC相关坐标
  2. 在web.xml配置SpringMVC核心控制器DispathcerServlet
  3. 创建Controller类和视图页面
  4. 使用注解配置Controller类中业务方法的映射地址
  5. 配置SpringMVC核心文件:spring-mvc.xml
  6. 客户端发起请求

详细步骤

  1. 导入相关坐标
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.0.5.RELEASE</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.0.5.RELEASE</version>
</dependency>
  1. 配置核心控制器
    <!--配置SpringMVC的前端控制器-->
    <servlet>
        <servlet-name>DispatcherServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<!--        加载spring-mvc.xml-->
        <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>
<!--        默认参数,所有请求都会通过此servlet-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>
  1. 创建Controller类和业务方法并配置注解
// 放到spring容器
@Controller
// 与方法的请求映射组合到一起进行访问,以此区分各个模块
@RequestMapping("/user")
public class UserController {

    // 请求地址  http://localhost:8080/user/quick
    // 请求映射,建立请求URL和处理请求方法之间的关系
    // method属性:指定请求方式
    // params属性:指定限制请求参数的条件,支持简单表达式,要求请求参数的key和value必须和配置的一模一样
    @RequestMapping(value = "/quick", method = RequestMethod.GET)
    public String save(){
        System.out.println("Controller save running....");
        // return要跳转的视图,加/表示从根目录下开始访问,不然相对路径会从http://localhost:8080/user/quick下开始访问
        // forward:转发,redirect:重定向
        return "forward:/success";
    }
}
  1. 创建视图页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Success!</h1>
</body>
</html>
  1. 创建spring-mvc.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       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 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

<!--    Controller组件扫描-->
    <context:component-scan base-package="com.itheima.controller"/>
  1. 客户端测试

访问测试地址:http://localhost:8080/user/quick

控制台打印:Controller save running....

页面显示:Success!

过程解析

客户端,即浏览器发起访问请求到Tomcat引擎,Tomcat接收客户端请求,解析请求资源地址;创建代表请求的req对象以及代表响应的resp对象;调用目标资源;获得resp中的内容,组装成http响应返回客户端。

XML配置解析

视图解析

<!--配置内部资源视图解析器-->
    <bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--        前缀-->
        <property name="prefix" value="/jsp/"/>
<!--        后缀-->
        <property name="suffix" value=".jsp"/>
    </bean>

配置视图解析器之后,在Controller类中的return跳转就不需要加入要跳转的页面后缀以及页面的上一级目录(前缀)。

请求与响应

以下代码示例均在Controller类中,同时所有配置文件遵循文章上面配置文件。Controller类在SpringMVC中负责处理由DispatcherServlet分发的请求,把用户请求的数据经过业务处理层处理之后封装成一个Model,然会把该Model返回给对应的View进行展示。

数据响应

页面跳转

  • 直接返回字符串

此种方式会将返回的字符串与视图解析器的前后缀拼接后跳转。

@RequestMapping("/quick")
public String quickMethod() {
	return "index";
}
<property name="prefix" value="/WEB-INF/views/"/>
<property name="suffix" value=".jsp"/>

请求地址:localhost:3306/quick

转发资源地址:/WEB-INF/views/index.jsp

返回带有前缀的字符串:

转发:forward:/WEB-INF/views/index.jsp

重定向:redirect:/index.jsp

  • 通过ModelAndView对象返回
// 返回ModelAndView
@RequestMapping(value = "/quick2")
public ModelAndView save2() {
    /*
    * Model:封装数据
    * View:展示数据
    * */
    ModelAndView modelAndView = new ModelAndView();
    // 设置模型数据放到request域中
    modelAndView.addObject("username", "itcast");
    // 设置视图名称
    modelAndView.setViewName("success");
    return modelAndView;
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <h1>Success!</h1>
<h1>${username}</h1>
</body>
</html>

直接返回ModelAndView对象,Model用于封装数据,其中的key需要与视图中的值一致,View用于设置视图名称,用于返回到指定视图(视图即jsp页面),View参数可以设置forward或redirect属性。

也可以直接在方法里直接定义ModelAndView形参,省略掉新建对象的步骤,代码如下所示。

@RequestMapping(value = "/quick3")
public ModelAndView save3(ModelAndView modelAndView) {
    modelAndView.addObject("username", "itheima");
    modelAndView.setViewName("success");
    return modelAndView;
}

也可以返回String字符串,指定要跳转到的视图,同时在形参里定义Model,设置模型数据,代码如下所示。

@RequestMapping(value = "/quick4")
public String save4(Model model) {
    model.addAttribute("username", "it4");
    return "success";
}

也可以直接设置request,返回String字符串,此方法不常用,代码如下所示。

// 不常用
@RequestMapping(value = "/quick5")
public String save5(HttpServletRequest request) {
    request.setAttribute("username", "it5");
    return "success";
}

回写数据

  • 返回普通字符串
// 回写普通字符串
@RequestMapping(value = "/quick6")
public void save6(HttpServletResponse response) throws Exception{
    response.getWriter().print("hello world");
}

通过普通的response直接将字符串返回到控制台,也可以通过@ResponseBody注解回写字符串,该注解告知spring-mvc框架,该方法不进行视图跳转,直接进行数据响应,在控制台直接打印字符串。同时需要在spring-mvc.xml中打开spring-mvc的注解驱动

<!--    mvc的注解驱动-->
    <mvc:annotation-driven/>
// 使用注解回写普通字符串,告知spring-mvc框架,该方法不进行视图跳转,直接进行数据响应
@ResponseBody
@RequestMapping(value = "/quick7")
public String save7() throws Exception{
    return "hello world";
}
  • 返回对象

通过SpringMVC帮助我们对对象或集合进行json字符串的转换并回写,为处理器适配器配置消息转换参数, 指定使用jackson进行对象或集合的转换,因此需要在spring-mvc.xml中使用mvc的注解驱动代替json的复杂配置。

// 使用json转换工具返回对象或集合
@ResponseBody
@RequestMapping(value = "/quick10")
public User save10() {
    User user = new User();
    user.setUsername("lisi");
    user.setAge(30);
    return user;
}

使用json转换工具返回对象或集合时,可以直接new一个实体类对象,同时使用实体类对象中的set方法传入参数并直接返回对象。

  • 返回json字符串
// 返回json格式字符串
@ResponseBody
@RequestMapping(value = "/quick8")
public String save8() throws Exception {
    return "{\"username\":\"zhangsan\",\"age\":18}";
}

json字符串也可以使用jackson返回json格式字符串,但是这里不会用到,所以不会赘述,以后会单独在关于json里面详解。

数据请求

获得请求参数

客户端请求参数的格式是:name=value&name=value......

客户端要获得请求的参数,有时还需要进行数据的封装,SpringMVC可以接收如下类型的参数:

  • 基本类型参数
// 获得基本类型参数
@ResponseBody
@RequestMapping(value = "/quick11")
public void save11(String username, int age) throws IOException{
    System.out.println(username);
    System.out.println(age);
}

客户端请求地址:localhost://3306/user/quick11?username=lisi&age=14

控制台打印:lisi \n14

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。

当请求的参数名称与Controller的业务方法参数名称不一致时,可以使用SpringMVC注解来解决这个问题,也称参数绑定,代码如下所示。

// 获得基本类型参数
// 参数绑定注解:@requestParam:当请求的参数名称与Controller的业务方法参数名称不一致时,就需要通过@requestParam注解显示绑定
@ResponseBody
@RequestMapping(value = "/quick16")
// 使用@RequestParam将请求的name绑定到username
// required属性:是否必须包括请求的参数,默认为true,提交时如果没有此参数则报错
// defaultValue属性:当没有指定请求参数时,则使用指定的默认值赋值
public void save16(@RequestParam(value = "name", required = false, defaultValue = "tom") String username) throws IOException{
    System.out.println(username);
}
  • POJO类型参数
// 获得POJO类型参数
@ResponseBody
@RequestMapping(value = "/quick12")
public void save12(User user) throws IOException {
    System.out.println(user );
}

客户端请求地址:localhost://3306/user/quick11?username=lisi&age=14

控制台打印:User{username='lisi', age=18}

Controller中的业务方法的参数名称要与请求参数的name一致,参数值会自动映射匹配。在这里业务方法中的参数名称是一个POJO类,请求时要请求类中包含的所有属性,服务器获取的是POJO类型的对象。

  • 数组类型参数
// 获得数组类型参数
@ResponseBody
@RequestMapping(value = "/quick13")
public void save13(String[] strs) throws IOException {
    System.out.println(Arrays.asList(strs));
}

客户端请求地址:localhost:8080/user/quick13?strs=111&strs=222&strs=333

控制台打印:[111, 222, 333]

Controller中的业务方法数组名称与请求参数的name一致,参数值会自动映射匹配。

  • 集合类型参数
// 获得集合类型参数
// 获得集合参数时,要将集合参数包装到一个POJO中
@ResponseBody
@RequestMapping(value = "/quick14")
// 使用VO创建存放User的List,利用表单提交List
public void save14(VO vo) throws IOException {
    System.out.println(vo);
}
package com.itheima.domain;

import java.util.List;

public class VO {
    private List<User> userList;

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }

    @Override
    public String toString() {
        return "VO{" +
                "userList=" + userList +
                '}';
    }
}

定义一个VO类,类中有实体类User的List集合与对应的get、set方法,业务方法会使用VO类进行请求数据的获取。同时因为在浏览器发起请求过于复杂,所以借助一个form表单来提交数据。

<%--
  Created by IntelliJ IDEA.
  User: zzc
  Date: 2021/12/16
  Time: 20:18
  To change this template use File | Settings | File Templates.
--%>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<form action="${pageContext.request.contextPath}/user/quick14" method="post">
<%--    表明是第几个User对象的username,age--%>
<%--    userList里第一个对象的username--%>
    <input type="text" name="userList[0].username"><br/>
    <input type="text" name="userList[0].age"><br/>
    <input type="text" name="userList[1].username"><br/>
    <input type="text" name="userList[1].age"><br/>
    <input type="submit">
</form>
</body>
</html>

请求数据乱码问题

<!--    配置全局过滤的filter解决post请求乱码-->
    <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.xml中配置全局过滤的filter即可解决。

获得Servlet相关API

SpringMVC支持使用原始ServletAPI对象作为控制器方法的参数进行注入,常用的对象如下:

  • HttpServletRequest
  • HttpServletResponse
  • HttpSession
// 获得Servlet相关API
@ResponseBody
@RequestMapping(value = "/quick19")
public void save19(HttpServletRequest request, HttpServletResponse response, HttpSession session) throws IOException{
    System.out.println(request);
    System.out.println(response);
    System.out.println(session);
}

获得请求头

使用@RequestHeader可以获得请求头信息,相当于web阶段学习的request.getHeader(name) @RequestHeader注解的属性如下:

  • value:请求头的名称
  • required:是否必须携带此请求头
// 获得请求头:user_agent
@ResponseBody
@RequestMapping(value = "/quick20")
public void save20(@RequestHeader(value = "User-Agent", required = false) String user_agent) throws IOException{
    System.out.println(user_agent);
}

使用@CookieValue可以获得指定Cookie的值,@CookieValue注解的属性如下:

  • value:指定cookie的名称
  • required:是否必须携带此cookie
// 获得请求头
@ResponseBody
@RequestMapping(value = "/quick21")
public void save21(@CookieValue(value = "JSESSIONID") String jsessionId) throws IOException{
    System.out.println(jsessionId);
}
posted @ 2021-12-18 20:09  喵酱的花椒  阅读(303)  评论(0)    收藏  举报