SpringMVC 入门、请求、响应
SpringMVC 概述
SSM 简介
SSM 三层架构
表现层:负责数据展示
业务层:负责业务处理
数据层:负责数据操作

MVC 简介
MVC(Model View Controller)是一种用于设计及创建 Web 应用程序表现层的模式。
Model(模型):数据模型,用于封装数据
View(视图):页面视图,用于展示数据
- jsp
 - html
 
Controller(控制器):处理用户交互的调度器,用于根据用户需求处理程序逻辑
- Servlet
 - SpringMVC
 

SpringMVC 简介
SpringMVC 是一种基于 Java 实现的、MVC 模型的、轻量级的 Web 框架。
SpringMVC 优点:
- 使用简单
 - 性能突出(相比现有的框架技术)
 - 灵活性强
 
入门案例
SpringMVC 工作流程分析:
- 服务器启动:
- 加载 web.xml 中 DispatcherServlet;
 - 读取 spring-mvc.xml 中的配置,加载所有 com 包中所有标记为 bean 的类;
 - 读取 bean 中方法上方标注 @RequestMapping 的内容;
 
 - 处理请求:
- DispatcherServlet 配置拦截所有请求“/”;
 - 使用请求路径与所有加载的 @RequestMapping 的内容进行比对;
 - 执行对应的方法;
 - 根据方法的返回值在 webapp 目录中查找对应的页面并展示。
 
 
实现示例:
- 导入 SpringMVC 相关的 Maven 依赖:
 
<!-- servlet3.1规范的坐标 -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>3.1.0</version>
    <scope>provided</scope>
</dependency>
<!--jsp坐标-->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>jsp-api</artifactId>
    <version>2.1</version>
    <scope>provided</scope>
</dependency>
<!--spring的坐标-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<!--spring web的坐标-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
<!--springmvc的坐标-->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.1.9.RELEASE</version>
</dependency>
- 定义表现层处理器 Controller(等同于 Servlet),并配置成 Spring 的 bean:
 
@Controller
public class UserController {
    public void save(){
        System.out.println("user mvc controller is running ...");
    }
}
- 定义 SpringMVC 配置文件(格式与 Spring 配置文件一致):
 
<?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">
    <!--扫描加载所有的控制类类-->
    <context:component-scan base-package="com"/>
</beans>
- web.xml 中配置 SpringMVC 核心控制器,用于将请求转发到对应的具体业务处理器 Controller 中(等同于 Servlet 配置):
 
<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>
</servlet>
<servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>
- 设定具体 Controller 的访问路径与返回页面(等同于 Servlet 在 web.xml 中的配置):
 
// 设定当前方法的访问映射地址
@RequestMapping("/save")
// 设置当前方法返回值类型为String,用于指定请求完成后跳转的页面
public String save(){
    System.out.println("user mvc controller is running ...");
    // 设定具体跳转的页面
    return "success.jsp";
}
Spring 技术架构

DispatcherServlet(前端控制器):是整体流程控制的中心,由其调用其它组件处理用户的请求,有效降低了组件间的耦合性。- HandlerMapping(处理器映射器):负责根据用户请求找到对应具体的 Handler 处理器。
 Handler(处理器):业务处理的核心类,通常由开发者编写,描述具体的业务。- HandlAdapter(处理器适配器):通过它对处理器进行执行。
 - View Resolver(视图解析器):将处理结果生成 View 视图。
 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 。
注意:

实现示例:
- 使用注解形式,将 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();;
    }
}
- 替换 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
@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";
}
@RequestParam
- 类型:形参注解
 - 位置:处理器类中的方法形参前方
 - 作用:绑定请求参数与处理方法形参间的关系
 
示例:
// 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 保存对象数据时,要求入参名称与对象层次结构名称保持一致,并使用数组格式描述集合中对象的位置。
- bean:
 
public class User {
    private String name;
    private Integer age;
    private List<Address> addresses;
}
public class Address {
    private String province;
    private String city;
    private String address;
}
- Controller:
 
