SpringMVC 入门、请求、响应
阅读原文时间:2021年12月19日阅读:1

目录

SpringMVC 概述

SSM 三层架构

  • 表现层:负责数据展示

  • 业务层:负责业务处理

  • 数据层:负责数据操作

MVC(Model View Controller)是一种用于设计及创建 Web 应用程序表现层的模式。

  • Model(模型):数据模型,用于封装数据

  • View(视图):页面视图,用于展示数据

    • jsp
    • html
  • Controller(控制器):处理用户交互的调度器,用于根据用户需求处理程序逻辑

    • Servlet
    • SpringMVC

SpringMVC 是一种基于 Java 实现的、MVC 模型的、轻量级的 Web 框架。

SpringMVC 优点

  1. 使用简单
  2. 性能突出(相比现有的框架技术)
  3. 灵活性强

SpringMVC 工作流程分析:

  1. 服务器启动:

  2. 处理请求:

实现示例

  1. 导入 SpringMVC 相关的 Maven 依赖:

    javax.servlet javax.servlet-api 3.1.0 provided

    javax.servlet.jsp jsp-api 2.1 provided

    org.springframework spring-context 5.1.9.RELEASE

    org.springframework spring-web 5.1.9.RELEASE

    org.springframework spring-webmvc 5.1.9.RELEASE

  2. 定义表现层处理器 Controller(等同于 Servlet),并配置成 Spring 的 bean:

    @Controller
    public class UserController {

    public void save(){
        System.out.println("user mvc controller is running ...");
    }

    }

  3. 定义 SpringMVC 配置文件(格式与 Spring 配置文件一致):


    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">

  4. web.xml 中配置 SpringMVC 核心控制器,用于将请求转发到对应的具体业务处理器 Controller 中(等同于 Servlet 配置):

    DispatcherServlet org.springframework.web.servlet.DispatcherServlet contextConfigLocation classpath*:spring-mvc.xml
    DispatcherServlet /

  5. 设定具体 Controller 的访问路径与返回页面(等同于 Servlet 在 web.xml 中的配置):

    // 设定当前方法的访问映射地址
    @RequestMapping("/save")
    // 设置当前方法返回值类型为String,用于指定请求完成后跳转的页面
    public String save(){
    System.out.println("user mvc controller is running …");
    // 设定具体跳转的页面
    return "success.jsp";
    }

  1. DispatcherServlet(前端控制器):是整体流程控制的中心,由其调用其它组件处理用户的请求,有效降低了组件间的耦合性。
  2. HandlerMapping(处理器映射器):负责根据用户请求找到对应具体的 Handler 处理器。
  3. Handler(处理器):业务处理的核心类,通常由开发者编写,描述具体的业务。
  4. HandlAdapter(处理器适配器):通过它对处理器进行执行。
  5. View Resolver(视图解析器):将处理结果生成 View 视图。
  6. View(视图):最终产出结果,常用视图如 jsp、html。

SpringMVC 基础配置

Controller 加载控制

SpringMVC 的处理器对应的 bean 必须按照规范格式开发,为了避免加入无效的 bean,可通过 bean 加载过滤器进行包含设定或排除设定。

例如,表现层 bean 标注通常设定为 @Controller,因此可以通过注解名称进行过滤控制:

<context:component-scan base-package="com">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>

静态资源加载

<!--放行指定类型静态资源配置方式-->
<mvc:resources mapping="/img/**" location="/img/"/>
<mvc:resources mapping="/js/**" location="/js/"/>
<mvc:resources mapping="/css/**" location="/css/"/>

<!--SpringMVC提供的通用资源放行方式-->
<mvc:default-servlet-handler/>

中文乱码处理

web.xml

<!-- 乱码处理过滤器,与Servlet中使用的完全相同,差异之处在于处理器的类由Spring提供 -->
<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 和 spring-mvc.xml 。

注意

实现示例

  1. 使用注解形式,将 SpringMVC 核心配置文件替换为配置类

    package com.config;

    import org.springframework.context.annotation.ComponentScan;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.FilterType;
    import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
    import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
    import org.springframework.web.servlet.mvc.Controller;

    @Configuration
    @ComponentScan(
    value="com",
    includeFilters = @ComponentScan.Filter(type = FilterType.ANNOTATION, classes={Controller.class})
    )
    public class SpringMvcConfig implements WebMvcConfigurer {

    // 注解配置放行指定资源格式
    // @Override
    // public void addResourceHandlers(ResourceHandlerRegistry registry) {
    //     registry.addResourceHandler("/img/**").addResourceLocations("/img/");
    //     registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    //     registry.addResourceHandler("/css/**").addResourceLocations("/css/");
    // }
    
    // 注解配置通用放行资源的格式
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();;
    }

    }

  2. 替换 web.xml:基于 servlet3.0 规范,自定义 Servlet 容器初始化配置类,加载 SpringMVC 核心配置类

    package com.config;

    import org.springframework.web.context.WebApplicationContext;
    import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
    import org.springframework.web.filter.CharacterEncodingFilter;
    import org.springframework.web.servlet.support.AbstractDispatcherServletInitializer;

    import javax.servlet.DispatcherType;
    import javax.servlet.FilterRegistration;
    import javax.servlet.ServletContext;
    import javax.servlet.ServletException;
    import java.util.EnumSet;
    import java.util.Objects;

    public class ServletInitConfig extends AbstractDispatcherServletInitializer {
    /*
    创建 Servlet 容器时,使用注解的方式加载 SpringMVC 配置类中的信息,并加载成 Web 专用的 ApplicationContext 对象
    该对象放入了 ServletContext 范围,后期在整个 Web 容器中可以随时获取调用
    */
    @Override
    protected WebApplicationContext createServletApplicationContext() {
    AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
    ctx.register(SpringMvcConfig.class);
    return ctx;
    }

    // 注解配置映射地址方式,服务于 SpringMVC 的核心控制器 DispatcherServlet
    @Override
    protected String[] getServletMappings() {
        return new String[]{"/"};
    }
    
    @Override
    protected WebApplicationContext createRootApplicationContext() {
        return null;
    }
    
    // 乱码处理作为过滤器,在 servlet 容器启动时进行配置
    @Override
    public void onStartup(ServletContext servletContext) throws ServletException {
        super.onStartup(Objects.<ServletContext>requireNonNull(servletContext));
        CharacterEncodingFilter cef = new CharacterEncodingFilter();
        cef.setEncoding("UTF-8");
        FilterRegistration.Dynamic registration = servletContext.addFilter("characterEncodingFilter", cef);
        registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST, DispatcherType.FORWARD,
                DispatcherType.INCLUDE), false, "/*");
    }

    }

请求

@RequestMapping 使用

  • 类型:类注解;方法注解

  • 位置:处理器类定义上方;处理器类中的方法定义上方

  • 作用:为当前处理器中所有方法设定公共的访问路径前缀;绑定请求地址与对应处理方法间的关系

    // 示例:方法注解
    @Controller
    public class UserController {
    // 访问 URI:/user/requestURL1
    @RequestMapping("/requestURL1")
    public String requestURL2() {
    return "page.jsp";
    }
    }

    // 示例:类注解
    @Controller
    @RequestMapping("/user")
    public class UserController {
    // 访问 URI:/user/requestURL2
    @RequestMapping("/requestURL2")
    public String requestURL2() {
    return "page.jsp";
    }
    }

常用属性

@RequestMapping(
    value="/requestURL3",  // 设定请求路径,与path属性、value属性相同
    method = RequestMethod.GET,  // 设定请求方式
    params = "name",  // 设定请求参数条件
    headers = "content-type=text/*",  // 设定请求消息头条件
    consumes = "text/*",  // 用于指定可以接收的请求正文类型(MIME类型)
    produces = "text/*"  // 用于指定可以生成的响应正文类型(MIME类型)
)
public String requestURL3() {
    return "/page.jsp";
}


// URL 访问:http://localhost:8080/requestParam1?name=xiaoming&age=14
@RequestMapping("/requestParam1")
public String requestParam1(String name ,String age){
    System.out.println("name="+name+", age="+age);
    return "page.jsp";
}
  • 类型:形参注解
  • 位置:处理器类中的方法形参前方
  • 作用:绑定请求参数与处理方法形参间的关系

示例

// http://localhost:8080/requestParam2?userName=Jock
@RequestMapping("/requestParam2")
public String requestParam2(@RequestParam(
                            name = "userName",
                            required = true,
                            defaultValue = "xiaohuang") String name) {
    System.out.println("name="+name);
    return "page.jsp";
}
  • 当未传参即直接访问“/requestParam2”时,方法会取默认值“xiaohuang”。

  • 当配置了“required=true”但未配置“defaultValue”时,访问时不传参则会报 400 错。