// 访问URL:http://localhost:8080/requestParam7?addresses[0].province=bj&addresses[1].province=tj
@RequestMapping("/requestParam7")
public String requestParam7(User user){
    System.out.println("user.addresses="+user.getAddresses());
    return "page.jsp";
}
注意:The valid characters are defined in RFC 7230 and RFC 3986
问题解决
2)当复杂对象中出现用 Map 保存对象数据时,要求入参名称与对象层次结构名称保持一致,并使用映射格式描述集合中对象的位置。
- bean:
 
public class User {
    private String name;
    private Integer age;
    private Map<String, Address> 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<String> 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
 - 类型:形参注解、成员变量注解
 - 位置:形参前面或成员变量上方
 - 作用:为当前参数或变量指定类型转换规则
 - 注意:依赖注解驱动支持(<mvc:annotation-driven />)
 - 范例:
 
// 形参前
// 访问 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 接口,并制定转换前与转换后的类型:
- 配置:
 
  <!-- 1.将自定义Converter注册为Bean,受SpringMVC管理 -->
  <bean id="myDateConverter" class="com.itheima.converter.MyDateConverter"/>
  <!-- 2.设定自定义Converter服务bean -->
  <bean id="conversionService"
        class="org.springframework.context.support.ConversionServiceFactoryBean">
      <!-- 3.注入所有的自定义Converter,该设定使用的是同类型覆盖的思想 -->
      <property name="converters">
          <!-- 4.set保障同类型转换器仅保留一个,去重规则以Converter<S,T>的泛型为准 -->
          <set>
              <!-- 5.具体的类型转换器 -->
              <ref bean="myDateConverter"/>
          </set>
      </property>
  </bean>
- 实现类:
 
// 自定义类型转换器,实现Converter接口,接口中指定的泛型即为最终作用的条件
// 本例中的泛型填写的是<String,Date>,最终出现字符串转日期时,该类型转换器生效
public class MyDateConverter implements Converter<String, Date> {
    // 重写接口的抽象方法,参数由泛型决定
    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 作用域,那会无故增大变量的作用域,转发也许可以帮助解决这个问题。
- 重定向:以前的请求中存放的变量全部失效,并进入一个新的请求作用域。
 - 转发:以前的请求中存放的变量不会失效,就像把两个页面拼到了一起。
 
页面访问快捷设定(InternalResourceViewResolver)
通常,展示页面的保存位置比较固定且结构相似,因此可以设定通用的访问路径,来简化页面配置。

示例:
<!-- 设定页面加载的前缀后缀,仅适用于默认形式,不适用于手工标注转发或重定向的方式 -->
<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;
    }
}
返回 JSON 数据
- 导入 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<Book> al = new ArrayList<>();
        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";
    }
}
												
											SpringMVC 入门、请求、响应的更多相关文章
- <SpringMvc>入门四 响应结果
		
1.响应String类型 根据试图解析器,去找相对应的jsp Model将对象存在request中 2.响应void类型 可以看出,此时void方法执行了,系统默认会去找testVoid.jsp 意思 ...
 - ajax和springmvc的请求响应原理——深入理解jQuery中$.get、$.post、$.getJSON和$.ajax的用法
		
1,四大重要部分: 请求链接 post请求和get请求 请求参数形式 响应内容形式 2,从springmvc的controller角度,controller能接收到请求的前提 请求链接必须对应 pos ...
 - SpringMVC之请求响应(上)
		
1.OutPutController package com.tz.controller; import java.util.Map; import org.springframework.stere ...
 - SpringMVC入门和常用注解
		
SpringMVC的基本概念 关于 三层架构和 和 MVC 三层架构 我们的开发架构一般都是基于两种形式,一种是 C/S 架构,也就是客户端/服务器,另一种是 B/S 架构,也就 是浏览器服务器.在 ...
 - springMvc REST 请求和响应
		
前言: 突然怎么也想不起来 springMvc REST 请求的返回 类型了! (尴尬+究竟) 然后本着 方便的想法 百度了一下 发现了个问题,大家在写 springMvc RES ...
 - Spring系列  SpringMVC的请求与数据响应
		