POJO

当使用 POJO(简单 Java 对象)时,传参名称与 POJO 类属性名保持一致即可。

  • POJO 类

    package com.bean;

    public class User {

    private String name;
    private Integer age;
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public Integer getAge() {
        return age;
    }
    
    public void setAge(Integer age) {
        this.age = age;
    }

    }

  • Controller

    // URL 访问:http://localhost:8080/requestParam3?name=xiaodong&age=18
    @RequestMapping("/requestParam3")
    public String requestParam3(User user){
    System.out.println("name="+user.getName());
    return "page.jsp";
    }

参数冲突

当 POJO 的属性与其他形参出现同名问题时,将被同时赋值。

// 访问 URL:http://localhost:8080/requestParam4?name=xiaoyi&age=14
@RequestMapping("/requestParam4")
public String requestParam4(User user, String age){
    System.out.println("user.age="+user.getAge()+", age="+age);  // user.age=14, age=14
    return "page.jsp";
}

建议使用 @RequestParam 注解进行区分。

复杂对象类型

当对象中出现对象属性时,则要求入参名称与对象层次结构名称保持一致。

对象集合

1)当复杂对象中出现用 List 保存对象数据时,要求入参名称与对象层次结构名称保持一致,并使用数组格式描述集合中对象的位置。

注意:[The valid characters are defined in RFC 7230 and RFC 3986

问题解决](https://www.cnblogs.com/aeolian/p/13915486.html)

2)当复杂对象中出现用 Map 保存对象数据时,要求入参名称与对象层次结构名称保持一致,并使用映射格式描述集合中对象的位置。

  • bean:

    public class User {
    private String name;
    private Integer age;
    private Map addressMap;
    }

    public class Address {
    private String province;
    private String city;
    private String address;
    }

  • controller:

    // 访问 URL:http://localhost:8080/requestParam8?addressMap['home'].province=bj&addressMap['job'].province=tj
    @RequestMapping("/requestParam8")
    public String requestParam8(User user){
    System.out.println("user.addressMap="+user.getAddressMap());
    return "page.jsp";
    }

    // 访问 URL:http://localhost:8080/requestParam9?nick=xiaoming1&nick=xiaoming2
    @RequestMapping("/requestParam9")
    public String requestParam9(String[] nick){
    System.out.println(nick[0]+", "+nick[1]); // xiaoming1, xiaoming2
    return "page.jsp";
    }

    // 访问 URL:http://localhost:8080/requestParam10?nick=xiaoming1&nick=xiaoming2
    @RequestMapping("/requestParam10")
    public String requestParam10(@RequestParam("nick") List nick){
    System.out.println(nick); // [xiaoming1, xiaoming2]
    return "page.jsp";
    }

注意:

  • SpringMVC 默认将 List 作为对象处理,赋值前先创建对象,然后将 nick 作为对象的属性进行处理。而由于 List 是接口,无法创建对象,报无法找到构造方法异常;修复类型为可创建对象的 ArrayList 类型后,对象可以创建,但没有 nick 属性,因此数据为空。

  • 此时需要告知 SpringMVC 的处理器 nick 是一组数据,而不是一个单一数据。

  • 因此通过 @RequestParam 注解,将数量大于 1 个的 names 参数打包成参数数组后, SpringMVC 才能识别该数据格式,并判定形参类型是否为数组或集合,并按数组或集合对象的形式操作数据。

SpringMVC 会对接收的参数进行自动类型转换,该工作通过 Converter 接口实现。

标量转换器

  • StringToBooleanConverter String —> Boolean
  • ObjectToStringConverter Object —> String
  • StringToNumberConverterFactory String —> Number( Integer、Long 等)
  • NumberToNumberConverterFactory Number子类型之间(Integer、Long、Double 等)
  • StringToCharacterConverter String —> java.lang.Character
  • NumberToCharacterConverter Number子类型(Integer、Long、Double 等) —> java.lang.Character
  • CharacterToNumberFactory java.lang.Character —> Number 子类型(Integer、Long、Double 等)
  • StringToEnumConverterFactory String —> enum 类型
  • EnumToStringConverter enum 类型 —> String
  • StringToLocaleConverter String —> java.util.Local
  • PropertiesToStringConverter java.util.Properties —> String
  • StringToPropertiesConverter String —> java.util.Properties

集合、数组相关转换器

  • ArrayToCollectionConverter 数组 —> 集合(List、Set)
  • CollectionToArrayConverter 集合(List、Set) —> 数组
  • ArrayToArrayConverter(数组间转换)
  • CollectionToCollectionConverter 集合间(List、Set)
  • MapToMapConverter Map间
  • ArrayToStringConverter 数组 —> String 类型
  • StringToArrayConverter String —> 数组(实现方式为 trim 后使用 "," 进行 split)
  • ArrayToObjectConverter 数组 —> Object
  • ObjectToArrayConverter Object —> 单元素数组
  • CollectionToStringConverter 集合(List、Set) —> String
  • StringToCollectionConverter String —> 集合(List、Set)(实现方式为 trim 后使用 "," 进行 split)
  • CollectionToObjectConverter 集合 —> Object
  • ObjectToCollectionConverter Object —> 单元素集合

默认转换器

  • ObjectToObjectConverter(Object 间转换)
  • IdToEntityConverter Id —> Entity
  • FallbackObjectToStringConverter Object —> String

配置版:声明自定义的转换格式并覆盖系统转换格式

<!-- 启用自定义Converter -->
<mvc:annotation-driven conversion-service="conversionService"/>
<!-- 1.设定格式类型Converter,注册为Bean,受SpringMVC管理 -->
<bean id="conversionService"
      class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
    <!-- 2.自定义Converter格式类型设定,该设定使用的是同类型覆盖的思想 -->
    <property name="formatters">
        <!-- 3.使用set保障相同类型的转换器仅保留一个,避免冲突 -->
        <set>
            <!-- 4.设置具体的格式类型 -->
            <bean class="org.springframework.format.datetime.DateFormatter">
                <!-- 5.类型规则 -->
                <property name="pattern" value="yyyy-MM-dd"/>
            </bean>
        </set>
    </property>
</bean>

注解版

  • 名称:@DateTimeFormat

  • 类型:形参注解、成员变量注解

  • 位置:形参前面或成员变量上方

  • 作用:为当前参数或变量指定类型转换规则

  • 注意:依赖注解驱动支持(

  • 范例:

    // 形参前
    // 访问 URL:http://localhost:8080/requestParam11?date=2021-12-12
    @RequestMapping("/requestParam11")
    public String requestParam11(@DateTimeFormat(pattern="yyyy-MM-dd") Date date){
    System.out.println("date="+date);
    return "page.jsp";
    }

    // 成员变量上方
    @DateTimeFormat(pattern="yyyy-MM-dd")
    private Date birthday;

1)实现 Converter 接口,并制定转换前与转换后的类型:

  • 配置:

  • 实现类:

    // 自定义类型转换器,实现Converter接口,接口中指定的泛型即为最终作用的条件
    // 本例中的泛型填写的是,最终出现字符串转日期时,该类型转换器生效
    public class MyDateConverter implements Converter {
    // 重写接口的抽象方法,参数由泛型决定
    public Date convert(String source) {
    DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
    Date date = null;
    // 类型转换器无法预计使用过程中出现的异常,因此必须在类型转换器内部捕获,不允许抛出,框架无法预计此类异常如何处理
    try {
    date = df.parse(source);
    } catch (ParseException e) {
    e.printStackTrace();
    }
    return date;
    }
    }

2)通过注册自定义转换器,将该功能加入到 SpringMVC 的转换服务 ConverterService 中:

<!-- 开启注解驱动,加载自定义格式化转换器对应的类型转换服务 -->
<mvc:annotation-driven conversion-service="conversionService"/>

响应

    // 转发
    @RequestMapping("/showPage1")
    public String showPage1() {
        System.out.println("user mvc controller is running ...");
        return "forward:page.jsp";  // 支持访问WEB-INF下的页面
    }

    // 重定向
    @RequestMapping("/showPage2")
    public String showPage2() {
        System.out.println("user mvc controller is running ...");
        return "redirect:page.jsp";  // 不支持访问WEB-INF下的页面
    }

请求转发与重定向的区别

  • 当使用请求转发时,Servlet 容器将使用一个内部的方法来调用目标页面,新的页面继续处理同一个请求,而浏览器将不会知道这个过程(即服务器行为)。与之相反,重定向的含义是第一个页面通知浏览器发送一个新的页面请求。因为当使用重定向时,浏览器中所显示的 URL 会变成新页面的 URL(浏览器行为)。而当使用转发时,该 URL 会保持不变。

  • 重定向的速度比转发慢,因为浏览器还得发出一个新的请求。

  • 同时,由于重定向产生了一个新的请求,所以经过一次重定向后,第一次请求内的对象将无法使用。