Spring系列 SpringMVC的请求与数据响应 SpringMVC的数据响应 数据响应的方式 y以下案例均部署在Tomcat上,使用浏览器来访问一个简单的success.jsp页面来实现 Suc ...
 - JSP请求响应流程入门介绍
		
一个完整的jsp请求响应流程可以简单的使用下图表示: 过滤器:直观的了解,就是对请求做一个过滤作用,比如身份验证,验证不通过的不让他继续往下走 Servlet:请求处理中心,这个也是我们写业务逻辑的地 ...
 - 【Spring】SpringMVC入门示例讲解
		
目录结构: // contents structure [-] SpringMVC是什么 Spring MVC的设计原理 SpringMVC入门示例 1,复制Jar包 2,Web.xml文件 3,My ...
 - SpringMVC入门第二天
		
SpringMVC第二天 1. 回顾 1.Springmvc介绍? Springmvc是Spring公司 2.Springmvc入门程序 第一步:Web工程 第二步:导Jar包 第三步:web.x ...
 
随机推荐
- [hdu6989]Didn't I Say to Make My Abilities Average in the Next Life?!
			
显然问题即求$\frac{\sum_{x\le l\le r\le y}(\max_{l\le i\le r}a_{i}+\min_{l\le i\le r}a_{i})}{(y-x+2)(y-x+1 ...
 - [bzoj5510]唱跳rap和篮球
			
显然答案可以理解为有(不是仅有)0对情况-1对情况+2对情况-- 考虑这个怎么计算,先计算这t对情况的位置,有c(n-3t,t)种情况(可以理解为将这4个点缩为1个,然后再从中选t个位置),然后相当于 ...
 - rm命令弱爆了!
			
大家好,我是良许. 创建.删除和修改文件是用户在 Linux 系统中执行的非常常见操作.大家都知道,在 Linux 系统里使用 rm 命令删除单个文件时,几乎一瞬间就完成了.但是如果文件数量很大,那么 ...
 - [spring-core]作用域
			
本文试图从原理上讲解Spring IoC容器的作用域机制,建议对着源码阅读,事半功倍. 0 引入问题 当我们谈到Spring作用域的时候,自然而然会想到如下作用域(来自spring-core官方文档) ...
 - Educational Codeforces Round 94 题解
			
我竟然比到了全场的 rk 14,incredible! A 大水题,直接输出 \(n\) 遍 \(s_n\) 即可. B 分类讨论题,放在 B 题可能难度有点大了. 直接暴力枚举你拿了多少个宝剑,然后 ...
 - Nginx  编译 echo 模块
			
Nginx 编译 echo 模块 echo模块下载地址:https://github.com/openresty/echo-nginx-module 查看nginx已经编译的模块, nginx -V ...
 - Mac下source tree 下的安装
			
安装时出现了以下错误,解决方法 git -c diff.mnemonicprefix=false -c core.quotepath=false -c credential.helper=source ...
 - lua5.4 beta中的to-be-closed变量的用法
			
对应目前最新lua5.4 beta版本:2019-10-09发布 这个功能之前修改过两次语法,当前的语法不出意外将会是最终决定了,目前还没有最新的中文资料,所以我来这里发一下. 先介绍下这个功能: 被 ...
 - 【模板】Splay(伸展树)普通平衡树(数据加强版)/洛谷P6136
			
题目链接 https://www.luogu.com.cn/problem/P6136 题目大意 需要写一种数据结构,来维护一些非负整数( \(int\) 范围内)的升序序列,其中需要提供以下操作: ...
 - 基于python win32setpixel api 实现计算机图形学相关操作
			
最近读研期间上了计算机可视化的课,老师也对计算机图形学的实现布置了相关的作业.虽然我没有系统地学过图形可视化的课,但是我之前逆向过一些游戏引擎,除了保护驱动之外,因为要做透视,接触过一些计算机图形学的 ...