总结

  • 重定向:两次请求,浏览器行为,地址栏改变,请求域中的数据会丢失。
  • 请求转发:一次请求,服务器行为,地址栏不变,请求域中的数据不丢失。

怎么选择是重定向还是转发呢

  • 通常情况下转发更快,而且能保持请求内的对象,所以它是第一选择。但是由于在转发之后,浏览器中 URL 仍然指向开始页面,此时如果重载当前页面,开始页面将会被重新调用。如果不想看到这样的情况,则选择重定向。

  • 不要仅仅为了把变量传到下一个页面而使用 session 作用域,那会无故增大变量的作用域,转发也许可以帮助解决这个问题。

    • 重定向:以前的请求中存放的变量全部失效,并进入一个新的请求作用域。
    • 转发:以前的请求中存放的变量不会失效,就像把两个页面拼到了一起。

通常,展示页面的保存位置比较固定且结构相似,因此可以设定通用的访问路径,来简化页面配置。

示例

<!-- 设定页面加载的前缀后缀,仅适用于默认形式,不适用于手工标注转发或重定向的方式 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/pages/"/>
    <property name="suffix" value=".jsp"/>
</bean>


public String showPage3() {
    return "page";
}

而如果未设定返回值,使用 void 类型,则默认使用访问路径来拼接前后缀:

// 最简页面配置方式:使用访问路径作为返回的页面名称,省略返回值
@RequestMapping("/showPage5")
public void showPage5() {
    System.out.println("user mvc controller is running ...");
}


public class Book {
    private String name;
    private Double price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}


import com.bean.Book;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;

@Controller
public class BookController {

    // 使用原生response对象响应数据
    @RequestMapping("/showData1")
    public void showData1(HttpServletResponse response) throws IOException {
        response.getWriter().write("message");
    }

    // 使用原生request对象传递参数
    @RequestMapping("/showPageAndData1")
    public String showPageAndData1(HttpServletRequest request) {
        request.setAttribute("name", "xiaoming");
        return "page";
    }

    // 使用Model形参传递参数
    @RequestMapping("/showPageAndData2")
    public String showPageAndData2(Model model) {
        Book book  = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        // 添加数据的方式
        model.addAttribute("name", "xiaoming");
        model.addAttribute("book", book);
        return "page";
    }

    // 使用ModelAndView形参传递参数,该对象还封装了页面信息
    @RequestMapping("/showPageAndData3")
    public ModelAndView showPageAndData3(ModelAndView modelAndView) {
        // ModelAndView mav = new ModelAndView();  // 替换形参中的参数
        Book book = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        // 添加数据的方式
        modelAndView.addObject("book", book);
        modelAndView.addObject("name", "xiaoming");
        // 设置返回页面(若该方法存在多个,则以最后一个为准)
        modelAndView.setViewName("page");
        // 返回值设定成ModelAndView对象
        return modelAndView;
    }

    // ModelAndView对象支持转发的手工设定,该设定不会启用前缀后缀的页面拼接格式
    @RequestMapping("/showPageAndData4")
    public ModelAndView showPageAndData4(ModelAndView modelAndView) {
        modelAndView.setViewName("forward:/WEB-INF/pages/page.jsp");
        return modelAndView;
    }

    // ModelAndView对象支持重定向的手工设定,该设定不会启用前缀后缀的页面拼接格式
    @RequestMapping("/showPageAndData5")
    public ModelAndView showPageAndData6(ModelAndView modelAndView) {
        modelAndView.setViewName("redirect:index.jsp");
        return modelAndView;
    }

}
  • 导入 maven 坐标:

        <!--json相关坐标3个-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.9.0</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.9.0</version>
        </dependency>
  • Controller:

    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;

    // 使用@ResponseBody将返回的结果作为响应内容,而非响应的页面名称
    @RequestMapping("/showData2")
    @ResponseBody
    public String showData2(){
        return "{\"name\":\"xiaoming\"}";
    }
    
    // 使用jackson进行json数据格式转化(会有中文乱码问题)
    @RequestMapping("/showData3")
    @ResponseBody
    public String showData3() throws JsonProcessingException {
        Book book  = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        ObjectMapper om = new ObjectMapper();
        return om.writeValueAsString(book);
    }
    
    /*
    <!--开启springmvc注解驱动,对@ResponseBody的注解进行格式增强,追加其类型转换的功能,具体实现由MappingJackson2HttpMessageConverter进行-->
    <mvc:annotation-driven/>
     */
    // 使用SpringMVC注解驱动,对标注@ResponseBody注解的控制器方法进行结果转换
    // 由于返回值为引用类型,自动调用jackson提供的类型转换器进行格式转换
    @RequestMapping("/showData4")
    @ResponseBody
    public Book showData4() {
        Book book  = new Book();
        book.setName("SpringMVC入门案例");
        book.setPrice(66.66d);
        return book;
    }
    
    // 转换集合类型数据
    @RequestMapping("/showData5")
    @ResponseBody
    public List showData5() {
        Book book1 = new Book();
        book1.setName("SpringMVC入门案例");
        book1.setPrice(66.66d);
    Book book2 = new Book();
    book2.setName("SpringMVC入门案例");
    book2.setPrice(66.66d);
    
    ArrayList&lt;Book&gt; al = new ArrayList&lt;&gt;();
    al.add(book1);
    al.add(book2);
    return al;  // 返回 [{"name":"SpringMVC入门案例","price":66.66},{"name":"SpringMVC入门案例","price":66.66}]
    }

Servlet 相关接口

SpringMVC 提供访问原始 Servlet 接口 API 的功能,通过形参声明即可。

    @RequestMapping("/servletApi")
    public String servletApi(HttpServletRequest request,
            HttpServletResponse response, HttpSession session){
        System.out.println(request);  // org.apache.catalina.connector.RequestFacade@6d3a1615
        System.out.println(response);  // org.apache.catalina.connector.ResponseFacade@55405578
        System.out.println(session);  // org.apache.catalina.session.StandardSessionFacade@714a7020
        request.setAttribute("name", "xiaoming");
        System.out.println(request.getAttribute("name"));  // xiaoming
        return "page.jsp";
    }

Header 数据获取:

  • 名称:@RequestHeader

  • 类型:形参注解

  • 位置:处理器类中的方法形参前方

  • 作用:绑定请求头数据与对应处理方法形参间的关系

    // header 数据获取
    @RequestMapping("/headApi")
    public String headApi(@RequestHeader("Accept-Language") String head){
        System.out.println(head);  // zh-CN,zh;q=0.9
        return "page.jsp";
    }

Cookie 数据获取:

  • 名称:@CookieValue

  • 类型:形参注解

  • 位置:处理器类中的方法形参前方

  • 作用:绑定请求 Cookie 数据与对应处理方法形参间的关系

    // cookie 数据获取
    @RequestMapping("/cookieApi")
    public String cookieApi(@CookieValue("JSESSIONID") String jsessionid){
        System.out.println(jsessionid);
        return "page.jsp";
    }

Session 数据获取:

  • 名称:@SessionAttribute

  • 类型:形参注解

  • 位置:处理器类中的方法形参前方

  • 作用:绑定请求 Session 数据与对应处理方法形参间的关系

    // 测试用方法,为下面的试验服务,用于在session中放入数据
    @RequestMapping("/setSessionData")
    public String setSessionData(HttpSession session){
        session.setAttribute("name", "xiaoming");
        return "page";
    }
    
    // session 数据获取
    @RequestMapping("/sessionApi")
    public String sessionApi(@SessionAttribute("name") String name){
        System.out.println(name);  // 获取session中的name值
        return "page.jsp";
    }

Session 数据设置:

  • 名称:@SessionAttributes

  • 类型:类注解

  • 位置:处理器类上方

  • 作用:声明放入 session 范围的变量名称,适用于 Model 类型数据传参

    @Controller
    // 设定当前类中名称为age和gender的变量放入session范围(不常用,了解即可)
    @SessionAttributes(names={"age","gender"})
    public class ServletController {

    // 配合 @SessionAttributes(names={"age","gender"}) 使用
    // 将数据放入session存储范围,通过Model对象实现数据set,通过@SessionAttributes注解实现范围设定
    @RequestMapping("/setSessionData2")
    public String setSessionDate2(Model model) {
        model.addAttribute("age",39);
        model.addAttribute("gender","男");
        return "page.jsp";
    }

    }